@unbrained/pm-cli 2026.9.2 → 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 (165) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +44 -0
  3. package/dist/cli/after-command-context-usage.js +16 -3
  4. package/dist/cli-bundle/bundle-manifest.json +151 -151
  5. package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +230 -0
  6. package/dist/cli-bundle/chunks/chunk-A24WAVE6.js +8 -0
  7. package/dist/cli-bundle/chunks/{chunk-TAG4VC22.js → chunk-HI6BHPCU.js} +27 -27
  8. package/dist/cli-bundle/chunks/{chunk-Y7VOMSZT.js → chunk-I2AS367G.js} +2 -2
  9. package/dist/cli-bundle/chunks/{chunk-X4RCGLTX.js → chunk-OGBVU67G.js} +5 -5
  10. package/dist/cli-bundle/chunks/{chunk-DTGWEL23.js → chunk-RI4XNOYS.js} +2 -2
  11. package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +38 -0
  12. package/dist/cli-bundle/chunks/{chunk-FZ4Z2J4F.js → chunk-V72UV7QS.js} +76 -79
  13. package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +9 -0
  14. package/dist/cli-bundle/chunks/{chunk-T6H5BZCP.js → chunk-X6CMGV6L.js} +2 -2
  15. package/dist/cli-bundle/chunks/{chunk-3WICXLVT.js → chunk-YW4QK2G7.js} +2 -2
  16. package/dist/cli-bundle/chunks/{register-list-query-XYNX4ASQ.js → register-list-query-Z5YYSJJG.js} +2 -2
  17. package/dist/cli-bundle/chunks/{register-mutation-WFQ7MJTX.js → register-mutation-ELSP6I4I.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-operations-JVTI7JPP.js → register-operations-OH7R3ZT4.js} +2 -2
  19. package/dist/cli-bundle/chunks/{register-setup-KVNC5KPL.js → register-setup-E2AE72QG.js} +2 -2
  20. package/dist/cli-bundle/focused-chunks/{chunk-MEASX544.js → chunk-25UJBH4M.js} +2 -2
  21. package/dist/cli-bundle/focused-chunks/{chunk-SVXJYD6G.js → chunk-3646BZ4W.js} +2 -2
  22. package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +12 -0
  23. package/dist/cli-bundle/focused-chunks/chunk-53IHPICX.js +3 -0
  24. package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +176 -0
  25. package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +54 -0
  26. package/dist/cli-bundle/focused-chunks/{chunk-4O4CJAR6.js → chunk-6PWPQKDN.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/chunk-7N2TV7WZ.js +8 -0
  28. package/dist/cli-bundle/focused-chunks/chunk-AJR3OP2E.js +3 -0
  29. package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +2 -0
  31. package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +9 -0
  32. package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +6 -0
  33. package/dist/cli-bundle/focused-chunks/{chunk-KB5OFSFD.js → chunk-MHKUIPJW.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-NBMJD6MK.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +20 -0
  36. package/dist/cli-bundle/focused-chunks/{chunk-BEVHCEWG.js → chunk-P2GOAOQN.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +2 -0
  38. package/dist/cli-bundle/main.js +15 -15
  39. package/dist/cli-bundle/sdk-authoring.js +1 -1
  40. package/dist/cli-bundle/sdk-contracts.js +1 -1
  41. package/dist/cli-bundle/sdk-core.js +28 -31
  42. package/dist/cli-bundle/sdk-governance.js +1 -1
  43. package/dist/cli-bundle/sdk-graph.js +1 -1
  44. package/dist/cli-bundle/sdk-merge.js +43 -36
  45. package/dist/cli-bundle/sdk-query.js +1 -1
  46. package/dist/cli-bundle/sdk-runtime.js +1 -1
  47. package/dist/cli-bundle/sdk-testing.js +1 -1
  48. package/dist/cli-bundle/sdk.js +10 -10
  49. package/dist/core/diagnostics/remediation.js +4 -4
  50. package/dist/core/history/event-classification.d.ts +21 -0
  51. package/dist/core/history/event-classification.js +109 -0
  52. package/dist/core/history/event-index.d.ts +14 -3
  53. package/dist/core/history/event-index.js +543 -88
  54. package/dist/core/history/history.d.ts +37 -1
  55. package/dist/core/history/history.js +320 -71
  56. package/dist/core/history/replay.js +68 -34
  57. package/dist/core/history/workspace-history.js +7 -6
  58. package/dist/core/lock/lock.d.ts +32 -2
  59. package/dist/core/lock/lock.js +161 -20
  60. package/dist/core/output/output.js +31 -7
  61. package/dist/core/shared/author.d.ts +3 -1
  62. package/dist/core/shared/author.js +111 -23
  63. package/dist/core/shared/time.d.ts +2 -0
  64. package/dist/core/shared/time.js +8 -2
  65. package/dist/core/store/item-metadata-query-index.js +5 -5
  66. package/dist/sdk/context/recency.d.ts +9 -0
  67. package/dist/sdk/context/recency.js +34 -0
  68. package/dist/sdk/context/usage-egress.d.ts +9 -0
  69. package/dist/sdk/context/usage-egress.js +30 -0
  70. package/dist/sdk/context-intent-contracts.js +7 -3
  71. package/dist/sdk/context-relevance.d.ts +23 -0
  72. package/dist/sdk/context-relevance.js +94 -23
  73. package/dist/sdk/context-signal-store.d.ts +7 -3
  74. package/dist/sdk/context-signal-store.js +155 -42
  75. package/dist/sdk/context-usage.d.ts +54 -0
  76. package/dist/sdk/context-usage.js +245 -16
  77. package/dist/sdk/environment/agent-environment.d.ts +296 -0
  78. package/dist/sdk/environment/agent-environment.js +467 -0
  79. package/dist/sdk/environment/project-runtime-compatibility.d.ts +19 -1
  80. package/dist/sdk/environment/project-runtime-compatibility.js +118 -21
  81. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
  82. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
  83. package/dist/sdk/governance/health.js +13 -44
  84. package/dist/sdk/governance/merge-receipt-history.d.ts +62 -0
  85. package/dist/sdk/governance/merge-receipt-history.js +207 -0
  86. package/dist/sdk/governance/provenance-health.js +9 -3
  87. package/dist/sdk/history-compact.js +14 -5
  88. package/dist/sdk/history-redact.js +58 -23
  89. package/dist/sdk/history-repair.js +16 -6
  90. package/dist/sdk/index.d.ts +4 -0
  91. package/dist/sdk/index.js +6 -2
  92. package/dist/sdk/init.d.ts +2 -0
  93. package/dist/sdk/init.js +18 -9
  94. package/dist/sdk/merge/driver.d.ts +3 -1
  95. package/dist/sdk/merge/driver.js +9 -9
  96. package/dist/sdk/merge/index.d.ts +1 -1
  97. package/dist/sdk/merge/index.js +3 -3
  98. package/dist/sdk/merge/receipts.d.ts +17 -6
  99. package/dist/sdk/merge/receipts.js +246 -75
  100. package/dist/sdk/merge/reconcile.d.ts +9 -7
  101. package/dist/sdk/merge/reconcile.js +175 -12
  102. package/dist/sdk/merge/three-way.d.ts +22 -2
  103. package/dist/sdk/merge/three-way.js +92 -25
  104. package/dist/sdk/query/context.d.ts +3 -1
  105. package/dist/sdk/query/context.js +21 -9
  106. package/dist/sdk/query/next.js +18 -9
  107. package/dist/sdk/runtime-input.d.ts +2 -0
  108. package/dist/sdk/runtime-input.js +25 -2
  109. package/dist/sdk/runtime-primitives.d.ts +2 -2
  110. package/dist/sdk/runtime-primitives.js +4 -4
  111. package/dist/sdk/runtime.d.ts +1 -0
  112. package/dist/sdk/runtime.js +17 -26
  113. package/dist/types.d.ts +27 -0
  114. package/dist/types.js +2 -2
  115. package/docs/AGENT_ENVIRONMENTS.md +47 -0
  116. package/docs/AGENT_PROVENANCE_ADR.md +17 -2
  117. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +38 -1
  118. package/docs/CONTEXT_RELEVANCE.md +44 -1
  119. package/docs/MERGE_SAFETY.md +119 -23
  120. package/docs/PERFORMANCE.md +6 -3
  121. package/docs/README.md +1 -0
  122. package/docs/READ_OUTPUT_CONTRACTS.md +9 -1
  123. package/docs/SDK.md +11 -8
  124. package/docs/SDK_CONTEXT.md +7 -0
  125. package/docs/SDK_CONTEXT_EVIDENCE_CONTRACTS.md +24 -2
  126. package/docs/SDK_RUNTIME_BOUNDARIES.md +17 -1
  127. package/docs/examples/sdk-agent-environment/README.md +14 -0
  128. package/docs/examples/sdk-agent-environment/package.json +8 -0
  129. package/docs/examples/sdk-agent-environment/run-agent-environment.mjs +154 -0
  130. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +5 -3
  131. package/marketplace.json +2 -2
  132. package/package.json +5 -5
  133. package/packages/pm-beads/package.json +1 -1
  134. package/packages/pm-calendar/package.json +1 -1
  135. package/packages/pm-command-kit/package.json +1 -1
  136. package/packages/pm-digital-twin/package.json +1 -1
  137. package/packages/pm-governance-audit/package.json +1 -1
  138. package/packages/pm-guide-shell/package.json +1 -1
  139. package/packages/pm-kanban/package.json +1 -1
  140. package/packages/pm-lifecycle-hooks/package.json +1 -1
  141. package/packages/pm-linked-test-adapters/package.json +1 -1
  142. package/packages/pm-search-advanced/package.json +1 -1
  143. package/packages/pm-templates/package.json +1 -1
  144. package/packages/pm-todos/package.json +1 -1
  145. package/packages/pm-vcs/package.json +1 -1
  146. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  147. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  148. package/sdk/public-surface.json +773 -46
  149. package/dist/cli-bundle/chunks/chunk-GOACULJW.js +0 -13
  150. package/dist/cli-bundle/chunks/chunk-NOPL37X4.js +0 -205
  151. package/dist/cli-bundle/chunks/chunk-UDW64J2W.js +0 -8
  152. package/dist/cli-bundle/chunks/chunk-ZLJIFSOE.js +0 -35
  153. package/dist/cli-bundle/focused-chunks/chunk-242AXYB2.js +0 -2
  154. package/dist/cli-bundle/focused-chunks/chunk-2FEZ5SKM.js +0 -3
  155. package/dist/cli-bundle/focused-chunks/chunk-6GCRSLPG.js +0 -2
  156. package/dist/cli-bundle/focused-chunks/chunk-7VATS5QY.js +0 -16
  157. package/dist/cli-bundle/focused-chunks/chunk-JEFKLWMM.js +0 -2
  158. package/dist/cli-bundle/focused-chunks/chunk-MKHG3T76.js +0 -20
  159. package/dist/cli-bundle/focused-chunks/chunk-O67VDLOT.js +0 -51
  160. package/dist/cli-bundle/focused-chunks/chunk-PF3E6Q36.js +0 -8
  161. package/dist/cli-bundle/focused-chunks/chunk-QDFJIRKN.js +0 -4
  162. package/dist/cli-bundle/focused-chunks/chunk-RMRCQPWU.js +0 -2
  163. package/dist/cli-bundle/focused-chunks/chunk-S4U5CN5Q.js +0 -2
  164. package/dist/cli-bundle/focused-chunks/chunk-T2LXXSOD.js +0 -158
  165. package/dist/cli-bundle/focused-chunks/chunk-Z2USIBR2.js +0 -5
@@ -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:
@@ -12,7 +12,7 @@ Every measured CLI and SDK operation targets:
12
12
  - default output at or below 5,000 estimated tokens;
13
13
  - no feature, flag, output, history, or validation loss.
14
14
 
15
- The committed regression budgets in [`scripts/bench/scale-budgets.json`](../scripts/bench/scale-budgets.json) protect the current baseline while the product targets stay fixed. Short local checks use the best observed latency as a regression floor; statistically meaningful runs of 20 or more use p95. Both receive 25% baseline headroom plus a 25 ms scheduler/filesystem noise margin. Reports always retain min/p50/p95, and product-target status always uses p95. This lets a busy workstation detect deterministic code slowdowns without pretending that three samples produce a meaningful p95 or hiding the real tail-latency target.
15
+ The committed regression budgets in [`scripts/bench/scale-budgets.json`](../scripts/bench/scale-budgets.json) protect the current baseline while the product targets stay fixed. Baseline refreshes use the Node major pinned by release and primary CI workflows (currently Node 24); newer supported runtimes remain compatibility targets, but their startup and memory characteristics must not silently rewrite the release baseline. Short local checks use the best observed latency as a regression floor; statistically meaningful runs of 20 or more use p95. Both receive 25% baseline headroom plus a 25 ms scheduler/filesystem noise margin. Reports always retain min/p50/p95, and product-target status always uses p95. This lets a busy workstation detect deterministic code slowdowns without pretending that three samples produce a meaningful p95 or hiding the real tail-latency target.
16
16
 
17
17
  ## Reproducible fixtures
18
18
 
@@ -92,7 +92,10 @@ probe off and performs no query on the create path; advisory/strict modes reuse
92
92
  one dependency-light SDK scorer with the package-owned dedupe audit. Mutation
93
93
  history events use a separate rebuildable ordered SQLite projection so
94
94
  `pm events --since <cursor>` catch-up cost follows new history rows instead of
95
- workspace size. See [SDK Context Coordination](SDK_CONTEXT_COORDINATION.md).
95
+ workspace size. Its v5 schema also indexes the declared substantive-versus-
96
+ maintenance event class, allowing context recency to fetch only the latest
97
+ substantive row per requested stream instead of folding complete histories on
98
+ each read. See [SDK Context Coordination](SDK_CONTEXT_COORDINATION.md).
96
99
 
97
100
  SDK hosts that commit authoritative item documents outside the stock mutation
98
101
  commands use `acquireItemMetadataDerivedIndexLock` and
@@ -127,7 +130,7 @@ To refresh a baseline after an intentional, measured improvement:
127
130
  pnpm benchmark:scale --items ci --iterations 5 --transport both --update --headroom 1.25
128
131
  ```
129
132
 
130
- Review the report and budget diff together. Never update a budget merely to silence a regression.
133
+ Review the report and budget diff together. Before a refresh, compare the delivery head with its exact base commit using the same runtime, fixture shape, and transport set; retain that evidence on the owning PM item. Never update a budget merely to silence a regression.
131
134
 
132
135
  ## Startup and observability
133
136
 
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
  # 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-oahhyc](../.agents/pm/issues/pm-oahhyc.toon), [pm-q4isdq](../.agents/pm/issues/pm-q4isdq.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).
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-wv47pf](../.agents/pm/issues/pm-wv47pf.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-oahhyc](../.agents/pm/issues/pm-oahhyc.toon), [pm-q4isdq](../.agents/pm/issues/pm-q4isdq.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
 
@@ -153,6 +153,14 @@ pm contracts --full --json
153
153
 
154
154
  Every projected result carries a `read_output` receipt with the requested dimensions, precedence, observed option provenance, deterministic estimated token count, string/row compaction signals, and budget outcome. When canonical controls are present, `canonical_options_used` records spellings such as `--output-include`; the optional field is omitted when no canonical control was supplied so minimum-budget session receipts remain compact. `legacy_aliases_used` and `migration_hints` record only compatibility flags the caller actually supplied. A command-local flag synthesized internally to execute a canonical projection mode is therefore never misreported as deprecated syntax. When both spellings are supplied, both provenance arrays report that mixed invocation. Budget degradation discovers nested arrays as well as declared result rows, so validation diagnostics and other governance payloads compact their inner findings before the useful result is omitted. `compacted_row_paths` names every reduced collection without redefining those nested arrays as ordinary pagination rows.
155
155
 
156
+ For `context` and `next`, that final projection is also the usage-feedback
157
+ delivery boundary. The SDK carries a JSON-invisible serve receipt through
158
+ intent and universal output projection, then appends the final omitted decision
159
+ and exact emitted item ids. An infeasible output budget records zero delivered
160
+ rows; it can never leave the packer's earlier inclusions marked as served.
161
+ `PmClient` finalizes the receipt before resolving, while the CLI finalizes it
162
+ from the exact active result passed to telemetry and after-command hooks.
163
+
156
164
  When rows are dropped to satisfy a ceiling, the result also carries `output_budget_truncation`, naming the binding budget and its source, any explicitly requested dimension the budget overrode, every compacted collection path, and executable CLI/SDK/MCP recovery options — a default ceiling can override an explicit `--output-limit unbounded`, and that override is reported rather than silent. If a producer supplied an opaque item-page cursor, compaction rebases it to the last row actually returned and reports `continuation_cursor_rebased: true`; following the cursor therefore cannot skip rows removed from the middle of a producer page. If no useful content can fit, `PmReadOutputBudgetExceeded` provides a discriminated omission result, a compact `{ outputBudget: "unbounded" }` recovery object, and `omitted_result_estimated_tokens`, the last useful-result estimate before omission; use `isReadOutputBudgetExceeded` before accessing result-specific fields. Universal controls are rejected on mutation commands and on the mutation mode of hybrid commands such as `comments`, `notes`, `files`, and `docs`.
157
165
 
158
166
  Cursor recovery carries the opaque value once in `recovery.cursor` and declares
package/docs/SDK.md CHANGED
@@ -1773,14 +1773,17 @@ For persistent derived signals, use `ContextSignalStore` with a caller-owned
1773
1773
  `ContextSignalStoreAdapter`, or use `JsonFileContextSignalStoreAdapter` for a
1774
1774
  same-directory atomic JSON snapshot. Each snapshot carries both a
1775
1775
  `format_version` and `signal_set_version`, the authoritative history or index
1776
- `source_cursor`, the stable caller clock, and whether its items came from the
1777
- `derived_index` or `scan_fallback` path. Item rows are deterministic and sorted;
1778
- the snapshot never replaces item or history data.
1779
-
1780
- `readOrRebuild(items, options)` reuses a snapshot only when the cursor and
1781
- complete item-id set match. Missing, stale, version-incompatible, or corrupt
1782
- state is rebuilt from the authoritative items and atomically replaced. The
1783
- result reports `cache_status` and non-fatal `context_signal_store_stale`,
1776
+ `source_cursor`, a deterministic `recency_evidence_fingerprint`, the stable
1777
+ caller clock, and whether its items came from the `derived_index` or
1778
+ `scan_fallback` path. Item rows are deterministic and sorted; the snapshot never
1779
+ replaces item or history data.
1780
+
1781
+ `readOrRebuild(items, options)` reuses a snapshot only when its format and
1782
+ signal-set metadata are supported, its item source matches, and its cursor,
1783
+ complete item-id set, and substantive recency-evidence fingerprint match.
1784
+ Missing, stale, version-incompatible, or corrupt state is rebuilt from the
1785
+ authoritative items and atomically replaced. The result reports `cache_status`
1786
+ and non-fatal `context_signal_store_stale`,
1784
1787
  `context_signal_store_invalid`, or `context_signal_store_write_failed`
1785
1788
  warnings. A write failure still serves the in-memory rebuilt candidates because
1786
1789
  the snapshot is derived, never authoritative. Optional maps for activity density,
@@ -31,6 +31,13 @@ stale, or unwritable snapshots return a stable warning, its meaning, an
31
31
  executable recovery command, and the expected effect. Re-running `pm context`
32
32
  confirms a successful rebuild as fresh.
33
33
 
34
+ Recency uses the public `classifyHistoryEvent()` contract and the most recent
35
+ substantive immutable event, with release-cohort and `created_at` fallbacks.
36
+ Explained ranking carries the selected coordinate, operation, and class.
37
+ `recordContextUsageServing()` plus `recordContextUsageDelivery()` expose the
38
+ same two-phase feedback boundary used by CLI and `PmClient`, so custom hosts can
39
+ correlate propensity rows with the exact result delivered after output budgets.
40
+
34
41
  See [Context relevance and packing](CONTEXT_RELEVANCE.md) for signal and token
35
42
  budgets, and [context coordination](SDK_CONTEXT_COORDINATION.md) for cursored
36
43
  events and duplicate governance.
@@ -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
+ }
@@ -0,0 +1,154 @@
1
+ import { mkdtemp, rm } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import {
5
+ PM_EPISODE_SCHEMA,
6
+ PM_OBSERVATION_SCHEMA,
7
+ PM_VERDICT_SCHEMA,
8
+ PM_WORKSPACE_RECIPE_SCHEMA,
9
+ PmClient,
10
+ defineEpisodeSpecification,
11
+ openPmEpisode,
12
+ runWithWorkspaceRecipe,
13
+ } from "@unbrained/pm-cli/sdk";
14
+
15
+ class PublicSdkAdapter {
16
+ constructor(workspace) {
17
+ this.client = new PmClient({ cwd: workspace, noExtensions: true });
18
+ this.itemId = "";
19
+ this.revision = 0;
20
+ }
21
+
22
+ async reset(recipe) {
23
+ const created = await runWithWorkspaceRecipe(recipe, async () => {
24
+ await this.client.init("environment");
25
+ return this.client.create({
26
+ id: "pm-created-by-adapter",
27
+ title: "Complete the SDK environment task",
28
+ type: "Task",
29
+ status: "open",
30
+ description: "Created inside a deterministic public-SDK episode.",
31
+ });
32
+ });
33
+ this.itemId = created.item.id;
34
+ this.revision = 0;
35
+ return { workspace_id: "temporary-pm-workspace", state_id: "revision:0" };
36
+ }
37
+
38
+ async execute(_action) {
39
+ const result = await this.client.close(
40
+ this.itemId,
41
+ "Public SDK episode completed",
42
+ {
43
+ resolution: "The ordinary PmClient close action recorded completion.",
44
+ expected: "The task is closed through the public SDK.",
45
+ actual: "The task is closed through the public SDK.",
46
+ validateClose: "warn",
47
+ },
48
+ );
49
+ this.revision += 1;
50
+ return { state_id: `revision:${this.revision}`, output: result };
51
+ }
52
+
53
+ async readRecordedState() {
54
+ const result = await this.client.get(this.itemId);
55
+ return {
56
+ snapshot_id: `revision:${this.revision}`,
57
+ state: {
58
+ item: {
59
+ id: result.item.id,
60
+ title: result.item.title,
61
+ status: result.item.status,
62
+ resolution: result.item.resolution,
63
+ },
64
+ },
65
+ };
66
+ }
67
+ }
68
+
69
+ const observation = {
70
+ schema: PM_OBSERVATION_SCHEMA,
71
+ id: "sdk-task-state",
72
+ version: 1,
73
+ reads: [{ command: "get", budget_tokens: 256 }],
74
+ calibration: {
75
+ basis: "emitted_bytes",
76
+ samples: [96, 128, 160],
77
+ expected_emitted_bytes: 128,
78
+ tolerance_bytes: 32,
79
+ },
80
+ corpus_dependence: { kind: "independent" },
81
+ tiers: [
82
+ {
83
+ id: "standard",
84
+ max_tokens: 256,
85
+ fields: ["item.id", "item.title", "item.status", "item.resolution"],
86
+ },
87
+ { id: "identity", max_tokens: 48, fields: ["item.id", "item.status"] },
88
+ ],
89
+ };
90
+
91
+ const verdict = {
92
+ schema: PM_VERDICT_SCHEMA,
93
+ id: "sdk-task-closed",
94
+ version: 1,
95
+ predicates: [
96
+ {
97
+ id: "closed",
98
+ kind: "field_equals",
99
+ path: "item.status",
100
+ expected: "closed",
101
+ },
102
+ { id: "explained", kind: "field_present", path: "item.resolution" },
103
+ ],
104
+ composition: { operator: "all", predicate_ids: ["closed", "explained"] },
105
+ };
106
+
107
+ const workspace = await mkdtemp(join(tmpdir(), "pm-sdk-environment-"));
108
+ try {
109
+ const session = await openPmEpisode(
110
+ defineEpisodeSpecification({
111
+ schema: PM_EPISODE_SCHEMA,
112
+ id: "public-sdk-environment",
113
+ version: 1,
114
+ mode: "evaluation",
115
+ recipe: {
116
+ schema: PM_WORKSPACE_RECIPE_SCHEMA,
117
+ seed: "public-sdk-environment",
118
+ clock: "2026-09-03T00:00:00.000Z",
119
+ tickMs: 1,
120
+ operations: [],
121
+ },
122
+ task_item_ids: ["pm-created-by-adapter"],
123
+ observable_fields: [
124
+ "item.id",
125
+ "item.title",
126
+ "item.status",
127
+ "item.resolution",
128
+ ],
129
+ withheld_fields: ["grading.expected_status"],
130
+ observation,
131
+ verdict,
132
+ limits: {
133
+ max_actions: 1,
134
+ max_observations: 2,
135
+ max_tokens_per_observation: 256,
136
+ },
137
+ }),
138
+ new PublicSdkAdapter(workspace),
139
+ );
140
+ const initial = await session.observe();
141
+ await session.step({ kind: "close" });
142
+ const completed = await session.close();
143
+ process.stdout.write(
144
+ `${JSON.stringify({
145
+ initial_status: initial.status,
146
+ initial_tier: initial.receipt.served_tier,
147
+ verdict: completed.verdict.outcome,
148
+ policy: completed.verdict.policy,
149
+ trajectory: completed.trajectory.map((entry) => entry.kind),
150
+ })}\n`,
151
+ );
152
+ } finally {
153
+ await rm(workspace, { recursive: true, force: true });
154
+ }
@@ -4,12 +4,12 @@ Tracker: `pm-f05lsg`.
4
4
 
5
5
  Every catalog code is listed. An `uncovered` row is an explicit closure obligation, never an omission or implied approval.
6
6
 
7
- - Catalog error codes: 355
7
+ - Catalog error codes: 357
8
8
  - Executable error codes: 19
9
9
  - Executable-code ratchet floor: 18
10
10
  - Required executable canonical codes: `bulk_ids_input_empty`, `bulk_ids_input_missing_path`, `bulk_ids_input_unreadable`, `invalid_argument_value`, `manifest_unknown_key`, `missing_lifecycle_target`, `missing_required_argument`, `no_version_bounds_declared`, `projection_options_mutually_exclusive`, `tracker_not_initialized`, `tracker_root_missing`, `tracker_root_not_directory`, `tracker_root_unreadable`, `unknown_context_intent`, `unknown_field_projection`, `unknown_option`, `unknown_subcommand`
11
- - Uncovered error codes: 336
12
- - Coverage fraction: 0.053521
11
+ - Uncovered error codes: 338
12
+ - Coverage fraction: 0.053221
13
13
  - Closed-domain probes: 19
14
14
  - Grammar probes: 94
15
15
 
@@ -120,6 +120,7 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
120
120
  | `history_merge_conflict_markers_detected` | `merge_conflict_markers_detected` | uncovered | none | 0 |
121
121
  | `history_stream_over_compact_threshold` | `history_stream_over_compact_threshold` | uncovered | none | 0 |
122
122
  | `history_target_out_of_range` | `history_target_out_of_range` | uncovered | none | 0 |
123
+ | `history_timestamp_invalid` | `history_timestamp_invalid` | uncovered | none | 0 |
123
124
  | `history_unknown_author_events` | `history_unknown_author_events` | uncovered | none | 0 |
124
125
  | `host_environment_capacity_fault` | `host_environment_capacity_fault` | uncovered | none | 0 |
125
126
  | `host_environment_operation_invalid` | `host_environment_operation_invalid` | uncovered | none | 0 |
@@ -232,6 +233,7 @@ Every catalog code is listed. An `uncovered` row is an explicit closure obligati
232
233
  | `profile_name_not_normalized` | `profile_name_not_normalized` | uncovered | none | 0 |
233
234
  | `profile_summary_empty` | `profile_summary_empty` | uncovered | none | 0 |
234
235
  | `profile_title_empty` | `profile_title_empty` | uncovered | none | 0 |
236
+ | `project_runtime_history_epoch_incompatible` | `project_runtime_history_epoch_incompatible` | uncovered | none | 0 |
235
237
  | `project_runtime_stale_mutation` | `project_runtime_stale_mutation` | uncovered | none | 0 |
236
238
  | `project_runtime_stale_read` | `project_runtime_stale_read` | uncovered | none | 0 |
237
239
  | `projection_options_mutually_exclusive` | `projection_options_mutually_exclusive` | executable | closed_domain | 3 |