@unbrained/pm-cli 2026.9.3 → 2026.9.4

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.
Files changed (120) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +27 -0
  3. package/dist/cli-bundle/bundle-manifest.json +146 -146
  4. package/dist/cli-bundle/chunks/{chunk-E5RBBCXO.js → chunk-6XSKPNCF.js} +75 -75
  5. package/dist/cli-bundle/chunks/chunk-A24WAVE6.js +8 -0
  6. package/dist/cli-bundle/chunks/{chunk-DKGP3QLE.js → chunk-HI6BHPCU.js} +2 -2
  7. package/dist/cli-bundle/chunks/{chunk-Y4PJ6HPK.js → chunk-I2AS367G.js} +2 -2
  8. package/dist/cli-bundle/chunks/{chunk-IEHHE6GA.js → chunk-OGBVU67G.js} +2 -2
  9. package/dist/cli-bundle/chunks/{chunk-EDPIS7EB.js → chunk-RI4XNOYS.js} +2 -2
  10. package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +38 -0
  11. package/dist/cli-bundle/chunks/{chunk-LENC656S.js → chunk-V72UV7QS.js} +76 -79
  12. package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +9 -0
  13. package/dist/cli-bundle/chunks/{chunk-34HASX3S.js → chunk-X6CMGV6L.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-UPPM2FOZ.js → chunk-YW4QK2G7.js} +2 -2
  15. package/dist/cli-bundle/chunks/{register-list-query-W2ZTOMKP.js → register-list-query-Z5YYSJJG.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-mutation-RVND5NCG.js → register-mutation-ELSP6I4I.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-operations-TTROIVC4.js → register-operations-OH7R3ZT4.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-setup-D3ZFHY3L.js → register-setup-E2AE72QG.js} +2 -2
  19. package/dist/cli-bundle/focused-chunks/{chunk-Q45NHPF2.js → chunk-25UJBH4M.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/{chunk-4HJFY4MB.js → chunk-3646BZ4W.js} +2 -2
  21. package/dist/cli-bundle/focused-chunks/{chunk-TXE4TSHM.js → chunk-4YRAVI43.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/{chunk-M5M6SVHS.js → chunk-53IHPICX.js} +2 -2
  23. package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +176 -0
  24. package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +54 -0
  25. package/dist/cli-bundle/focused-chunks/{chunk-D7KXFBXV.js → chunk-6PWPQKDN.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/{chunk-S27XMBIN.js → chunk-7N2TV7WZ.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/{chunk-5RFXUPN5.js → chunk-AJR3OP2E.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/{chunk-KZ2NB3ET.js → chunk-B3A6MJYE.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/{chunk-BWKHEIVF.js → chunk-BFDDJ2T2.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-4WR46RMG.js → chunk-BHUIRZWQ.js} +8 -8
  31. package/dist/cli-bundle/focused-chunks/{chunk-4RRHC3S4.js → chunk-JADHHPY6.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/{chunk-GT7MXDLW.js → chunk-MHKUIPJW.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-NBMJD6MK.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +20 -0
  35. package/dist/cli-bundle/focused-chunks/{chunk-OL5EH6I3.js → chunk-P2GOAOQN.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/{chunk-UCLO3XDU.js → chunk-YARWJM2B.js} +2 -2
  37. package/dist/cli-bundle/main.js +2 -2
  38. package/dist/cli-bundle/sdk-authoring.js +1 -1
  39. package/dist/cli-bundle/sdk-contracts.js +1 -1
  40. package/dist/cli-bundle/sdk-core.js +28 -31
  41. package/dist/cli-bundle/sdk-governance.js +1 -1
  42. package/dist/cli-bundle/sdk-graph.js +1 -1
  43. package/dist/cli-bundle/sdk-merge.js +42 -37
  44. package/dist/cli-bundle/sdk-query.js +1 -1
  45. package/dist/cli-bundle/sdk-runtime.js +1 -1
  46. package/dist/cli-bundle/sdk-testing.js +1 -1
  47. package/dist/cli-bundle/sdk.js +10 -10
  48. package/dist/core/diagnostics/remediation.js +4 -4
  49. package/dist/core/history/history.d.ts +37 -1
  50. package/dist/core/history/history.js +278 -58
  51. package/dist/core/history/replay.js +68 -34
  52. package/dist/core/lock/lock.d.ts +10 -0
  53. package/dist/core/lock/lock.js +42 -3
  54. package/dist/core/shared/author.d.ts +3 -1
  55. package/dist/core/shared/author.js +111 -23
  56. package/dist/sdk/environment/agent-environment.d.ts +296 -0
  57. package/dist/sdk/environment/agent-environment.js +467 -0
  58. package/dist/sdk/environment/project-runtime-compatibility.d.ts +19 -1
  59. package/dist/sdk/environment/project-runtime-compatibility.js +118 -21
  60. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
  61. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -14
  62. package/dist/sdk/governance/health.js +13 -44
  63. package/dist/sdk/governance/merge-receipt-history.d.ts +62 -0
  64. package/dist/sdk/governance/merge-receipt-history.js +207 -0
  65. package/dist/sdk/governance/provenance-health.js +9 -3
  66. package/dist/sdk/history-compact.js +14 -5
  67. package/dist/sdk/history-redact.js +58 -23
  68. package/dist/sdk/history-repair.js +16 -6
  69. package/dist/sdk/index.d.ts +2 -0
  70. package/dist/sdk/index.js +4 -2
  71. package/dist/sdk/merge/driver.d.ts +3 -1
  72. package/dist/sdk/merge/driver.js +9 -9
  73. package/dist/sdk/merge/index.d.ts +1 -1
  74. package/dist/sdk/merge/index.js +3 -3
  75. package/dist/sdk/merge/receipts.d.ts +17 -6
  76. package/dist/sdk/merge/receipts.js +246 -75
  77. package/dist/sdk/merge/reconcile.d.ts +9 -7
  78. package/dist/sdk/merge/reconcile.js +175 -12
  79. package/dist/sdk/merge/three-way.d.ts +22 -2
  80. package/dist/sdk/merge/three-way.js +92 -25
  81. package/dist/sdk/runtime-primitives.d.ts +2 -2
  82. package/dist/sdk/runtime-primitives.js +4 -4
  83. package/dist/types.d.ts +25 -0
  84. package/dist/types.js +2 -2
  85. package/docs/AGENT_ENVIRONMENTS.md +47 -0
  86. package/docs/AGENT_PROVENANCE_ADR.md +17 -2
  87. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +38 -1
  88. package/docs/MERGE_SAFETY.md +119 -23
  89. package/docs/README.md +1 -0
  90. package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +24 -2
  91. package/docs/SDK_RUNTIME_BOUNDARIES.md +17 -1
  92. package/docs/examples/sdk-agent-environment/README.md +14 -0
  93. package/docs/examples/sdk-agent-environment/package.json +8 -0
  94. package/docs/examples/sdk-agent-environment/run-agent-environment.mjs +154 -0
  95. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
  96. package/marketplace.json +2 -2
  97. package/package.json +2 -2
  98. package/packages/pm-beads/package.json +1 -1
  99. package/packages/pm-calendar/package.json +1 -1
  100. package/packages/pm-command-kit/package.json +1 -1
  101. package/packages/pm-digital-twin/package.json +1 -1
  102. package/packages/pm-governance-audit/package.json +1 -1
  103. package/packages/pm-guide-shell/package.json +1 -1
  104. package/packages/pm-kanban/package.json +1 -1
  105. package/packages/pm-lifecycle-hooks/package.json +1 -1
  106. package/packages/pm-linked-test-adapters/package.json +1 -1
  107. package/packages/pm-search-advanced/package.json +1 -1
  108. package/packages/pm-templates/package.json +1 -1
  109. package/packages/pm-todos/package.json +1 -1
  110. package/packages/pm-vcs/package.json +1 -1
  111. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  112. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  113. package/sdk/public-surface.json +534 -24
  114. package/dist/cli-bundle/chunks/chunk-AY324UJ5.js +0 -9
  115. package/dist/cli-bundle/chunks/chunk-L7B7343B.js +0 -8
  116. package/dist/cli-bundle/chunks/chunk-LISESA7W.js +0 -35
  117. package/dist/cli-bundle/focused-chunks/chunk-3ZBI35HU.js +0 -176
  118. package/dist/cli-bundle/focused-chunks/chunk-GHCZ3YFR.js +0 -20
  119. package/dist/cli-bundle/focused-chunks/chunk-KBLZRU62.js +0 -2
  120. package/dist/cli-bundle/focused-chunks/chunk-QKHCSUGJ.js +0 -51
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]="668a8823-62c4-5c69-9b9b-0c72d6d94b2b")}catch(e){}}();
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]="4ee067ac-f28d-5411-9ac7-c92112384a64")}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=668a8823-62c4-5c69-9b9b-0c72d6d94b2b
246
+ //# debugId=4ee067ac-f28d-5411-9ac7-c92112384a64
@@ -0,0 +1,47 @@
1
+ # SDK Agent Environments
2
+
3
+ Tracker: [pm-e1vkee](../.agents/pm/features/pm-e1vkee.toon), [pm-gd6vnn](../.agents/pm/features/pm-gd6vnn.toon), [pm-li2fj5](../.agents/pm/features/pm-li2fj5.toon), [pm-t8a0x1](../.agents/pm/features/pm-t8a0x1.toon)
4
+
5
+ ## Agent Quick Context
6
+
7
+ `@unbrained/pm-cli/sdk` provides three composable contracts for building reproducible project-management environments without a machine-learning runtime dependency:
8
+
9
+ - an observation contract declares every read ceiling, emitted-byte calibration, corpus-size dependence, and an ordered degradation ladder;
10
+ - a verdict contract evaluates named, versioned predicates over recorded state and returns `satisfied`, `violated`, or `not_applicable` without producing a reward signal;
11
+ - an episode specification combines a deterministic workspace recipe, canonical task items, observable and withheld fields, hard limits, and an adapter for ordinary `PmClient` actions.
12
+
13
+ The executable [public-SDK example](examples/sdk-agent-environment/README.md) runs the complete reset → observe → act → verdict → close loop in a temporary pm workspace.
14
+
15
+ ## Contract Boundaries
16
+
17
+ Observation cost is knowable before a read. `describeObservationCost()` returns the sum of the declared read ceilings plus the calibrated expected emitted bytes. `serveDeclaredObservation()` measures stable serialized bytes, attempts tiers in declaration order, names the served tier, and returns a payload-free refusal if no tier fits.
18
+
19
+ Verdicts only inspect the adapter's `WorkspaceRecordedState`. Evidence identifies the exact snapshot and JSON pointer while a digest avoids copying field values into the result. The interpreter is deterministic and read-only; `policy: "verdict_only_no_reward"` makes the non-reward boundary machine-readable.
20
+
21
+ Episodes never grant a second mutation vocabulary. The adapter's `execute()` method should call ordinary public `PmClient` methods, so lifecycle validation, history, extensions, and policy remain authoritative. Each session owns its counters and trajectory, allowing concurrent runs without shared episode state.
22
+
23
+ Withheld grading fields cannot also be observable. Every tier field must be declared observable, and projection copies only the selected tier fields. Hard action and observation limits fail closed.
24
+
25
+ ## Minimal Shape
26
+
27
+ ```ts
28
+ import {
29
+ defineEpisodeSpecification,
30
+ openPmEpisode,
31
+ type EpisodeRuntimeAdapter,
32
+ } from "@unbrained/pm-cli/sdk";
33
+
34
+ const specification = defineEpisodeSpecification({
35
+ // Versioned recipe, task set, observation, verdict, and limits.
36
+ });
37
+ const session = await openPmEpisode(
38
+ specification,
39
+ adapter satisfies EpisodeRuntimeAdapter<MyAction>,
40
+ );
41
+
42
+ await session.observe();
43
+ await session.step({ kind: "close" });
44
+ const evidence = await session.close();
45
+ ```
46
+
47
+ Use the same specification and adapter boundary for benchmarks, evaluations, training data collection, or scale-transfer experiments. Consumer intent changes through `mode`; the pm action and evidence contracts do not.
@@ -10,7 +10,9 @@ 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). Cross-harness adapters and
13
+ [pm-3yxwv5](../.agents/pm/issues/pm-3yxwv5.toon). Stable Claude session
14
+ discovery across child working directories is tracked by
15
+ [pm-l7m7k5](../.agents/pm/issues/pm-l7m7k5.toon). Cross-harness adapters and
14
16
  operator-managed probe/vocabulary controls are tracked by
15
17
  [pm-c0lrdm](../.agents/pm/features/pm-c0lrdm.toon) and
16
18
  [pm-yds9dt](../.agents/pm/chores/pm-yds9dt.toon).
@@ -56,7 +58,13 @@ from literal descriptor keys, trusted caller data, or a named bounded resolver.
56
58
  Detection does not spawn processes, traverse process trees, evaluate user
57
59
  regexes, or access the network. The built-in Claude and Codex resolvers read
58
60
  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
61
+ resolves an explicitly supplied transcript first, then the direct workspace
62
+ coordinate, then performs a deterministic scan of at most 512 immediate
63
+ project directories for the unique stable session id. This keeps provenance
64
+ attached when the invocation cwd moves into a child package. No match is
65
+ reported as `resolver_input_missing`; multiple matches are ambiguous and remain
66
+ `resolver_failed` instead of selecting an arbitrary transcript. Claude uses the
67
+ bounded session window to recover its recorded model/version. Codex uses the
60
68
  recent tail plus a bounded initial-head fallback for oversized sessions to
61
69
  recover allow-listed `turn_context.model` and `turn_context.effort` values.
62
70
  Both cap traversal, file bytes, lines, and line length, ignore all other fields,
@@ -70,6 +78,13 @@ the existing domain-separated, truncated `agent_instance` digest. Public
70
78
  telemetry continues to use installation-scoped hashes or presence booleans; it
71
79
  does not export raw provenance values.
72
80
 
81
+ Health counts resolvers with an available input, plus failed or ambiguous
82
+ resolution attempts, as attempts. A sustained attempted-but-zero-success series
83
+ remains advisory: it truthfully identifies parser, filesystem, ambiguity, or
84
+ provider-shape drift without treating missing descriptive metadata as
85
+ authorization or item-state corruption. Missing-input and probes-disabled
86
+ events are classified separately and do not inflate that warning.
87
+
73
88
  ## Compatibility
74
89
 
75
90
  All new history fields are optional. Readers must accept:
@@ -1,6 +1,6 @@
1
1
  # Context Integrity Contracts
2
2
 
3
- Tracker references: [pm-4fwgaz](../.agents/pm/issues/pm-4fwgaz.toon), [pm-qqoumq](../.agents/pm/issues/pm-qqoumq.toon), [pm-fpdk37](../.agents/pm/issues/pm-fpdk37.toon), [pm-jn1x30](../.agents/pm/issues/pm-jn1x30.toon), and [pm-0wfdim](../.agents/pm/issues/pm-0wfdim.toon).
3
+ Tracker references: [pm-4fwgaz](../.agents/pm/issues/pm-4fwgaz.toon), [pm-qqoumq](../.agents/pm/issues/pm-qqoumq.toon), [pm-fpdk37](../.agents/pm/issues/pm-fpdk37.toon), [pm-jn1x30](../.agents/pm/issues/pm-jn1x30.toon), [pm-0wfdim](../.agents/pm/issues/pm-0wfdim.toon), [pm-javbsq](../.agents/pm/issues/pm-javbsq.toon), and [pm-aka8m7](../.agents/pm/issues/pm-aka8m7.toon).
4
4
 
5
5
  ## Agent Quick Context
6
6
 
@@ -53,6 +53,43 @@ History writers using item-hash epoch 2 always emit `item_hash_version: 2`. An e
53
53
 
54
54
  Repair keeps implicit legacy streams implicit and byte-stable when no drift exists. Unsupported explicit epochs still fail with a typed `unsupported_item_hash_version` diagnostic instead of being rewritten.
55
55
 
56
+ | Writer/runtime range | Item-hash output | Read contract |
57
+ | ---------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------ |
58
+ | Legacy writers before an explicit marker | implicit epoch 1 | Modern readers retain legacy canonicalization candidates. |
59
+ | Observed 2026.8.24 through 2026.8.28 | explicit epoch 2 | Modern readers accept both field-frozen and expanded epoch-2 forms without mixing forms inside one entry. |
60
+ | 2026.8.31 and newer | explicit epoch 3 | Exact pins and bounded ranges that cannot select an epoch-3 reader cause current runtimes to reject the write before mutation. |
61
+
62
+ The table records confirmed release boundaries rather than inventing an exact
63
+ first release for legacy epoch 1 or epoch 2. The SDK exports
64
+ `HISTORY_ITEM_HASH_VERSION_3_INTRODUCED_IN`, and runtime compatibility checks
65
+ use that boundary for package-manager-neutral write refusal.
66
+
67
+ ## Whole-Record History Integrity
68
+
69
+ Item anchors prove the replayed project state; they do not prove who recorded an
70
+ event, when it happened, which operation produced it, or which provenance and
71
+ context were attached. New events therefore use a separate record-integrity
72
+ epoch. `record_hash_version: 1` seals every immutable field while preserving the
73
+ item-hash epoch as an independent compatibility contract.
74
+
75
+ `verifyHistoryRecordHash()` reports `record_and_item_state` for a valid sealed
76
+ event and `item_state_only` for a legacy event with neither record-envelope
77
+ field. Half-present, unsupported, and mismatched envelopes fail closed. The
78
+ public SDK also exports the record and patch hashing, sealing,
79
+ `verifyHistoryRewriteEvidence()`, rewrite-resealing, stream-digest, and
80
+ reanchoring primitives so packages and embedded hosts do not need private core
81
+ imports or their own canonicalization.
82
+
83
+ Maintenance retains prior anchors and patch digests in `reanchor_evidence`.
84
+ When policy permits, it also retains the exact prior sealed record so
85
+ metadata-only rewrites remain independently verifiable. Privacy-sensitive
86
+ redaction and provenance normalization deliberately retain digest-only evidence
87
+ instead of embedding the removed value. This separates two claims: the current
88
+ chain is replay-consistent, and a rewrite preserved evidence of what it
89
+ replaced. Compaction records a digest of its pruned prefix and explicitly states
90
+ that individual pruned entries require the pre-compaction stream; it never
91
+ upgrades intentional information loss into a stronger assurance claim.
92
+
56
93
  ## Verification Boundary
57
94
 
58
95
  The regression suite covers each contract at its public SDK or command boundary. Release verification additionally installs the packed package into a temporary project and exercises sparse reads, remote docs, graph impact, extension diagnostics, and history repair without touching the repository tracker.
@@ -5,7 +5,19 @@ Tracked by [pm-wc1r](../.agents/pm/features/pm-wc1r.toon), with the integrity an
5
5
  Lossless receipt health gating is tracked by
6
6
  [pm-baksix](../.agents/pm/issues/pm-baksix.toon), and executable remediation
7
7
  that performs settlement is tracked by
8
- [pm-r0p3at](../.agents/pm/issues/pm-r0p3at.toon).
8
+ [pm-r0p3at](../.agents/pm/issues/pm-r0p3at.toon). Immutable record sealing and
9
+ retained re-anchor evidence are tracked by
10
+ [pm-javbsq](../.agents/pm/issues/pm-javbsq.toon) and
11
+ [pm-aka8m7](../.agents/pm/issues/pm-aka8m7.toon); preferred-era receipt-summary
12
+ compatibility is tracked by
13
+ [pm-wn3ee5](../.agents/pm/issues/pm-wn3ee5.toon).
14
+ Lossless concurrent acceptance-criteria composition is tracked by
15
+ [pm-inn5y5](../.agents/pm/issues/pm-inn5y5.toon).
16
+ Recency-aware scalar convergence, bounded fresh-clone decision evidence, and
17
+ audited pre-durable receipt dispositions are tracked by
18
+ [pm-7wzb6d](../.agents/pm/issues/pm-7wzb6d.toon),
19
+ [pm-mg13iz](../.agents/pm/issues/pm-mg13iz.toon), and
20
+ [pm-cf4t42](../.agents/pm/issues/pm-cf4t42.toon).
9
21
 
10
22
  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.
11
23
 
@@ -59,12 +71,12 @@ pm merge install --dry-run --json
59
71
 
60
72
  ## Artifact semantics
61
73
 
62
- | Artifact | Driver | Merge behavior |
63
- | ---------------------------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
64
- | Item `.toon` / `.md` | `pm-item-toon` / `pm-item-markdown` | Three-way field merge; append-like collections use set union, `updated_at` uses latest timestamp, scalar conflicts select a stable direction-independent value, and canonical serialization recomputes TOON counts. |
65
- | `history/*.jsonl` | `pm-history` | Preserves the common prefix and both divergent suffixes, orders deterministically, then re-anchors the resulting hash chain. |
66
- | 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. |
67
- | 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. |
74
+ | Artifact | Driver | Merge behavior |
75
+ | ---------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
76
+ | Item `.toon` / `.md` | `pm-item-toon` / `pm-item-markdown` | Three-way field merge; append-like collections use set union, `updated_at` uses the latest timestamp, scalar conflicts select the value from the later document update with stable value order as an equal-timestamp tie-break, and canonical serialization recomputes TOON counts. |
77
+ | `history/*.jsonl` | `pm-history` | Preserves the common prefix and both divergent suffixes, orders deterministically, then re-anchors the resulting hash chain. |
78
+ | 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. |
79
+ | 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. |
68
80
 
69
81
  The `tests` collection has an additional execution-safety rule. Its semantic
70
82
  identity excludes provenance so the same command/context does not duplicate
@@ -80,17 +92,50 @@ boundary for append-like data that becomes executable after a merge; ordinary
80
92
  notes, files, and other non-executable collections retain normal set-union
81
93
  behavior.
82
94
 
83
- 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).
95
+ Although `acceptance_criteria` is serialized as a semicolon-delimited scalar
96
+ for backward compatibility, the item driver treats its parsed criteria as a
97
+ collection. Independent additions compose in branch order, removals made by
98
+ either side remain removed, the field is reported in `union_fields`, and a
99
+ lossless merge does not create a scalar conflict decision. This gives repeated
100
+ `pm update --add-ac` mutations the same multi-branch preservation guarantee as
101
+ native append-like metadata without a storage migration.
102
+
103
+ When both sides change the same item scalar differently, the driver retains the
104
+ value from the document with the later `metadata.updated_at` timestamp. Equal
105
+ timestamps fall back to stable value ordering, so reversing Git's ours/theirs
106
+ labels still converges to the same result. Item results, driver results, and
107
+ receipts expose `conflict_resolution: latest_document_update` and
108
+ `requested_preference_applied: false`; each conflict decision adds
109
+ `retained_side` and `resolution_basis` so review automation can distinguish a
110
+ recency decision from the stable tie-break. The caller's
111
+ `requested_preference` remains observable but does not override item scalar
112
+ convergence. Readers continue to accept legacy `preferred_side` and
113
+ `stable_value_order` receipts and normalize the legacy `preferred` key. JSON
114
+ leaf conflicts retain their explicit preferred-side policy. Git keeps the item
115
+ path conflicted so a human or coordinating agent must review the discarded
116
+ value and explicitly `git add` the resolution.
117
+
118
+ The exact object `{ "pm_item_scalar_missing": true }` is reserved for
119
+ JSON-stable missing-value evidence. Item merge inputs reject that object as a
120
+ present metadata value, while the hashing primitive independently separates
121
+ present and missing domains. This prevents extension data from impersonating a
122
+ deletion without wrapping every ordinary scalar in receipt output.
84
123
 
