@unbrained/pm-cli 2026.8.22 → 2026.8.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +28 -0
- package/dist/cli/error-guidance.d.ts +13 -0
- package/dist/cli/error-guidance.js +62 -6
- package/dist/cli/main.js +13 -4
- package/dist/cli/register-mutation.js +6 -6
- package/dist/cli/register-operations.d.ts +73 -0
- package/dist/cli/register-operations.js +39 -14
- package/dist/cli/register-setup.js +3 -3
- package/dist/cli/schema-registration-helpers.d.ts +8 -1
- package/dist/cli/schema-registration-helpers.js +14 -5
- package/dist/cli-bundle/bundle-manifest.json +155 -155
- package/dist/cli-bundle/chunks/chunk-3ENVHX6C.js +36 -0
- package/dist/cli-bundle/chunks/{chunk-QI2CT3IX.js → chunk-DW2CGEMU.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WG4STC36.js → chunk-EG6CLDZT.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-MYYI3ZOA.js → chunk-F3AI2JFL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-U6GQ4VMV.js → chunk-HWZ6CELB.js} +4 -4
- package/dist/cli-bundle/chunks/chunk-HZBMLSZI.js +201 -0
- package/dist/cli-bundle/chunks/chunk-JB4KZWBF.js +3 -0
- package/dist/cli-bundle/chunks/chunk-KPH73XXJ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-BWX4SK46.js → chunk-KXPMB2YL.js} +58 -58
- package/dist/cli-bundle/chunks/{chunk-MZTZQTMS.js → chunk-QDVHNHAQ.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TFI5V5N2.js +13 -0
- package/dist/cli-bundle/chunks/{register-list-query-HZKBQNWW.js → register-list-query-UJB5FMV2.js} +2 -2
- package/dist/cli-bundle/chunks/register-mutation-NX5XE4VX.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-RXIJIYXC.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-QK4OTOXN.js → register-setup-GFUZEKRE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2POVTNLY.js → chunk-37Z4OEAP.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-3UPTYG44.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-E2EWYPY6.js → chunk-5S7E72FY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-GMYPD4FX.js → chunk-AUFH5H35.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-E7X25GC3.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3LKU6PTJ.js → chunk-FQCSTBWE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6S2MO3Q3.js → chunk-FZS4H32O.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-IFLWKY2R.js +156 -0
- package/dist/cli-bundle/focused-chunks/{chunk-PMGJUFNQ.js → chunk-JOWDB2MH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-LYVSW5VM.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-MRCNF3U6.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-A2BC5PQL.js → chunk-OFVUGTLJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2ARQGDDW.js → chunk-OGLQBL46.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-R6SR45XU.js → chunk-OY7QAV4Y.js} +48 -47
- package/dist/cli-bundle/focused-chunks/chunk-QGFNI65N.js +26 -0
- package/dist/cli-bundle/focused-chunks/{chunk-D6RBZEJJ.js → chunk-R27IDGHD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-UYRFYCDQ.js +5 -0
- package/dist/cli-bundle/focused-chunks/{chunk-PH2OXXVZ.js → chunk-ZHVA42R5.js} +9 -9
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +40 -40
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +33 -32
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +5 -5
- package/dist/core/config/nested-settings.js +8 -2
- package/dist/core/config/positional-value.d.ts +1 -1
- package/dist/core/config/positional-value.js +5 -2
- package/dist/core/history/history.js +3 -3
- package/dist/core/item/item-format.js +66 -12
- package/dist/core/reproducibility/context.d.ts +4 -0
- package/dist/core/reproducibility/context.js +14 -8
- package/dist/core/shared/author.d.ts +55 -1
- package/dist/core/shared/author.js +333 -16
- package/dist/core/shared/constants.js +3 -2
- package/dist/core/store/settings-validator.d.ts +1 -0
- package/dist/core/store/settings-validator.js +6 -3
- package/dist/core/store/settings.js +5 -2
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +30 -9
- package/dist/sdk/agent/identity-config.d.ts +63 -0
- package/dist/sdk/agent/identity-config.js +107 -0
- package/dist/sdk/agent/refusal-corpus-contracts.d.ts +76 -0
- package/dist/sdk/agent/refusal-corpus-contracts.js +194 -0
- package/dist/sdk/cli-contracts/agent-output-contracts.js +6 -4
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -0
- package/dist/sdk/cli-contracts/enum-contracts.js +9 -2
- package/dist/sdk/cli-contracts/flag-contracts.js +9 -2
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +4 -4
- package/dist/sdk/cli-contracts/registration-helpers.js +5 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +22 -2
- package/dist/sdk/cli-contracts/tool-schema.d.ts +1 -1
- package/dist/sdk/cli-contracts/tool-schema.js +14 -3
- package/dist/sdk/cli-contracts.d.ts +3 -3
- package/dist/sdk/cli-contracts.js +4 -4
- package/dist/sdk/config.d.ts +6 -1
- package/dist/sdk/config.js +119 -14
- package/dist/sdk/context-intent-contracts.js +4 -2
- package/dist/sdk/core-governance.d.ts +1 -1
- package/dist/sdk/core-governance.js +3 -3
- package/dist/sdk/extension/scaffold.js +11 -5
- package/dist/sdk/flag-invocation-contracts.js +4 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +50 -2
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +87 -38
- package/dist/sdk/governance/assurance-action.js +30 -10
- package/dist/sdk/governance/validate.d.ts +2 -2
- package/dist/sdk/governance/validate.js +39 -14
- package/dist/sdk/index.d.ts +7 -2
- package/dist/sdk/index.js +8 -3
- package/dist/sdk/lifecycle/create.js +6 -3
- package/dist/sdk/lifecycle/update.js +5 -3
- package/dist/sdk/merge/three-way.js +105 -26
- package/dist/sdk/read-output-budget.d.ts +21 -0
- package/dist/sdk/read-output-budget.js +39 -2
- package/dist/sdk/read-output-contracts.d.ts +5 -3
- package/dist/sdk/read-output-contracts.js +20 -12
- package/dist/sdk/reproducibility/process.d.ts +19 -0
- package/dist/sdk/reproducibility/process.js +88 -0
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +6 -5
- package/dist/sdk/test/batch.d.ts +6 -0
- package/dist/sdk/test/batch.js +15 -3
- package/dist/sdk/test/entry.d.ts +1 -1
- package/dist/sdk/test/entry.js +3 -2
- package/dist/sdk/test/execution.d.ts +28 -3
- package/dist/sdk/test/execution.js +193 -34
- package/dist/sdk/test/parsers.d.ts +6 -0
- package/dist/sdk/test/parsers.js +21 -2
- package/dist/sdk/test/trust.d.ts +33 -0
- package/dist/sdk/test/trust.js +207 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_PROVENANCE_ADR.md +41 -5
- package/docs/CONFIGURATION.md +4 -0
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +19 -2
- package/docs/MERGE_SAFETY.md +15 -1
- package/docs/READ_OUTPUT_CONTRACTS.md +11 -1
- package/docs/REPRODUCIBLE_WORKSPACES.md +42 -8
- package/docs/SDK.md +9 -0
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +6 -4
- package/docs/SDK_EVIDENCE_TRACEABILITY.md +1 -1
- package/docs/TESTING.md +75 -8
- package/docs/agent-task-token-baseline.json +2 -2
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +2 -2
- package/marketplace.json +2 -2
- package/package.json +2 -2
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +427 -17
- package/dist/cli-bundle/chunks/chunk-EMWDM5FI.js +0 -13
- package/dist/cli-bundle/chunks/chunk-HYG6LRL4.js +0 -200
- package/dist/cli-bundle/chunks/chunk-SMWXHMVB.js +0 -35
- package/dist/cli-bundle/chunks/chunk-VMMIL3SI.js +0 -2
- package/dist/cli-bundle/chunks/chunk-YBPJAOQQ.js +0 -3
- package/dist/cli-bundle/chunks/register-mutation-HTKEEGRD.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-6EMRWJJY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2AZT5WXZ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-5SHSBMX2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-C4S4A4JJ.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-L5LDSRO2.js +0 -155
- package/dist/cli-bundle/focused-chunks/chunk-MB37AYN6.js +0 -26
- package/dist/cli-bundle/focused-chunks/chunk-MCOR37QK.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-WZE4LIPW.js +0 -8
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { LinkedTest } from "../../types/index.js";
|
|
2
|
+
/** Classification of one linked-test command against the current clone. */
|
|
3
|
+
export interface LinkedTestTrustDecision {
|
|
4
|
+
/** Stable hash binding the decision to command, context, and provenance. */
|
|
5
|
+
fingerprint: string;
|
|
6
|
+
/** Whether execution may proceed without an untrusted-command override. */
|
|
7
|
+
trusted: boolean;
|
|
8
|
+
/** Machine-readable reason for the decision. */
|
|
9
|
+
reason: "legacy" | "local_mutation" | "local_source_ref" | "acknowledged" | "invalid_provenance" | "foreign_source_ref";
|
|
10
|
+
/** Source ref recorded when the command entered tracker data. */
|
|
11
|
+
source_ref?: string;
|
|
12
|
+
/** Current source ref used for the local decision. */
|
|
13
|
+
current_source_ref?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Resolve the current Git branch without invoking a shell. */
|
|
16
|
+
export declare function resolveLinkedTestSourceRef(cwd?: string): Promise<string | undefined>;
|
|
17
|
+
/** Resolve the source checkout shared by linked-test provenance and execution. */
|
|
18
|
+
export declare function resolveLinkedTestSourceWorkspaceRoot(cwd?: string): string;
|
|
19
|
+
/** Attach immutable author/time/ref provenance to newly stored commands. */
|
|
20
|
+
export declare function attachLinkedTestProvenance(tests: LinkedTest[] | undefined, author: string, createdAt: string, sourceRef: string | undefined): LinkedTest[] | undefined;
|
|
21
|
+
/** Attach provenance while avoiding Git inspection for an empty mutation. */
|
|
22
|
+
export declare function attachLinkedTestMutationProvenance(tests: LinkedTest[] | undefined, author: string, createdAt: string): Promise<LinkedTest[] | undefined>;
|
|
23
|
+
/** Produce the clone-local trust identity for one linked-test entry. */
|
|
24
|
+
export declare function linkedTestTrustFingerprint(test: LinkedTest): string;
|
|
25
|
+
/** Resolve whether one stored command is trusted by this clone. */
|
|
26
|
+
export declare function resolveLinkedTestTrust(pmRoot: string, test: LinkedTest, currentSourceRef?: string): Promise<LinkedTestTrustDecision>;
|
|
27
|
+
/** Resolve a collection with one ledger read for validation and batch runs. */
|
|
28
|
+
export declare function resolveLinkedTestTrustBatch(pmRoot: string, tests: LinkedTest[], currentSourceRef?: string): Promise<LinkedTestTrustDecision[]>;
|
|
29
|
+
/** Persist explicit clone-local acknowledgement for selected linked tests. */
|
|
30
|
+
export declare function acknowledgeLinkedTests(pmRoot: string, tests: LinkedTest[], acknowledgedAt: string): Promise<{
|
|
31
|
+
acknowledged: number;
|
|
32
|
+
fingerprints: string[];
|
|
33
|
+
}>;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sdk/test/trust
|
|
3
|
+
*
|
|
4
|
+
* Provides provenance and clone-local trust decisions for stored linked-test
|
|
5
|
+
* commands. Tracker items remain portable while execution acknowledgements stay
|
|
6
|
+
* outside the merge-unioned project record.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="30a61f26-5db8-50ba-af37-1990a4742ce8")}catch(e){}}();
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { readFile } from "node:fs/promises";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { promisify } from "node:util";
|
|
14
|
+
import { ensureDir, writeFileAtomic, } from "../../core/fs/fs-utils.js";
|
|
15
|
+
import { sha256Hex, stableStringify } from "../../core/shared/serialization.js";
|
|
16
|
+
import { isTimestampLiteral } from "../../core/shared/time.js";
|
|
17
|
+
import { getRuntimePath } from "../../core/store/paths.js";
|
|
18
|
+
const execFileAsync = promisify(execFile);
|
|
19
|
+
const LINKED_TEST_TRUST_LEDGER_VERSION = 1;
|
|
20
|
+
const LINKED_TEST_TRUST_LEDGER_FILE = "linked-test-trust.json";
|
|
21
|
+
function trustLedgerPath(pmRoot) {
|
|
22
|
+
return path.join(getRuntimePath(pmRoot), LINKED_TEST_TRUST_LEDGER_FILE);
|
|
23
|
+
}
|
|
24
|
+
function emptyTrustLedger() {
|
|
25
|
+
return { version: LINKED_TEST_TRUST_LEDGER_VERSION, acknowledged: {} };
|
|
26
|
+
}
|
|
27
|
+
async function readTrustLedger(pmRoot) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(await readFile(trustLedgerPath(pmRoot), "utf8"));
|
|
30
|
+
if (parsed.version !== LINKED_TEST_TRUST_LEDGER_VERSION ||
|
|
31
|
+
typeof parsed.acknowledged !== "object" ||
|
|
32
|
+
parsed.acknowledged === null ||
|
|
33
|
+
Array.isArray(parsed.acknowledged)) {
|
|
34
|
+
return emptyTrustLedger();
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
version: LINKED_TEST_TRUST_LEDGER_VERSION,
|
|
38
|
+
acknowledged: parsed.acknowledged,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// A missing, corrupt, or unreadable ledger grants no acknowledgements.
|
|
43
|
+
// The local/source-ref provenance checks remain independent of this file.
|
|
44
|
+
return emptyTrustLedger();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Resolve the current Git branch without invoking a shell. */
|
|
48
|
+
export async function resolveLinkedTestSourceRef(cwd = process.cwd()) {
|
|
49
|
+
const hostedRef = process.env.GITHUB_HEAD_REF?.trim() || process.env.GITHUB_REF_NAME?.trim();
|
|
50
|
+
if (hostedRef && hostedRef !== "merge") {
|
|
51
|
+
return hostedRef;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const { stdout } = await execFileAsync("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], { cwd, encoding: "utf8", windowsHide: true, timeout: 10_000 });
|
|
55
|
+
const ref = stdout.trim();
|
|
56
|
+
/* c8 ignore start -- successful git symbolic-ref output is non-empty by contract */
|
|
57
|
+
if (ref.length === 0)
|
|
58
|
+
return undefined;
|
|
59
|
+
/* c8 ignore stop */
|
|
60
|
+
return ref;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Resolve the source checkout shared by linked-test provenance and execution. */
|
|
67
|
+
export function resolveLinkedTestSourceWorkspaceRoot(cwd = process.cwd()) {
|
|
68
|
+
return process.env.PM_SOURCE_WORKSPACE_ROOT?.trim() || cwd;
|
|
69
|
+
}
|
|
70
|
+
function hasValidLinkedTestProvenance(provenance) {
|
|
71
|
+
if (provenance === null || typeof provenance !== "object")
|
|
72
|
+
return false;
|
|
73
|
+
return (typeof provenance.author === "string" &&
|
|
74
|
+
provenance.author.trim().length > 0 &&
|
|
75
|
+
typeof provenance.created_at === "string" &&
|
|
76
|
+
isTimestampLiteral(provenance.created_at) &&
|
|
77
|
+
(provenance.source_kind === "local_mutation" ||
|
|
78
|
+
provenance.source_kind === "merge_union"));
|
|
79
|
+
}
|
|
80
|
+
/** Build the optional ref portion shared by clone-local trust decisions. */
|
|
81
|
+
function linkedTestTrustRefs(sourceRef, currentSourceRef) {
|
|
82
|
+
return {
|
|
83
|
+
...(sourceRef ? { source_ref: sourceRef } : {}),
|
|
84
|
+
...(currentSourceRef ? { current_source_ref: currentSourceRef } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Attach immutable author/time/ref provenance to newly stored commands. */
|
|
88
|
+
export function attachLinkedTestProvenance(tests, author, createdAt, sourceRef) {
|
|
89
|
+
return tests?.map((test) => test.command && !test.provenance
|
|
90
|
+
? {
|
|
91
|
+
...test,
|
|
92
|
+
provenance: {
|
|
93
|
+
author,
|
|
94
|
+
created_at: createdAt,
|
|
95
|
+
source_kind: "local_mutation",
|
|
96
|
+
...(sourceRef ? { source_ref: sourceRef } : {}),
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
: test);
|
|
100
|
+
}
|
|
101
|
+
/** Attach provenance while avoiding Git inspection for an empty mutation. */
|
|
102
|
+
export async function attachLinkedTestMutationProvenance(tests, author, createdAt) {
|
|
103
|
+
if (!tests || tests.length === 0)
|
|
104
|
+
return tests;
|
|
105
|
+
const sourceWorkspaceRoot = resolveLinkedTestSourceWorkspaceRoot();
|
|
106
|
+
return attachLinkedTestProvenance(tests, author, createdAt, await resolveLinkedTestSourceRef(sourceWorkspaceRoot));
|
|
107
|
+
}
|
|
108
|
+
/** Produce the clone-local trust identity for one linked-test entry. */
|
|
109
|
+
export function linkedTestTrustFingerprint(test) {
|
|
110
|
+
return sha256Hex(stableStringify({
|
|
111
|
+
command: test.command ?? null,
|
|
112
|
+
path: test.path ?? null,
|
|
113
|
+
scope: test.scope,
|
|
114
|
+
pm_context_mode: test.pm_context_mode ?? null,
|
|
115
|
+
workspace_context_mode: test.workspace_context_mode ?? null,
|
|
116
|
+
env_set: test.env_set ?? null,
|
|
117
|
+
env_clear: test.env_clear ?? null,
|
|
118
|
+
shared_host_safe: test.shared_host_safe ?? null,
|
|
119
|
+
provenance: test.provenance ?? null,
|
|
120
|
+
provenance_invalid: test.provenance_invalid ?? null,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
/** Resolve whether one stored command is trusted by this clone. */
|
|
124
|
+
export async function resolveLinkedTestTrust(pmRoot, test, currentSourceRef) {
|
|
125
|
+
const ledger = await readTrustLedger(pmRoot);
|
|
126
|
+
return resolveLinkedTestTrustFromLedger(test, currentSourceRef, ledger);
|
|
127
|
+
}
|
|
128
|
+
function resolveLinkedTestTrustFromLedger(test, currentSourceRef, ledger) {
|
|
129
|
+
const fingerprint = linkedTestTrustFingerprint(test);
|
|
130
|
+
const sourceRef = test.provenance?.source_ref;
|
|
131
|
+
if (test.provenance === undefined &&
|
|
132
|
+
test.provenance_invalid !== true) {
|
|
133
|
+
return { fingerprint, trusted: true, reason: "legacy" };
|
|
134
|
+
}
|
|
135
|
+
const acknowledged = Object.hasOwn(ledger.acknowledged, fingerprint);
|
|
136
|
+
if (test.provenance_invalid === true ||
|
|
137
|
+
!hasValidLinkedTestProvenance(test.provenance)) {
|
|
138
|
+
if (acknowledged) {
|
|
139
|
+
return {
|
|
140
|
+
fingerprint,
|
|
141
|
+
trusted: true,
|
|
142
|
+
reason: "acknowledged",
|
|
143
|
+
...linkedTestTrustRefs(undefined, currentSourceRef),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
fingerprint,
|
|
148
|
+
trusted: false,
|
|
149
|
+
reason: "invalid_provenance",
|
|
150
|
+
...linkedTestTrustRefs(undefined, currentSourceRef),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (test.provenance.source_kind === "local_mutation" &&
|
|
154
|
+
sourceRef === undefined) {
|
|
155
|
+
return {
|
|
156
|
+
fingerprint,
|
|
157
|
+
trusted: true,
|
|
158
|
+
reason: "local_mutation",
|
|
159
|
+
...linkedTestTrustRefs(undefined, currentSourceRef),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (test.provenance.source_kind === "local_mutation" &&
|
|
163
|
+
sourceRef !== undefined &&
|
|
164
|
+
sourceRef === currentSourceRef) {
|
|
165
|
+
return {
|
|
166
|
+
fingerprint,
|
|
167
|
+
trusted: true,
|
|
168
|
+
reason: "local_source_ref",
|
|
169
|
+
source_ref: sourceRef,
|
|
170
|
+
current_source_ref: currentSourceRef,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (acknowledged) {
|
|
174
|
+
return {
|
|
175
|
+
fingerprint,
|
|
176
|
+
trusted: true,
|
|
177
|
+
reason: "acknowledged",
|
|
178
|
+
...linkedTestTrustRefs(sourceRef, currentSourceRef),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
fingerprint,
|
|
183
|
+
trusted: false,
|
|
184
|
+
reason: "foreign_source_ref",
|
|
185
|
+
...linkedTestTrustRefs(sourceRef, currentSourceRef),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/** Resolve a collection with one ledger read for validation and batch runs. */
|
|
189
|
+
export async function resolveLinkedTestTrustBatch(pmRoot, tests, currentSourceRef) {
|
|
190
|
+
const ledger = await readTrustLedger(pmRoot);
|
|
191
|
+
return tests.map((test) => resolveLinkedTestTrustFromLedger(test, currentSourceRef, ledger));
|
|
192
|
+
}
|
|
193
|
+
/** Persist explicit clone-local acknowledgement for selected linked tests. */
|
|
194
|
+
export async function acknowledgeLinkedTests(pmRoot, tests, acknowledgedAt) {
|
|
195
|
+
const ledger = await readTrustLedger(pmRoot);
|
|
196
|
+
const fingerprints = tests
|
|
197
|
+
.filter((test) => typeof test.command === "string" && test.command.length > 0)
|
|
198
|
+
.map(linkedTestTrustFingerprint);
|
|
199
|
+
for (const fingerprint of fingerprints) {
|
|
200
|
+
ledger.acknowledged[fingerprint] = { acknowledged_at: acknowledgedAt };
|
|
201
|
+
}
|
|
202
|
+
await ensureDir(path.dirname(trustLedgerPath(pmRoot)));
|
|
203
|
+
await writeFileAtomic(trustLedgerPath(pmRoot), `${JSON.stringify(ledger, null, 2)}\n`);
|
|
204
|
+
return { acknowledged: fingerprints.length, fingerprints };
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=trust.js.map
|
|
207
|
+
//# debugId=30a61f26-5db8-50ba-af37-1990a4742ce8
|
package/dist/types.d.ts
CHANGED
|
@@ -166,6 +166,17 @@ export interface LinkedFile {
|
|
|
166
166
|
/** Value that configures or reports note for this contract. */
|
|
167
167
|
note?: string;
|
|
168
168
|
}
|
|
169
|
+
/** Valid immutable provenance captured when a linked command enters tracker data. */
|
|
170
|
+
export interface LinkedTestProvenance {
|
|
171
|
+
/** Author identity recorded by the originating mutation. */
|
|
172
|
+
author: string;
|
|
173
|
+
/** ISO 8601 time at which the command entered tracker data. */
|
|
174
|
+
created_at: string;
|
|
175
|
+
/** Mutation path that introduced the command. */
|
|
176
|
+
source_kind: "local_mutation" | "merge_union";
|
|
177
|
+
/** Best-effort Git branch or hosted head ref of the originating mutation. */
|
|
178
|
+
source_ref?: string;
|
|
179
|
+
}
|
|
169
180
|
/** Documents the linked test payload exchanged by command, SDK, and package integrations. */
|
|
170
181
|
export interface LinkedTest {
|
|
171
182
|
/** Value that configures or reports command for this contract. */
|
|
@@ -178,6 +189,12 @@ export interface LinkedTest {
|
|
|
178
189
|
timeout_seconds?: number;
|
|
179
190
|
/** Strategy used to control pm context behavior. */
|
|
180
191
|
pm_context_mode?: "schema" | "tracker" | "auto";
|
|
192
|
+
/** Strategy used for source-workspace visibility and command working directory. */
|
|
193
|
+
workspace_context_mode?: "source" | "isolated" | "snapshot";
|
|
194
|
+
/** Immutable provenance captured when the linked command enters tracker data. */
|
|
195
|
+
provenance?: LinkedTestProvenance;
|
|
196
|
+
/** Explicit fail-closed marker retained when stored provenance is malformed. */
|
|
197
|
+
provenance_invalid?: true;
|
|
181
198
|
/** Value that configures or reports env set for this contract. */
|
|
182
199
|
env_set?: Record<string, string>;
|
|
183
200
|
/** Value that configures or reports env clear for this contract. */
|
|
@@ -566,6 +583,10 @@ export interface ItemTestRunExecution {
|
|
|
566
583
|
requested_pm_context_mode?: "schema" | "tracker" | "auto";
|
|
567
584
|
/** Effective context mode used by the linked command. */
|
|
568
585
|
pm_context_mode?: "schema" | "tracker" | "auto";
|
|
586
|
+
/** Effective source-workspace mode used by the linked command. */
|
|
587
|
+
workspace_context_mode?: "source" | "isolated" | "snapshot";
|
|
588
|
+
/** Trust classification applied before execution. */
|
|
589
|
+
trust_reason?: "legacy" | "local_mutation" | "local_source_ref" | "acknowledged" | "invalid_provenance" | "foreign_source_ref";
|
|
569
590
|
}
|
|
570
591
|
/** Documents the item test run summary payload exchanged by command, SDK, and package integrations. */
|
|
571
592
|
export interface ItemTestRunSummary {
|
|
@@ -1121,6 +1142,8 @@ export interface PmSettings {
|
|
|
1121
1142
|
/** Value that configures or reports testing for this contract. */
|
|
1122
1143
|
testing: {
|
|
1123
1144
|
record_results_to_items: boolean;
|
|
1145
|
+
/** Permit explicit one-shot execution of commands not yet trusted by this clone. */
|
|
1146
|
+
allow_untrusted_linked_tests: boolean;
|
|
1124
1147
|
};
|
|
1125
1148
|
/** Value that configures or reports telemetry for this contract. */
|
|
1126
1149
|
telemetry: {
|
package/dist/types.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Supported values accepted by the builtin item type contract. */
|
|
7
7
|
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="64223a83-1287-57ac-915d-dbd5e375a6eb")}catch(e){}}();
|
|
9
9
|
export const BUILTIN_ITEM_TYPE_VALUES = [
|
|
10
10
|
"Epic",
|
|
11
11
|
"Feature",
|
|
@@ -243,4 +243,4 @@ export const CONTEXT_SECTION_VALUES = [
|
|
|
243
243
|
"tests",
|
|
244
244
|
];
|
|
245
245
|
//# sourceMappingURL=types.js.map
|
|
246
|
-
//# debugId=
|
|
246
|
+
//# debugId=64223a83-1287-57ac-915d-dbd5e375a6eb
|
|
@@ -10,7 +10,10 @@ Implementation lineage:
|
|
|
10
10
|
resolution and patch-free historical reads implemented by
|
|
11
11
|
[pm-ffz0a9](../.agents/pm/issues/pm-ffz0a9.toon),
|
|
12
12
|
[pm-v8gfi7](../.agents/pm/issues/pm-v8gfi7.toon), and
|
|
13
|
-
[pm-3yxwv5](../.agents/pm/issues/pm-3yxwv5.toon).
|
|
13
|
+
[pm-3yxwv5](../.agents/pm/issues/pm-3yxwv5.toon). Cross-harness adapters and
|
|
14
|
+
operator-managed probe/vocabulary controls are tracked by
|
|
15
|
+
[pm-c0lrdm](../.agents/pm/features/pm-c0lrdm.toon) and
|
|
16
|
+
[pm-yds9dt](../.agents/pm/chores/pm-yds9dt.toon).
|
|
14
17
|
|
|
15
18
|
Status: accepted amendment to
|
|
16
19
|
[pm-qwuber](../.agents/pm/decisions/pm-qwuber.toon). The original stable-author
|
|
@@ -51,10 +54,13 @@ Provenance values are descriptive context, never authentication or
|
|
|
51
54
|
authorization principals. Values are trimmed, length-bounded, and obtained only
|
|
52
55
|
from literal descriptor keys, trusted caller data, or a named bounded resolver.
|
|
53
56
|
Detection does not spawn processes, traverse process trees, evaluate user
|
|
54
|
-
regexes, or access the network. The built-in Claude
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
regexes, or access the network. The built-in Claude and Codex resolvers read
|
|
58
|
+
only bounded windows of the current session's harness-owned JSONL file. Claude
|
|
59
|
+
uses the recent tail to recover its recorded model/version. Codex uses the
|
|
60
|
+
recent tail plus a bounded initial-head fallback for oversized sessions to
|
|
61
|
+
recover allow-listed `turn_context.model` and `turn_context.effort` values.
|
|
62
|
+
Both cap traversal, file bytes, lines, and line length, ignore all other fields,
|
|
63
|
+
never follow symlinks, and fail closed. `agent_identity.probes_enabled` or
|
|
58
64
|
`PM_AGENT_PROBES=off` disables every local resolver without disabling ordinary
|
|
59
65
|
environment, argv, client, or host detection.
|
|
60
66
|
|
|
@@ -113,6 +119,11 @@ fabricate precision that was never captured.
|
|
|
113
119
|
The aggregate and core SDK entrypoints export:
|
|
114
120
|
|
|
115
121
|
- `AGENT_PROVENANCE_DIMENSIONS`;
|
|
122
|
+
- `BUILTIN_AGENT_PROVENANCE_ADAPTERS`,
|
|
123
|
+
`listAgentProvenanceAdapters()`, and
|
|
124
|
+
`registerAgentProvenanceAdapters()`;
|
|
125
|
+
- `normalizeAgentProvenanceAdapterValue()` for stable model-family and effort
|
|
126
|
+
vocabulary projections that retain the bounded raw observation;
|
|
116
127
|
- `detectAgentIdentity()` and `detectHarnessIdentity()`;
|
|
117
128
|
- `analyzeAgentProvenanceDescriptorCoverage()` for the descriptor capability
|
|
118
129
|
matrix and negative controls;
|
|
@@ -138,6 +149,31 @@ Legacy author interpretation is workspace-owned data under
|
|
|
138
149
|
version and whether a harness was `recorded`, resolved by `vocabulary`, or
|
|
139
150
|
remains `unresolved`; immutable authors and hashes are never rewritten.
|
|
140
151
|
|
|
152
|
+
`pm config get agent-identity-vocabulary`, `config list`, and `config export`
|
|
153
|
+
publish only its `version` and `alias_count`. Typed mutations use the existing
|
|
154
|
+
config transport:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
pm config set agent-identity-probes-enabled false
|
|
158
|
+
pm config set agent-identity-vocabulary --policy preview-add \
|
|
159
|
+
--value "Legacy Codex=codex" --criterion "Legacy Codex" --criterion "Alice"
|
|
160
|
+
pm config set agent-identity-vocabulary --policy add \
|
|
161
|
+
--value "Legacy Codex=codex"
|
|
162
|
+
pm config set agent-identity-vocabulary --policy remove --value "Legacy Codex"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`preview-*` policies perform no write and report the exact residual unique
|
|
166
|
+
author count without returning author spellings. Real add/remove/clear changes
|
|
167
|
+
bump the vocabulary revision once; identical adds and absent removes are
|
|
168
|
+
idempotent. Aliases for already canonical `harness:<name>` authors fail closed.
|
|
169
|
+
|
|
170
|
+
Every built-in interactive harness has a contract-versioned adapter with an
|
|
171
|
+
implementation version, priority, covered dimensions, source classes,
|
|
172
|
+
normalization revisions, confidence, waivers, and immutable probe bounds.
|
|
173
|
+
Packages may register a new namespace or explicitly replace a built-in only at
|
|
174
|
+
a higher priority. Equal-priority ambiguity and descriptor mismatch fail
|
|
175
|
+
closed, and the disposer restores the prior adapter.
|
|
176
|
+
|
|
141
177
|
The SDK/CLI matrix classifies every input as shared, positional, transport,
|
|
142
178
|
presentation, local adapter, scope selector, compatibility alias, or SDK-native.
|
|
143
179
|
An unknown CLI flag fails closed as `unclassified`. Committed test baselines cap
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -29,6 +29,7 @@ pm config project export --json
|
|
|
29
29
|
pm config project get item-format --json
|
|
30
30
|
pm config project set item-format --format toon
|
|
31
31
|
pm config project set test-result-tracking --policy enabled
|
|
32
|
+
pm config project set untrusted-linked-test-execution --policy disabled
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
`config set <key> <value>` also accepts the value as a positional argument; pm routes
|
|
@@ -85,6 +86,7 @@ When `settings.json` cannot be loaded, `pm` falls back to built-in defaults and
|
|
|
85
86
|
| `history.compact_policy.max_entries` | when the policy is enabled, the entry count above which a stream is flagged by `pm health` and the default `pm history-compact --all-over` threshold (default `500`) |
|
|
86
87
|
| `history.compact_policy.trigger` | policy intent when enabled: `health_warn` (advisory only) or `auto` (scheduled sweeps expected) |
|
|
87
88
|
| `testing.record_results_to_items` | persist bounded linked-test summaries |
|
|
89
|
+
| `testing.allow_untrusted_linked_tests` | permit the explicit `pm test --allow-untrusted-linked-tests` one-run override (default `false`; does not trust or execute commands by itself) |
|
|
88
90
|
| `validation.sprint_release_format` | `warn` or `strict_error` |
|
|
89
91
|
| `validation.parent_reference` | `warn` or `strict_error` (`strict_error` is the built-in default; `pm create --allow-missing-parent` is the explicit escape hatch) |
|
|
90
92
|
| `item_types.definitions[]` | custom item types and type options |
|
|
@@ -115,6 +117,7 @@ pm config project set schema_unknown_field_policy reject # (schema.unknown_fie
|
|
|
115
117
|
pm config project set governance-duplicate-detection-mode strict # (governance.duplicate_detection_mode) off | advisory | strict
|
|
116
118
|
pm config project set governance-duplicate-detection-threshold 0.8 # (governance.duplicate_detection_threshold) ratio 0..1
|
|
117
119
|
pm config project set governance-duplicate-detection-limit 3 # (governance.duplicate_detection_limit) integer 0..20
|
|
120
|
+
pm config project set untrusted-linked-test-execution disabled # (testing.allow_untrusted_linked_tests) enabled | disabled
|
|
118
121
|
```
|
|
119
122
|
|
|
120
123
|
Duplicate governance uses the shared SDK scorer and bounded metadata query
|
|
@@ -227,6 +230,7 @@ pm config project set sprint-release-format-policy --policy warn
|
|
|
227
230
|
pm config project set parent-reference-policy --policy strict_error
|
|
228
231
|
pm config project set history-missing-stream-policy --policy auto_create
|
|
229
232
|
pm config project set test-result-tracking --policy enabled
|
|
233
|
+
pm config project set untrusted-linked-test-execution --policy disabled
|
|
230
234
|
```
|
|
231
235
|
|
|
232
236
|
Use standalone checks when validating a repository:
|
|
@@ -58,6 +58,15 @@ estimates, applied stages, and omitted top-level fields. Minimal fallbacks bound
|
|
|
58
58
|
the named omission list and disclose any additional count through
|
|
59
59
|
`omitted_fields_overflow_count`.
|
|
60
60
|
|
|
61
|
+
Structured CLI refusals also include a compact `refusal` identity with the
|
|
62
|
+
failing command/flag/operand surface, rejected scalar when observable, complete
|
|
63
|
+
legal domain when one exists, and the process exit code. Recovery-bearing
|
|
64
|
+
errors use the `recovery_bundle` diagnostic class. Collection degradation may
|
|
65
|
+
compact explanatory domains inside `recovery`, but `refusal.legal_domain`
|
|
66
|
+
remains complete and `recovery.suggested_retry_args` is atomic: the projector
|
|
67
|
+
either retains the executable argv or removes the recovery rather than slicing
|
|
68
|
+
it into a dead command.
|
|
69
|
+
|
|
61
70
|
The deterministic ladder is:
|
|
62
71
|
|
|
63
72
|
1. full diagnostic;
|
|
@@ -73,8 +82,12 @@ envelope.
|
|
|
73
82
|
|
|
74
83
|
## Executable Assurance
|
|
75
84
|
|
|
76
|
-
`pnpm quality:recovery-closure` builds the current CLI and replays
|
|
77
|
-
contracts in isolated trackers
|
|
85
|
+
`pnpm quality:recovery-closure` builds the current CLI and replays 117 refusal
|
|
86
|
+
contracts in isolated trackers: 18 closed-domain rows, 88 required-argument
|
|
87
|
+
omissions derived from core executable positional signatures, seven
|
|
88
|
+
closed-action families, and four tracker-preflight states. Package-owned
|
|
89
|
+
commands enter executable coverage when their package runtime is active rather
|
|
90
|
+
than being misreported as core. Ten representative, high-frequency failure
|
|
78
91
|
paths are also ratcheted by
|
|
79
92
|
`scripts/release/diagnostic-output-baseline.json`. The gate requires every row
|
|
80
93
|
to remain within the SDK-declared JSON ceiling and retain a mechanically
|
|
@@ -85,6 +98,10 @@ The baseline is a coverage ratchet, not permission to weaken a ceiling. Its
|
|
|
85
98
|
negative control requires a missing baseline probe to fail. The existing
|
|
86
99
|
refusal-closure negative controls independently prove that incomplete domains,
|
|
87
100
|
broken retries, and malformed recovery envelopes remain blocking findings.
|
|
101
|
+
The grammar corpus additionally hashes authoritative tracker state around each
|
|
102
|
+
refusal; schema, items, history, settings, and package state must not change.
|
|
103
|
+
Ephemeral runtime lock/cache directories are excluded from that semantic
|
|
104
|
+
snapshot.
|
|
88
105
|
|
|
89
106
|
Run the focused proof with:
|
|
90
107
|
|
package/docs/MERGE_SAFETY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Multi-Branch Tracker Merge Safety
|
|
2
2
|
|
|
3
|
-
Tracked by [pm-wc1r](../.agents/pm/features/pm-wc1r.toon), with the integrity and concurrency fixes [pm-9q2t](../.agents/pm/issues/pm-9q2t.toon), [pm-cxyv](../.agents/pm/issues/pm-cxyv.toon), [pm-gpo7](../.agents/pm/issues/pm-gpo7.toon), [pm-m3nl](../.agents/pm/issues/pm-m3nl.toon), [pm-wwfd](../.agents/pm/issues/pm-wwfd.toon), and [pm-xdn6](../.agents/pm/issues/pm-xdn6.toon). Fresh-init fence ownership is tracked by [pm-1w3ljt](../.agents/pm/issues/pm-1w3ljt.toon); runtime-cache index governance by [pm-hous](../.agents/pm/issues/pm-hous.toon); local allocation safety by [pm-khdq](../.agents/pm/issues/pm-khdq.toon); fence-coverage completeness and drift detection by [pm-i4fx](../.agents/pm/issues/pm-i4fx.toon); package-defined item coverage by [pm-5rexki](../.agents/pm/issues/pm-5rexki.toon); non-item JSON coverage by [pm-gjicmx](../.agents/pm/issues/pm-gjicmx.toon); portable driver identity by [pm-w91mvg](../.agents/pm/issues/pm-w91mvg.toon); pending receipt validation by [pm-ysqb6n](../.agents/pm/issues/pm-ysqb6n.toon); receipt classification by [pm-jtwsct](../.agents/pm/issues/pm-jtwsct.toon); direction-independent item conflict selection by [pm-dlx7v7](../.agents/pm/issues/pm-dlx7v7.toon); corrected reconciliation guidance by [pm-lwmstb](../.agents/pm/issues/pm-lwmstb.toon); cross-branch id collision safety by [pm-pibw](../.agents/pm/issues/pm-pibw.toon); auditable merge history by [pm-9j2r3b](../.agents/pm/tasks/pm-9j2r3b.toon); durable conflict decisions by [pm-rh98vo](../.agents/pm/issues/pm-rh98vo.toon); continuous conformance by [pm-76dnfg](../.agents/pm/tasks/pm-76dnfg.toon); workspace-wide CI enforcement by [pm-pdr8t1](../.agents/pm/tasks/pm-pdr8t1.toon); post-merge reconciliation by [pm-mfkv92](../.agents/pm/issues/pm-mfkv92.toon); this repository's own adoption by [pm-iwsj](../.agents/pm/chores/pm-iwsj.toon).
|
|
3
|
+
Tracked by [pm-wc1r](../.agents/pm/features/pm-wc1r.toon), with the integrity and concurrency fixes [pm-9q2t](../.agents/pm/issues/pm-9q2t.toon), [pm-cxyv](../.agents/pm/issues/pm-cxyv.toon), [pm-gpo7](../.agents/pm/issues/pm-gpo7.toon), [pm-m3nl](../.agents/pm/issues/pm-m3nl.toon), [pm-wwfd](../.agents/pm/issues/pm-wwfd.toon), and [pm-xdn6](../.agents/pm/issues/pm-xdn6.toon). Fresh-init fence ownership is tracked by [pm-1w3ljt](../.agents/pm/issues/pm-1w3ljt.toon); runtime-cache index governance by [pm-hous](../.agents/pm/issues/pm-hous.toon); local allocation safety by [pm-khdq](../.agents/pm/issues/pm-khdq.toon); fence-coverage completeness and drift detection by [pm-i4fx](../.agents/pm/issues/pm-i4fx.toon); package-defined item coverage by [pm-5rexki](../.agents/pm/issues/pm-5rexki.toon); non-item JSON coverage by [pm-gjicmx](../.agents/pm/issues/pm-gjicmx.toon); portable driver identity by [pm-w91mvg](../.agents/pm/issues/pm-w91mvg.toon); pending receipt validation by [pm-ysqb6n](../.agents/pm/issues/pm-ysqb6n.toon); receipt classification by [pm-jtwsct](../.agents/pm/issues/pm-jtwsct.toon); direction-independent item conflict selection by [pm-dlx7v7](../.agents/pm/issues/pm-dlx7v7.toon); corrected reconciliation guidance by [pm-lwmstb](../.agents/pm/issues/pm-lwmstb.toon); cross-branch id collision safety by [pm-pibw](../.agents/pm/issues/pm-pibw.toon); auditable merge history by [pm-9j2r3b](../.agents/pm/tasks/pm-9j2r3b.toon); durable conflict decisions by [pm-rh98vo](../.agents/pm/issues/pm-rh98vo.toon); continuous conformance by [pm-76dnfg](../.agents/pm/tasks/pm-76dnfg.toon); workspace-wide CI enforcement by [pm-pdr8t1](../.agents/pm/tasks/pm-pdr8t1.toon); post-merge reconciliation by [pm-mfkv92](../.agents/pm/issues/pm-mfkv92.toon); linked-command execution trust by [pm-ed28wi](../.agents/pm/issues/pm-ed28wi.toon); this repository's own adoption by [pm-iwsj](../.agents/pm/chores/pm-iwsj.toon).
|
|
4
4
|
|
|
5
5
|
pm stores project context as reviewable repository files. Concurrent agents can therefore use ordinary branches and worktrees, but tracker artifacts need semantic merge behavior: raw line merging cannot preserve TOON collection counts, JSON object structure, or append-only history hash chains.
|
|
6
6
|
|
|
@@ -61,6 +61,20 @@ pm merge install --dry-run --json
|
|
|
61
61
|
| tracker `**/*.jsonl` except the later `history/*.jsonl` override | `pm-relationship` | Covers default and package-owned custom relationship event paths, unions divergent suffixes by `eventId` (timestamp-ordered, ours-first on ties), and renumbers `sequence` consecutively so the strict-sequence store loader accepts the merged stream. |
|
|
62
62
|
| root `settings.json` and nested `**/*.json` | `pm-json` | Recursively merges objects per key. Arrays compose when both branches preserve the base and add distinct entries, so independent extension installs and evaluation additions merge without weakening edit/removal conflict detection. |
|
|
63
63
|
|
|
64
|
+
The `tests` collection has an additional execution-safety rule. Its semantic
|
|
65
|
+
identity excludes provenance so the same command/context does not duplicate
|
|
66
|
+
when branches record different authorship metadata. A test definition newly
|
|
67
|
+
contributed by the other merge side is persisted with
|
|
68
|
+
`provenance.source_kind=merge_union` while retaining its author, creation time,
|
|
69
|
+
and source ref. `pm test --run` and `pm test-all` refuse that command before
|
|
70
|
+
spawning a process until the receiving clone acknowledges its fingerprint or
|
|
71
|
+
uses the two-part project-policy plus per-run override documented in
|
|
72
|
+
[Testing](TESTING.md#linked-test-command-trust). `pm validate
|
|
73
|
+
--check-command-references` reports outstanding entries. This is the threat
|
|
74
|
+
boundary for append-like data that becomes executable after a merge; ordinary
|
|
75
|
+
notes, files, and other non-executable collections retain normal set-union
|
|
76
|
+
behavior.
|
|
77
|
+
|
|
64
78
|
When both sides change the same item scalar differently, the driver writes the same stable value regardless of which branch Git labels ours or theirs, but exits nonzero. Item results and receipts expose the caller's `requested_preference`; the per-decision `retained` and `discarded` values or hashes are authoritative because stable value order can retain either side. Readers normalize the legacy receipt key `preferred`, while new receipts no longer emit it. JSON leaf conflicts retain the explicit preferred-side policy. Git keeps either path conflicted so a human or coordinating agent must review the discarded value and explicitly `git add` the resolution. This correction is tracked by [pm-qckpnq](../.agents/pm/issues/pm-qckpnq.toon).
|
|
65
79
|
|
|
66
80
|
The driver result's `guidance` always points unresolved conflicts to `pm merge report`. When a clone-local receipt exists, guidance includes its privacy-safe receipt and item ids for exact correlation; discarded values remain confined to the local receipt and never appear in generic logs or tracker history. Tracked by [pm-fbrz7p](../.agents/pm/issues/pm-fbrz7p.toon).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Universal Read Output Contracts
|
|
2
2
|
|
|
3
|
-
Tracker references: [pm-hb7ug8](../.agents/pm/features/pm-hb7ug8.toon), [pm-cxr0jb](../.agents/pm/features/pm-cxr0jb.toon), [pm-hid9g1](../.agents/pm/features/pm-hid9g1.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-5t33or](../.agents/pm/features/pm-5t33or.toon), [pm-srns](../.agents/pm/issues/pm-srns.toon), [pm-sb0tns](../.agents/pm/issues/pm-sb0tns.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-eugaqy](../.agents/pm/issues/pm-eugaqy.toon), [pm-jt8aa2](../.agents/pm/issues/pm-jt8aa2.toon), [pm-kyjdne](../.agents/pm/issues/pm-kyjdne.toon), [pm-8nev0o](../.agents/pm/issues/pm-8nev0o.toon), [pm-e5gl05](../.agents/pm/issues/pm-e5gl05.toon), [pm-cha95z](../.agents/pm/tasks/pm-cha95z.toon),
|
|
3
|
+
Tracker references: [pm-hb7ug8](../.agents/pm/features/pm-hb7ug8.toon), [pm-cxr0jb](../.agents/pm/features/pm-cxr0jb.toon), [pm-hid9g1](../.agents/pm/features/pm-hid9g1.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-5t33or](../.agents/pm/features/pm-5t33or.toon), [pm-srns](../.agents/pm/issues/pm-srns.toon), [pm-sb0tns](../.agents/pm/issues/pm-sb0tns.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-eugaqy](../.agents/pm/issues/pm-eugaqy.toon), [pm-jt8aa2](../.agents/pm/issues/pm-jt8aa2.toon), [pm-kyjdne](../.agents/pm/issues/pm-kyjdne.toon), [pm-8nev0o](../.agents/pm/issues/pm-8nev0o.toon), [pm-e5gl05](../.agents/pm/issues/pm-e5gl05.toon), [pm-cha95z](../.agents/pm/tasks/pm-cha95z.toon), [pm-2qvq7a](../.agents/pm/issues/pm-2qvq7a.toon), and [pm-xam9bt](../.agents/pm/issues/pm-xam9bt.toon).
|
|
4
4
|
|
|
5
5
|
## Agent Quick Context
|
|
6
6
|
|
|
@@ -164,6 +164,16 @@ an unbounded multi-megabyte response;
|
|
|
164
164
|
`recovery_budget_multiplier: 1` declares that each next page retains the same
|
|
165
165
|
useful-result ceiling.
|
|
166
166
|
|
|
167
|
+
When compaction affects a nested collection that is not declared resumable,
|
|
168
|
+
the recovery budget is derived from the larger of the binding ceiling plus one
|
|
169
|
+
and the measured pre-compaction result. The SDK adds a 25% envelope margin and
|
|
170
|
+
rounds up to 100 tokens. The CLI, SDK, and MCP bindings therefore receive the
|
|
171
|
+
same finite value, which is strictly larger than the request that already
|
|
172
|
+
truncated. If safe-integer arithmetic cannot represent that value, recovery
|
|
173
|
+
uses `unbounded` explicitly. `resolveReadOutputRecoveryBudget()` exposes the
|
|
174
|
+
versioned pure calculation to package authors; there is no hard-coded smaller
|
|
175
|
+
retry and no recovery cycle.
|
|
176
|
+
|
|
167
177
|
Assurance declares `budget_retention_policy: verdict_priority`: failing block,
|
|
168
178
|
warn, and observe rows precede retired and passing rows while preserving order
|
|
169
179
|
within each class. `assertions_total` remains the pre-projection denominator,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Reproducible Workspaces and Snapshots
|
|
2
2
|
|
|
3
|
-
Tracked by [pm-rbcvt2](../.agents/pm/features/pm-rbcvt2.toon)
|
|
4
|
-
[pm-dkrmzv](../.agents/pm/features/pm-dkrmzv.toon)
|
|
3
|
+
Tracked by [pm-rbcvt2](../.agents/pm/features/pm-rbcvt2.toon),
|
|
4
|
+
[pm-dkrmzv](../.agents/pm/features/pm-dkrmzv.toon), and
|
|
5
|
+
[pm-gh1089](../.agents/pm/issues/pm-gh1089.toon).
|
|
5
6
|
|
|
6
7
|
These SDK primitives make a pm workspace reproducible without changing normal
|
|
7
8
|
interactive behavior. Recipes control time and identifier entropy only inside
|
|
@@ -22,9 +23,7 @@ const recipe: WorkspaceRecipe = {
|
|
|
22
23
|
seed: "example-fixture-v1",
|
|
23
24
|
clock: "2026-07-28T10:00:00.000Z",
|
|
24
25
|
tickMs: 1,
|
|
25
|
-
operations: [
|
|
26
|
-
{ action: "create", input: { title: "Deterministic task" } },
|
|
27
|
-
],
|
|
26
|
+
operations: [{ action: "create", input: { title: "Deterministic task" } }],
|
|
28
27
|
};
|
|
29
28
|
|
|
30
29
|
const results = await executeWorkspaceRecipe(
|
|
@@ -36,9 +35,9 @@ const results = await executeWorkspaceRecipe(
|
|
|
36
35
|
The caller owns action dispatch. pm owns the deterministic execution context:
|
|
37
36
|
`nowIso()` advances from `clock` by `tickMs`, and generated item identifiers
|
|
38
37
|
derive from `seed`. Async scopes are isolated with `AsyncLocalStorage`, so
|
|
39
|
-
concurrent recipes do not share counters.
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
concurrent recipes do not share counters. Normal CLI and MCP execution still
|
|
39
|
+
uses the system clock and cryptographic randomness unless the process opts in
|
|
40
|
+
through the environment contract below.
|
|
42
41
|
|
|
43
42
|
`defineWorkspaceRecipe` immediately validates the clock, seed, tick, schema,
|
|
44
43
|
operation actions, and recursively JSON-compatible inputs. Its TypeScript
|
|
@@ -51,6 +50,41 @@ Seeds are reproducibility inputs, not secrets. A replay is byte-identical only
|
|
|
51
50
|
when it begins from equivalent authoritative state and invokes the same ordered
|
|
52
51
|
operations with the same recipe.
|
|
53
52
|
|
|
53
|
+
## CLI and MCP process configuration
|
|
54
|
+
|
|
55
|
+
Shell-based harnesses can install the same SDK-owned deterministic context for
|
|
56
|
+
the `pm` and `pm-mcp` processes without patching JavaScript globals:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
PM_CLOCK=2026-07-28T10:00:00.000Z \
|
|
60
|
+
PM_CLOCK_TICK_MS=1 \
|
|
61
|
+
PM_SEED=example-fixture-v1 \
|
|
62
|
+
pm create --title "Deterministic task" --type Task --json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`PM_CLOCK` and `PM_SEED` are required together. `PM_CLOCK` must be an ISO-8601
|
|
66
|
+
instant with `Z` or a numeric UTC offset; timezone-less and non-ISO inputs are
|
|
67
|
+
rejected so separate hosts cannot interpret the same configuration differently.
|
|
68
|
+
`PM_CLOCK_TICK_MS` is optional, defaults to `1`, and must be a non-negative integer. Partial or invalid input
|
|
69
|
+
fails before command dispatch with the stable
|
|
70
|
+
`invalid_reproducible_process_environment` code and recovery that names the
|
|
71
|
+
missing or invalid variable. Unset all three variables for normal interactive
|
|
72
|
+
behavior.
|
|
73
|
+
|
|
74
|
+
Every CLI process invocation begins a fresh deterministic scope. A workflow
|
|
75
|
+
that launches several CLI processes must derive a stable, distinct seed for
|
|
76
|
+
each ordered step; reusing one seed intentionally reproduces the same entropy
|
|
77
|
+
sequence and can reproduce an existing generated identifier. A long-lived MCP
|
|
78
|
+
server instead owns one process-lifetime sequence and advances it across its
|
|
79
|
+
serialized JSON-RPC requests. Two equivalent servers therefore produce the
|
|
80
|
+
same files without generating duplicate identifiers inside either server.
|
|
81
|
+
|
|
82
|
+
The public SDK exports `PM_REPRODUCIBLE_PROCESS_ENV`,
|
|
83
|
+
`resolveReproducibleProcessEnvironment`,
|
|
84
|
+
`runWithReproducibleProcessEnvironment`, and
|
|
85
|
+
`createReproducibleProcessRunner` for custom one-shot and long-lived process
|
|
86
|
+
transports.
|
|
87
|
+
|
|
54
88
|
## Content-addressed snapshots
|
|
55
89
|
|
|
56
90
|
The SDK exports:
|
package/docs/SDK.md
CHANGED
|
@@ -1702,6 +1702,15 @@ const telemetry = await runTelemetry(
|
|
|
1702
1702
|
global tracker roots. `pm_context_mode`, run-level overrides, automatic tracker
|
|
1703
1703
|
context, assertion requirements, empty-run detection, and failure categories are
|
|
1704
1704
|
part of the SDK result contract rather than presentation-layer behavior.
|
|
1705
|
+
Workspace results distinguish the run-level requested mode from the effective
|
|
1706
|
+
per-test mode. `isolated` executes from an empty disposable directory;
|
|
1707
|
+
`snapshot` executes from a filtered disposable workspace. Trust preflight
|
|
1708
|
+
failures report `trust_refusal`, while malformed or incomplete provenance uses
|
|
1709
|
+
the additive `provenance_invalid` storage marker and fail-closed
|
|
1710
|
+
`invalid_provenance` trust reason. Package mutation adapters can call
|
|
1711
|
+
`attachLinkedTestMutationProvenance` so Git inspection occurs only when commands
|
|
1712
|
+
are added; `resolveLinkedTestSourceWorkspaceRoot` keeps their source-ref lookup
|
|
1713
|
+
aligned with CLI execution and `PM_SOURCE_WORKSPACE_ROOT` overrides.
|
|
1705
1714
|
When item test-result tracking is enabled, `measure` persists typed numeric
|
|
1706
1715
|
evidence on the producing run. Each entry has a stable name, finite numeric
|
|
1707
1716
|
value, optional unit and threshold, and the run timestamp. Run history remains
|
|
@@ -6,7 +6,8 @@ Tracker references: [pm-9wbiye](../.agents/pm/issues/pm-9wbiye.toon),
|
|
|
6
6
|
[pm-3zgh2c](../.agents/pm/features/pm-3zgh2c.toon),
|
|
7
7
|
[pm-eq9dlw](../.agents/pm/issues/pm-eq9dlw.toon), and
|
|
8
8
|
[pm-lu6sca](../.agents/pm/features/pm-lu6sca.toon), plus
|
|
9
|
-
[pm-5q8wa0](../.agents/pm/issues/pm-5q8wa0.toon)
|
|
9
|
+
[pm-5q8wa0](../.agents/pm/issues/pm-5q8wa0.toon) and
|
|
10
|
+
[pm-c0lrdm](../.agents/pm/features/pm-c0lrdm.toon).
|
|
10
11
|
|
|
11
12
|
Project management is context management. The public SDK therefore carries a
|
|
12
13
|
session's purpose and episode boundary through the same immutable history that
|
|
@@ -128,9 +129,10 @@ public SDK exports for custom hosts.
|
|
|
128
129
|
the bounded built-in resolver. It never contains environment values, session
|
|
129
130
|
paths, prompts, or file contents.
|
|
130
131
|
|
|
131
|
-
New mutation history records failed
|
|
132
|
-
`context.agent_provenance_outcomes`;
|
|
133
|
-
the compact legacy-compatible null projection.
|
|
132
|
+
New mutation history records failed or explicitly unavailable configured
|
|
133
|
+
resolver outcomes under `context.agent_provenance_outcomes`; dimensions with
|
|
134
|
+
no configured resolver retain the compact legacy-compatible null projection.
|
|
135
|
+
A resolver is only counted as
|
|
134
136
|
attempted when its required input belongs to the detected harness; a foreign
|
|
135
137
|
host's shared `AI_AGENT` value is not Codex input. Consequently `pm health` can report
|
|
136
138
|
`provenance_resolver_zero_success:<harness>:<dimension>:<resolver>:<attempts>`
|