85
124
  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).
86
125
 
87
126
  For item conflicts, the driver writes a clone-local receipt below the Git
88
127
  directory and a durable privacy-safe sidecar below `merge-receipts/` in the
89
128
  tracker. The local receipt contains retained and discarded values so recovery
90
- does not depend on a reflog. The tracked sidecar contains only field names and
91
- value hashes, so fresh clones and CI can still fail closed on an unreviewed
92
- decision without publishing either value. When both copies exist the SDK
93
- deduplicates them and prefers the locally recoverable copy:
129
+ does not depend on a reflog. The tracked sidecar applies the versioned
130
+ `bounded_non_sensitive_scalars_v1` policy. Built-in lifecycle statuses,
131
+ priority integers from 0 through 4, bounded risk/confidence/severity ordinals,
132
+ and `null` are stored with both their value and matching hash. All other values
133
+ remain hash-only. `value_availability` distinguishes `bounded_inline`, `mixed`,
134
+ and `hash_only`, while the clone-local receipt remains `clone_local`. This lets
135
+ a fresh-clone reviewer recover ordinary control-plane decisions without
136
+ publishing titles, descriptions, custom statuses, or other potentially private
137
+ content. When both copies exist the SDK deduplicates them and prefers the
138
+ locally recoverable copy:
94
139
 
95
140
  ```bash
96
141
  pm merge report
@@ -108,7 +153,9 @@ that distinction without returning malformed contents.
108
153
  loss-aware contract through `complete`, `invalid_evidence_count`, bounded
109
154
  `invalid_evidence[]`, `invalid_evidence_truncated`, and
110
155
  `clone_local_evidence_resolved`. Each rejected candidate reports a stable
111
- reason plus its `clone_local`, `durable`, or copy-consistency source. A safe
156
+ reason plus its `clone_local`, `durable`, or copy-consistency source. Schema and
157
+ identity failures additionally expose a bounded `validation_error` such as
158
+ `required_fields`, `item_path`, `filename`, or `durable_decisions`. A safe
112
159
  receipt filename is returned as `receipt_id`; unsafe candidate names are
113
160
  represented only by `candidate_name_hash`, and malformed contents are never
114
161
  returned. The detail list is capped at 100 rows while the count remains exact,
@@ -118,13 +165,26 @@ POSIX instead of treating platform-specific `ENOENT`/`ENOTDIR` spellings as
118
165
  equivalent. Full health also cross-checks the privacy-safe receipt summaries in
119
166
  append-only history against valid pending and reconciled evidence. Missing
120
167
  evidence emits `merge_receipt_history_reference_missing:<n>` with bounded item,
121
- history-line, and receipt-id-or-hash coordinates. Its remediation enumerates
122
- the exact references and directs recovery from an authoritative clone or
123
- backup; it never recommends deleting receipts or rewriting history. The CLI
168
+ history-line, and receipt-id-or-hash coordinates. Recover an available receipt
169
+ from an authoritative clone or backup first. For an exact reference whose
170
+ history-event timestamp predates tracked durable receipts, `pm merge reconcile
171
+ --force` can append a `merge_reconcile` audit event containing the original
172
+ item, line, receipt id, timestamp, and the closed
173
+ `legacy_clone_local_only` reason. Health accepts only that exact coordinate and
174
+ reports it through `accepted_missing_merge_receipt_dispositions`; it never
175
+ rewrites or deletes the original history. The audit event must also occur after
176
+ the referenced history line; an earlier event cannot pre-authorize a later
177
+ missing receipt. Missing post-durable evidence remains blocking and cannot be
178
+ dispositioned through this compatibility path. The CLI
124
179
  exits nonzero when evidence is incomplete, even when the valid-receipt count is
125
180
  zero. Current SDK implementations always emit the new field, while its optional
126
181
  type preserves structural compatibility for existing typed adapters and test
127
- fixtures. `runMergeReceiptReport` remains the compatible valid-only report.
182
+ fixtures. A structurally valid preferred-era history summary that contains its
183
+ complete privacy-safe receipt evidence is accepted in place: health counts it
184
+ as `accepted_legacy_merge_receipt_references` and does not demand an external
185
+ receipt file that the older writer never created. Incomplete, contradictory, or
186
+ modern summaries still fail closed. `runMergeReceiptReport` remains the
187
+ compatible valid-only report.
128
188
 
129
189
  ## Cross-branch id collision safety
130
190
 
@@ -165,7 +225,8 @@ Serialized source claims are ignored. Receipt readers validate the complete
165
225
  bounded schema, safe identifiers, filename and item-path identity, timestamps,
166
226
  and bounded decision structure before a sidecar enters health or
167
227
  reconciliation. Reads use size-preflighted, no-follow regular-file descriptors;
168
- durable decisions must retain hash-only values. Qualifying durable-only receipts
228
+ durable decision values must conform to the declared bounded-inline policy or
229
+ remain hash-only. Qualifying durable-only receipts
169
230
  are reloaded from the authoritative store and accepted only after exact canonical
170
231
  item path, declared-field, and merged-value hash verification. Legacy receipts,
171
232
  receipts whose declared fields disagree with their hashes, same-item tampering,
@@ -173,16 +234,19 @@ and drift on unrelated items fail closed to the normal `pm history-repair`
173
234
  guidance. Health indexes authoritative evidence once by item and reconciliation
174
235
  uses the same per-item groups with a fixed receipt-only worker pool, so committed
175
236
  sidecars cannot amplify drift scans into unbounded parallel repair work.
176
- The machine-executable remediation names the apply command because `--dry-run`
177
- returns a successful preview without changing the red health state. Operators
178
- may still run the documented dry-run first; agents that execute the remediation
179
- field verbatim perform the settlement instead of entering a successful no-op
180
- loop.
237
+ The machine-executable remediation for a missing receipt reference names
238
+ `pm merge reconcile --dry-run`. It never publishes `--force` as an executable
239
+ hint: the human-readable summary explains that exact eligible pre-durable
240
+ coordinates may be dispositioned by a separately reviewed force pass. Ordinary
241
+ pending lossless receipts retain their unforced apply remediation.
181
242
  Apply-mode reconciliation repeats the same proof against the exact
182
243
  item snapshot used by the audited history rewrite. The audit event and
183
244
  settlement include only the individually proven receipt id, so one valid receipt
184
245
  cannot authorize an untrusted same-item sibling. Failed or unproven receipts
185
246
  remain pending unless the coordinator explicitly reviews and supplies `--force`.
247
+ Snapshot verification accepts both the current presence-domain digest and the
248
+ legacy version-1 scalar digest, so already-written receipts remain repairable;
249
+ new receipts always use the collision-free presence-domain scheme.
186
250
  Receipts with discarded scalar values retain the distinct
187
251
  `merge_decisions_unreviewed:<n>` finding. Matching authoritative hash proof
188
252
  allows those receipts to settle without `--force`; without qualifying proof,
@@ -192,6 +256,15 @@ an unforced apply command that clears `merge_decisions_unreviewed` when the
192
256
  receipt proves the exact current merged values. This prevents routine repair
193
257
  from hiding unfinished reconciliation while avoiding redundant force for an
194
258
  already-proven canonical snapshot.
259
+ The same `--force` boundary also handles an unrecoverable pre-durable
260
+ clone-local-only history reference. Preview and apply results expose
261
+ `missing_history_references_before`, `legacy_disposition_eligible`,
262
+ `legacy_disposition_recorded`, and `missing_history_references_after`. When
263
+ coordinates exceed the bounded health response, explicit result guidance
264
+ requires repeated dry-run and reviewed force passes until health no longer
265
+ reports truncated coordinate details and the remaining count is zero. An apply
266
+ result cannot return `ok: true` while any missing reference or truncated
267
+ evidence remains.
195
268
  It exits nonzero while either merge-critical validation check is non-green, so
196
269
  CI and explicit post-merge hooks cannot approve unresolved receipts or drift.
197
270
  The apply pass uses the audited history rewrite boundary to append a
@@ -233,6 +306,29 @@ keeps version incompatibility distinct from item corruption and is tracked by
233
306
  [pm-2htk4p](../.agents/pm/issues/pm-2htk4p.toon) and
234
307
  [pm-2qahia](../.agents/pm/issues/pm-2qahia.toon).
235
308
 
309
+ New history events also carry `record_hash_version` and `record_hash`. Unlike
310
+ the item anchors, the record hash covers the complete immutable event: author
311
+ and agent provenance, timestamp, operation, message, context, patch, item-hash
312
+ epoch, and before/after anchors. A record that carries only one envelope field,
313
+ uses an unsupported record epoch, or changes after sealing fails verification.
314
+ Entries created before this envelope remain readable as explicit
315
+ `item_state_only` coverage; they are not presented as record-authenticated.
316
+
317
+ Every maintenance rewrite verifies a present record hash before changing the
318
+ stream and reseals the output. When anchors or patch representation change, the
319
+ entry's append-only `reanchor_evidence` retains the prior anchors, item epoch,
320
+ patch digest, and prior record envelope. Lenient repair additionally retains
321
+ the complete replaced patch operations. `verifyHistoryRewriteEvidence()`
322
+ reconstructs every available prior envelope and rejects a record that was
323
+ modified and merely resealed after maintenance. Redaction never copies sensitive patch
324
+ values into new evidence: it keeps the digest and drops a retained patch if the
325
+ patch itself matched a redaction rule. Compaction baselines retain the pruned
326
+ entry count and ordered stream digest plus an explicit
327
+ `individual_pruned_entries_require_pre_compaction_stream` limitation. A holder
328
+ of the pre-compaction stream can therefore validate the checkpoint, while the
329
+ post-compaction stream does not falsely claim that it can reconstruct content
330
+ that was intentionally pruned.
331
+
236
332
  ## Delete versus modify policy
237
333
 
238
334
  A delete on one branch and an edit on another is not safely resolvable by a generic file driver. The merged workspace must not silently resurrect the item. `storage_integrity` reports the live document plus delete-terminated history as a hard finding. The coordinator chooses one policy explicitly:
package/docs/README.md CHANGED
@@ -63,6 +63,7 @@ pm guide release --json
63
63
  - [Mutation Integrity](MUTATION_INTEGRITY.md) - shared CLI/SDK/MCP author, secret, append-only disposition, and stale-work guardrails.
64
64
  - [Agent Provenance ADR Amendment](AGENT_PROVENANCE_ADR.md) - extensible model, effort, role, and host provenance with privacy and compatibility boundaries.
65
65
  - [SDK Agent Session and Episode Context](SDK_AGENT_SESSION_CONTEXT.md) - inherited role/topic context, cross-process episode identity, and deterministic history grouping.
66
+ - [SDK Agent Environments](AGENT_ENVIRONMENTS.md) - calibrated observations, total verdicts, isolated episodes, and an executable public-SDK environment.
66
67
  - [Improvement Ledger and History Analytics](IMPROVEMENT_ANALYTICS.md) - audited quantitative observations, live provenance coverage, and bounded observational fleet outcomes.
67
68
  - [Project Assurance Primitives](ASSURANCE.md) - SDK-owned measurements, assertions, lifecycle gates, cost receipts, and durable verdict history shared by CLI and MCP.
68
69
  - [Defect Recurrence and Boundary Evidence](DEFECT_RECURRENCE.md) - captured external samples, structured defect-escape evidence, incremental change-risk indexing, and executable recovery-producer census.
@@ -1,6 +1,6 @@
1
1
  # SDK Context and Evidence Contracts
2
2
 
3
- Tracked by [pm-gok2km](../.agents/pm/issues/pm-gok2km.toon), [pm-zryb9d](../.agents/pm/issues/pm-zryb9d.toon), [pm-qckpnq](../.agents/pm/issues/pm-qckpnq.toon), [pm-hfqju5](../.agents/pm/issues/pm-hfqju5.toon), [pm-2htk4p](../.agents/pm/issues/pm-2htk4p.toon), and [pm-v0a0un](../.agents/pm/issues/pm-v0a0un.toon).
3
+ Tracked by [pm-gok2km](../.agents/pm/issues/pm-gok2km.toon), [pm-zryb9d](../.agents/pm/issues/pm-zryb9d.toon), [pm-qckpnq](../.agents/pm/issues/pm-qckpnq.toon), [pm-hfqju5](../.agents/pm/issues/pm-hfqju5.toon), [pm-2htk4p](../.agents/pm/issues/pm-2htk4p.toon), [pm-v0a0un](../.agents/pm/issues/pm-v0a0un.toon), [pm-7wzb6d](../.agents/pm/issues/pm-7wzb6d.toon), [pm-mg13iz](../.agents/pm/issues/pm-mg13iz.toon), and [pm-cf4t42](../.agents/pm/issues/pm-cf4t42.toon).
4
4
 
5
5
  These contracts keep SDK context truthful, bounded, and reusable across the CLI, MCP, packages, and automation. They are designed around the project principle that project management is context management: a compact response must reveal material omissions, merge evidence must describe what actually survived, and compatibility failures must not masquerade as corruption.
6
6
 
@@ -22,7 +22,29 @@ This keeps health diagnostics and lazy runtime behavior on one ownership contrac
22
22
 
23
23
  ## Merge provenance
24
24
 
25
- Stable-value item merges distinguish a caller request from the outcome. Low-level item results, driver results, clone-local receipts, and privacy-safe summaries expose `requested_preference`. The actual outcome remains in each decision's `retained` and `discarded` values or hashes. New receipts do not emit the ambiguous `preferred` key; readers still ingest legacy schema-v1 receipts and normalize that key to `requested_preference`.
25
+ Item scalar merges distinguish a caller request from the convergent outcome.
26
+ The `latest_document_update` policy selects the branch document with the later
27
+ `metadata.updated_at`; equal timestamps use stable value order. Low-level item
28
+ results, driver results, receipts, and privacy-safe summaries expose
29
+ `requested_preference` plus `requested_preference_applied: false`. Each new
30
+ decision records `retained_side` and `resolution_basis`. New receipts do not
31
+ emit the ambiguous `preferred` key; readers still ingest legacy schema-v1
32
+ receipts and normalize `preferred_side` and `stable_value_order` evidence.
33
+
34
+ Tracked receipt evidence uses `bounded_non_sensitive_scalars_v1`: built-in
35
+ status, priority 0 through 4, risk/confidence/severity ordinals, and `null` may
36
+ be included beside their verifiable hashes. Every other value remains
37
+ hash-only. Fresh-clone consumers must branch on `value_availability` rather than
38
+ assuming raw values exist. Invalid evidence separates `schema_invalid` from
39
+ `identity_invalid` and adds a bounded `validation_error`, while retaining the
40
+ legacy combined reason in the public union for source compatibility.
41
+
42
+ `runMergeReconcile` also reports missing history receipt counts before and
43
+ after the operation. With explicit `force`, it can append a narrowly matched
44
+ audit disposition for a missing reference whose original event predates the
45
+ durable-receipt epoch. The item id, original line, receipt id, and timestamp
46
+ must all match, and the audit event must occur later in that history stream;
47
+ current-era missing evidence remains blocking.
26
48
 
27
49
  ## Claim race classification
28
50
 
@@ -2,7 +2,9 @@
2
2
 
3
3
  Tracker: [pm-1eted6](../.agents/pm/issues/pm-1eted6.toon),
4
4
  [pm-3lhth4](../.agents/pm/issues/pm-3lhth4.toon), and
5
- [pm-0xmajx](../.agents/pm/issues/pm-0xmajx.toon). Refusal reachability and
5
+ [pm-0xmajx](../.agents/pm/issues/pm-0xmajx.toon), with forward history-epoch
6
+ protection tracked by
7
+ [pm-aka8m7](../.agents/pm/issues/pm-aka8m7.toon). Refusal reachability and
6
8
  recovery completeness are tracked by
7
9
  [pm-elmpav](../.agents/pm/features/pm-elmpav.toon),
8
10
  [pm-185870](../.agents/pm/issues/pm-185870.toon), and
@@ -29,6 +31,20 @@ package-manager-neutral recovery action. SDK callers receive the same warning
29
31
  inside `ProjectRuntimeCompatibilityResult`. `PM_ALLOW_STALE_CLI=1` is the
30
32
  explicit, auditable emergency override.
31
33
 
34
+ The boundary is bidirectional for history storage. A current runtime also
35
+ refuses a mutation when any package declaration or lockfile pin cannot select a
36
+ runtime that reads the writer epoch. Every manifest section is evaluated, so a
37
+ newer permissive declaration cannot hide an older exact pin. Upper-bounded
38
+ ranges that exclude the first compatible reader also fail closed, including
39
+ inclusive hyphen ranges. Disjunctive ranges evaluate each alternative, so one
40
+ branch that can select a compatible reader keeps the declaration writable. The
41
+ original incompatible declaration is preserved in the diagnostic rather than
42
+ being reduced to its representative lower bound. The typed
43
+ `project_runtime_history_epoch_incompatible` error reports the writer epoch,
44
+ the incompatible declaration, its redaction-safe source, and the minimum
45
+ upgrade. Reads remain available, and the same emergency override is reserved
46
+ for an intentionally coordinated fleet migration.
47
+
32
48
  The public `isProjectMutatingInvocation` classifier applies the same decision
33
49
  to package hosts and the bundled CLI. It resolves mixed command families by
34
50
  their effective action: configuration, merge, schema, profile, package,
@@ -0,0 +1,14 @@
1
+ # Public SDK Agent Environment
2
+
3
+ Tracker: [pm-t8a0x1](../../../.agents/pm/features/pm-t8a0x1.toon)
4
+
5
+ This executable example imports only Node.js built-ins and `@unbrained/pm-cli/sdk`. It creates an isolated temporary tracker, uses ordinary `PmClient` actions, serves a budgeted observation, evaluates recorded state, and closes the episode. It has no machine-learning dependencies.
6
+
7
+ From an installed package checkout:
8
+
9
+ ```bash
10
+ npm install @unbrained/pm-cli
11
+ npm start
12
+ ```
13
+
14
+ The JSON result is intentionally small and stable enough for a CI assertion. The temporary workspace is removed after the run.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "pm-sdk-agent-environment-example",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "start": "node run-agent-environment.mjs"
7
+ }
8
+ }