@unbrained/pm-cli 2026.8.15 → 2026.8.17

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 (176) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +56 -12
  3. package/README.md +13 -13
  4. package/dist/cli/error-guidance.d.ts +5 -0
  5. package/dist/cli/error-guidance.js +15 -2
  6. package/dist/cli/public.d.ts +2 -0
  7. package/dist/cli/public.js +21 -0
  8. package/dist/cli/register-history-author.js +16 -11
  9. package/dist/cli/register-mutation.js +4 -4
  10. package/dist/cli-bundle/bundle-manifest.json +143 -143
  11. package/dist/cli-bundle/chunks/{chunk-J42EGKDK.js → chunk-2QLOXC3V.js} +2 -2
  12. package/dist/cli-bundle/chunks/{chunk-LJHOAVGI.js → chunk-3UEGXBMR.js} +49 -43
  13. package/dist/cli-bundle/chunks/chunk-4JPYF536.js +35 -0
  14. package/dist/cli-bundle/chunks/chunk-6VDLG2FC.js +13 -0
  15. package/dist/cli-bundle/chunks/chunk-7IBRGCHX.js +2 -0
  16. package/dist/cli-bundle/chunks/chunk-HBJAS566.js +8 -0
  17. package/dist/cli-bundle/chunks/chunk-ION3E43Q.js +197 -0
  18. package/dist/cli-bundle/chunks/{chunk-WLPDLNEZ.js → chunk-JOKATURE.js} +4 -4
  19. package/dist/cli-bundle/chunks/{chunk-MEM2ZS3O.js → chunk-TPXZIBIV.js} +5 -5
  20. package/dist/cli-bundle/chunks/chunk-YM2YAMF7.js +2 -0
  21. package/dist/cli-bundle/chunks/{register-list-query-CT3LFDDN.js → register-list-query-Q7KII4G5.js} +2 -2
  22. package/dist/cli-bundle/chunks/{register-mutation-NWEVA5YS.js → register-mutation-4WBRPXLV.js} +3 -3
  23. package/dist/cli-bundle/chunks/{register-operations-AHIAG5KM.js → register-operations-SSENDH5B.js} +2 -2
  24. package/dist/cli-bundle/chunks/{register-setup-ZJZFVAKE.js → register-setup-DOSFBGKE.js} +2 -2
  25. package/dist/cli-bundle/focused-chunks/{chunk-WTSER4WJ.js → chunk-267MUUS6.js} +11 -11
  26. package/dist/cli-bundle/focused-chunks/chunk-2NNFLLNG.js +2 -0
  27. package/dist/cli-bundle/focused-chunks/chunk-2QSAKMIH.js +2 -0
  28. package/dist/cli-bundle/focused-chunks/{chunk-ZMFXQ7VF.js → chunk-ATEY76SX.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/chunk-BUCG4ZI2.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/{chunk-M67F5AIN.js → chunk-CYFK5UPB.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/chunk-EHXIKD6K.js +2 -0
  32. package/dist/cli-bundle/focused-chunks/{chunk-EXZA4257.js → chunk-KGEXTMPG.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-KP2VQQVQ.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/chunk-MHPIL773.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-POEEAD2V.js +4 -0
  36. package/dist/cli-bundle/focused-chunks/{chunk-ITAUHSO6.js → chunk-SALH6B6K.js} +47 -47
  37. package/dist/cli-bundle/focused-chunks/{chunk-KLVUMNXJ.js → chunk-SYZENPIT.js} +3 -3
  38. package/dist/cli-bundle/focused-chunks/{chunk-KTKH4IMG.js → chunk-XKAMP5OU.js} +2 -2
  39. package/dist/cli-bundle/focused-chunks/{chunk-NSPYTG6G.js → chunk-XPIC53VA.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/{chunk-6XKF3PGV.js → chunk-ZQPGZZWQ.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/chunk-ZT2DJS27.js +155 -0
  42. package/dist/cli-bundle/main.js +10 -10
  43. package/dist/cli-bundle/sdk-authoring.js +1 -1
  44. package/dist/cli-bundle/sdk-contracts.js +1 -1
  45. package/dist/cli-bundle/sdk-core.js +31 -31
  46. package/dist/cli-bundle/sdk-governance.js +1 -1
  47. package/dist/cli-bundle/sdk-graph.js +1 -1
  48. package/dist/cli-bundle/sdk-merge.js +32 -32
  49. package/dist/cli-bundle/sdk-query.js +1 -1
  50. package/dist/cli-bundle/sdk-runtime.js +1 -1
  51. package/dist/cli-bundle/sdk-testing.js +1 -1
  52. package/dist/cli-bundle/sdk.js +4 -2
  53. package/dist/core/extensions/loader.js +10 -6
  54. package/dist/core/extensions/manifest-schema.d.ts +20 -0
  55. package/dist/core/extensions/manifest-schema.js +52 -0
  56. package/dist/core/history/replay.js +32 -14
  57. package/dist/core/history/workspace-history.js +32 -10
  58. package/dist/core/output/output.js +6 -3
  59. package/dist/core/schema/fields-file.d.ts +1 -1
  60. package/dist/core/schema/fields-file.js +2 -2
  61. package/dist/core/schema/runtime-field-values.js +115 -9
  62. package/dist/core/schema/runtime-schema.d.ts +3 -1
  63. package/dist/core/schema/runtime-schema.js +124 -3
  64. package/dist/core/shared/errors.d.ts +12 -0
  65. package/dist/core/shared/errors.js +2 -2
  66. package/dist/core/shared/time.d.ts +2 -0
  67. package/dist/core/shared/time.js +27 -2
  68. package/dist/core/store/item-store.js +28 -2
  69. package/dist/sdk/agent/refusal-reachability.d.ts +56 -8
  70. package/dist/sdk/agent/refusal-reachability.js +414 -4
  71. package/dist/sdk/author-attribution.d.ts +56 -11
  72. package/dist/sdk/author-attribution.js +174 -50
  73. package/dist/sdk/cli-contracts/flag-contracts.js +5 -2
  74. package/dist/sdk/cli-contracts/tool-parameter-tables.js +12 -4
  75. package/dist/sdk/cli-contracts/tool-schema.js +12 -4
  76. package/dist/sdk/completion.js +11 -4
  77. package/dist/sdk/compose.d.ts +6 -2
  78. package/dist/sdk/compose.js +33 -3
  79. package/dist/sdk/context-intent-contracts.d.ts +8 -4
  80. package/dist/sdk/context-intent-contracts.js +76 -31
  81. package/dist/sdk/dependency-flag-validation.d.ts +9 -2
  82. package/dist/sdk/dependency-flag-validation.js +101 -35
  83. package/dist/sdk/environment/host-environment-errors.js +25 -7
  84. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +62 -14
  85. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
  86. package/dist/sdk/governance/assurance-action.d.ts +3 -7
  87. package/dist/sdk/governance/assurance-action.js +97 -2
  88. package/dist/sdk/governance/boundary-fixtures.d.ts +86 -0
  89. package/dist/sdk/governance/boundary-fixtures.js +201 -0
  90. package/dist/sdk/governance/coverage-assurance.d.ts +24 -0
  91. package/dist/sdk/governance/coverage-assurance.js +61 -0
  92. package/dist/sdk/governance/defect-recurrence-signals.d.ts +10 -0
  93. package/dist/sdk/governance/defect-recurrence-signals.js +25 -0
  94. package/dist/sdk/governance/defect-recurrence.d.ts +242 -0
  95. package/dist/sdk/governance/defect-recurrence.js +523 -0
  96. package/dist/sdk/governance/extension-host-version.js +20 -9
  97. package/dist/sdk/governance.d.ts +2 -0
  98. package/dist/sdk/governance.js +4 -2
  99. package/dist/sdk/graph/governance.js +3 -2
  100. package/dist/sdk/guide-topics.js +191 -2
  101. package/dist/sdk/index.d.ts +5 -1
  102. package/dist/sdk/index.js +6 -3
  103. package/dist/sdk/lifecycle/create.js +4 -2
  104. package/dist/sdk/lifecycle/update-many.js +15 -2
  105. package/dist/sdk/lifecycle/update.js +5 -2
  106. package/dist/sdk/linked-artifacts.js +63 -14
  107. package/dist/sdk/query/get.d.ts +2 -0
  108. package/dist/sdk/query/get.js +32 -7
  109. package/dist/sdk/read-output-contracts.js +5 -3
  110. package/dist/sdk/relationship-analytics.js +90 -14
  111. package/dist/sdk/relationship-kinds/contract.d.ts +4 -0
  112. package/dist/sdk/relationship-kinds/contract.js +3 -2
  113. package/dist/sdk/relationships.d.ts +1 -1
  114. package/dist/sdk/relationships.js +11 -2
  115. package/dist/sdk/runtime.d.ts +2 -5
  116. package/dist/sdk/runtime.js +3 -2
  117. package/dist/sdk/schema.d.ts +1 -0
  118. package/dist/sdk/schema.js +2 -2
  119. package/dist/sdk/test/execution.d.ts +6 -2
  120. package/dist/sdk/test/execution.js +39 -13
  121. package/dist/types.d.ts +29 -2
  122. package/dist/types.js +4 -2
  123. package/docs/CONFIGURATION.md +58 -1
  124. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +58 -0
  125. package/docs/DEFECT_RECURRENCE.md +134 -0
  126. package/docs/DEPENDENCY_KIND_CONTRACT.md +12 -2
  127. package/docs/README.md +2 -0
  128. package/docs/READ_OUTPUT_CONTRACTS.md +7 -1
  129. package/docs/RELATIONSHIP_GRAPH.md +16 -2
  130. package/docs/RELEASING.md +13 -7
  131. package/docs/SDK.md +38 -5
  132. package/docs/SDK_CONTEXT_INTEGRITY.md +33 -5
  133. package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +13 -5
  134. package/docs/SDK_RUNTIME_BOUNDARIES.md +9 -1
  135. package/docs/TESTING.md +18 -1
  136. package/docs/TRUSTWORTHY_CONTEXT_EVIDENCE.md +1 -1
  137. package/marketplace.json +2 -2
  138. package/package.json +6 -4
  139. package/packages/pm-beads/package.json +1 -1
  140. package/packages/pm-calendar/package.json +1 -1
  141. package/packages/pm-command-kit/package.json +1 -1
  142. package/packages/pm-digital-twin/package.json +1 -1
  143. package/packages/pm-governance-audit/package.json +1 -1
  144. package/packages/pm-guide-shell/package.json +1 -1
  145. package/packages/pm-kanban/package.json +1 -1
  146. package/packages/pm-lifecycle-hooks/package.json +1 -1
  147. package/packages/pm-linked-test-adapters/package.json +1 -1
  148. package/packages/pm-search-advanced/package.json +1 -1
  149. package/packages/pm-templates/package.json +1 -1
  150. package/packages/pm-todos/package.json +1 -1
  151. package/packages/pm-vcs/package.json +1 -1
  152. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  153. package/plugins/pm-claude/skills/pm-audit/SKILL.md +26 -0
  154. package/plugins/pm-claude/skills/pm-developer/SKILL.md +26 -0
  155. package/plugins/pm-claude/skills/pm-planner/SKILL.md +26 -0
  156. package/plugins/pm-claude/skills/pm-release/SKILL.md +26 -0
  157. package/plugins/pm-claude/skills/pm-workflow/SKILL.md +26 -0
  158. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  159. package/plugins/pm-codex/skills/pm-auditor/SKILL.md +26 -0
  160. package/plugins/pm-codex/skills/pm-native/SKILL.md +26 -0
  161. package/plugins/pm-codex/skills/pm-release/SKILL.md +26 -0
  162. package/sdk/public-surface.json +716 -33
  163. package/dist/cli-bundle/chunks/chunk-24GAV7XL.js +0 -8
  164. package/dist/cli-bundle/chunks/chunk-AIM6VT2N.js +0 -13
  165. package/dist/cli-bundle/chunks/chunk-DSWDLTDR.js +0 -197
  166. package/dist/cli-bundle/chunks/chunk-KIEGUBYQ.js +0 -2
  167. package/dist/cli-bundle/chunks/chunk-KLKYLSDX.js +0 -2
  168. package/dist/cli-bundle/chunks/chunk-QHPCJWEJ.js +0 -35
  169. package/dist/cli-bundle/focused-chunks/chunk-4X57RE4U.js +0 -2
  170. package/dist/cli-bundle/focused-chunks/chunk-7NJ4QYQ2.js +0 -2
  171. package/dist/cli-bundle/focused-chunks/chunk-KT5XMYSX.js +0 -4
  172. package/dist/cli-bundle/focused-chunks/chunk-OKA6ELTL.js +0 -2
  173. package/dist/cli-bundle/focused-chunks/chunk-PUISBOPP.js +0 -2
  174. package/dist/cli-bundle/focused-chunks/chunk-QLNMCESQ.js +0 -155
  175. package/dist/cli-bundle/focused-chunks/chunk-SLKC6QLJ.js +0 -2
  176. package/dist/cli-bundle/focused-chunks/chunk-U65UC4G3.js +0 -2
@@ -0,0 +1,58 @@
1
+ # Context Integrity Contracts
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).
4
+
5
+ ## Agent Quick Context
6
+
7
+ Project management is context management. A successful read or analysis must not silently erase an item's identity, reinterpret a reference, reverse a relationship, accept an ignored compatibility spelling, or rewrite history into a format an older supported CLI cannot read. These rules are implemented in shared SDK/core primitives so the CLI, packages, extensions, and MCP hosts inherit the same behavior.
8
+
9
+ ## Sparse Read Identity
10
+
11
+ `pm get <id> --fields ...` always returns `item.id`, even when `id` was not explicitly requested. Explicitly requested collection metadata is materialized as an empty array when absent. This distinguishes “the requested collection is empty” from “the field was not read” without forcing callers to request a larger projection.
12
+
13
+ ```bash
14
+ pm get pm-example --fields comments,notes,learnings,tests,test_runs,docs,plan_steps,plan_decisions,plan_discoveries,plan_validation --json
15
+ ```
16
+
17
+ The result retains the canonical ID and every requested empty group, including planning and test-run collections. The public `GetResult` type requires `item.id`, so SDK consumers do not need an impossible missing-identity branch. Unrequested groups remain omitted, preserving the token-saving projection contract.
18
+
19
+ ## Extension Manifest Compatibility
20
+
21
+ Extension manifests use the canonical top-level `pm_min_version` and optional `pm_max_version` fields. `compatibility.pm`, `engines.pm`, or other alternate spellings do not establish the loader's pm version floor.
22
+
23
+ `checkExtensionManifestCompatibility` now performs a closed top-level schema inspection before evaluating bounds. It reports deterministic advisory findings for unknown keys and independently reports when both canonical bounds are absent, including for an otherwise recognized manifest. A recognized `compatibility` spelling includes `suggested_key: "pm_min_version"`. Runtime discovery emits matching `extension_manifest_*` warnings, which means `pm extension doctor` cannot silently report a clean manifest after discarding an unknown compatibility block or after receiving no compatibility intent at all.
24
+
25
+ Warnings are advisory; malformed or unmet canonical bounds retain their existing blocking behavior.
26
+
27
+ ## Lossless Remote Documentation Links
28
+
29
+ `pm docs <id> --add` accepts structured `path=...,scope=...,note=...` values, bare paths, Markdown links, and CSV label/URL pairs:
30
+
31
+ ```bash
32
+ pm docs pm-example --add '[Pull request](https://github.com/org/repo/pull/42)'
33
+ pm docs pm-example --add 'Issue report,https://github.com/org/repo/issues/17'
34
+ pm docs pm-example --add 'Query evidence,https://example.com/report?fields=id,status'
35
+ pm docs pm-example --add '[Nested path](https://example.com/report_(final))'
36
+ ```
37
+
38
+ Each example creates one project-scoped documentation reference. The first comma separates a CSV label from the complete URL remainder, and balanced parentheses inside Markdown destinations remain part of the destination. The URL is preserved byte-for-byte as the path and the label becomes the note. File-link parsing is unchanged, and ordinary comma-separated bare document paths continue to expand as before.
39
+
40
+ ## Direction-Locked Graph Impact
41
+
42
+ Dependency storage is oriented from the item that declares a relationship (`source`) to the referenced item (`target`). Impact analysis uses that stored orientation even for associative kinds:
43
+
44
+ - `incoming` follows source items that point at the current target: dependents and requesters.
45
+ - `outgoing` follows targets referenced by the current source: prerequisites and context dependencies.
46
+ - `both` is the deterministic union of the complete incoming and outgoing traversals. Each branch keeps its starting direction; traversal never reverses through an associative edge halfway through a path.
47
+
48
+ This prevents a shared `related` item from bridging an incoming impact query into an unrelated epic. Rows retain shortest explanation paths, bounded pagination, truncation, and query-cost receipts.
49
+
50
+ ## Cross-Version History Epochs
51
+
52
+ History writers using item-hash epoch 2 always emit `item_hash_version: 2`. An entry without an explicit epoch is therefore legacy epoch 1 when the entire stream is implicit, including documents whose hashes happen to be identical under both algorithms. A supported explicit epoch becomes authoritative from its marker forward, so earlier unversioned entries retain both legacy and transitional candidates while a trailing ambiguous hash cannot downgrade the marked epoch. Verification and repair no longer guess a different epoch from the last ambiguous entry.
53
+
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
+
56
+ ## Verification Boundary
57
+
58
+ 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.
@@ -0,0 +1,134 @@
1
+ # Defect Recurrence and Boundary Evidence
2
+
3
+ Tracked by [pm-1qkivy](../.agents/pm/features/pm-1qkivy.toon), [pm-rtn5h6](../.agents/pm/tasks/pm-rtn5h6.toon), [pm-0pzgit](../.agents/pm/tasks/pm-0pzgit.toon), and [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon).
4
+
5
+ ## Agent Quick Context
6
+
7
+ `pm` treats project management as context management. A resolved defect is therefore not only a closed item: it is durable context that should select the checks most likely to prevent the same failure from recurring.
8
+
9
+ The public SDK now provides three composable contracts:
10
+
11
+ - a captured-boundary registry that rejects self-generated fixtures, unsafe samples, missing samples, and expired waivers;
12
+ - a defect-evidence ratchet that requires a typed escape class plus a gate improvement or reviewed, expiring waiver on new terminal defects;
13
+ - a versioned recurrence index that maps proposed files, packages, PM items, tags, and error codes to shared local and hosted checks.
14
+
15
+ The CLI and MCP use the same SDK action path. Repository policy can be replaced by a package or workspace policy without changing the analyzer.
16
+
17
+ ## Public SDK
18
+
19
+ Import the governance surface from the package root or the narrow governance entrypoint:
20
+
21
+ ```ts
22
+ import {
23
+ analyzeDefectChangeRisk,
24
+ buildDefectRecurrenceIndex,
25
+ evaluateBoundaryFixtures,
26
+ evaluateDefectGateEvidence,
27
+ parseDefectRecurrencePolicy,
28
+ type DefectChangeRiskInput,
29
+ type DefectRecurrencePolicy,
30
+ } from "@unbrained/pm-cli/sdk/governance";
31
+
32
+ const policy: DefectRecurrencePolicy =
33
+ parseDefectRecurrencePolicy(serializedPolicy);
34
+ const index = buildDefectRecurrenceIndex(policy, pmItems, {
35
+ previous_index: previousIndex,
36
+ changed_item_ids: changedItemIds,
37
+ });
38
+ const change: DefectChangeRiskInput = {
39
+ files: ["src/sdk/governance/assurance-action.ts"],
40
+ item_ids: ["pm-1qkivy"],
41
+ };
42
+ const report = analyzeDefectChangeRisk(index, change, { limit: 25 });
43
+ ```
44
+
45
+ The index and report are deterministic. `policy_fingerprint` identifies the versioned policy; `index_fingerprint` also covers the sparse PM item-to-family contributions. Continuation cursors bind to the latter, so a cursor cannot silently continue against changed context.
46
+
47
+ Each report explains its exact matching signals, returns deduplicated local and hosted checks, and includes a small cost receipt. Package authors may keep their own recurrence policy and feed the same SDK from a custom command, extension, CI adapter, or application.
48
+
49
+ ## CLI and MCP Action
50
+
51
+ `assurance risk` accepts one JSON request through the same `definition` transport already used by SDK and MCP hosts:
52
+
53
+ ```bash
54
+ risk_request=$(jq -cn \
55
+ --slurpfile policy config/defect-recurrence-policy.json \
56
+ '{policy:$policy[0],change:{files:["src/sdk/governance/assurance-action.ts"],item_ids:["pm-1qkivy"]},limit:25}')
57
+ pm assurance risk --definition "$risk_request" --json
58
+ ```
59
+
60
+ The result uses `items` as its bounded row collection and publishes `.items[]` as the stable selector. When `next_cursor` is present, submit it in the next request. A stale or malformed cursor fails rather than restarting from an ambiguous offset.
61
+
62
+ Use `pm assurance risk` for an operator or agent decision. Use the pure SDK functions when a package already owns the item projection, wants to preserve an incremental index, or needs to combine risk with another domain model.
63
+
64
+ ### TypeScript compatibility
65
+
66
+ The exported `ASSURANCE_ACTIONS` tuple and `AssuranceActionResult` union now include `risk` and `DefectChangeRiskReport`. This is additive at runtime, but TypeScript consumers with an exhaustive action or result switch must add the new branch. The SDK surface snapshot records that source-compatibility change explicitly.
67
+
68
+ ## Policy Model
69
+
70
+ The repository example is [config/defect-recurrence-policy.json](../config/defect-recurrence-policy.json). Every family declares:
71
+
72
+ - a stable id, monotonic version, title, and accountable PM item;
73
+ - one of `production_defect`, `nightly_regression`, `scanner_finding`, or `review_caught_late`;
74
+ - file, package, item, tag, or error-code triggers;
75
+ - local and hosted checks selected from the same policy;
76
+ - a negative-control change that must select the family;
77
+ - historical PM items that justify the family;
78
+ - maximum escape-rate and false-positive-rate budgets.
79
+
80
+ Repository policy validation rejects duplicate ids, absent historical examples, missing family negative controls, invalid taxonomy values, and budgets outside zero through one. Deterministic sorting makes the serialized policy merge-friendly.
81
+
82
+ ## Defect Evidence on PM Items
83
+
84
+ Projects can register the structured fields without changing the SDK:
85
+
86
+ ```bash
87
+ pm schema add-field escape_class \
88
+ --type string \
89
+ --commands create,update,list,search,context \
90
+ --description "Defect escape taxonomy"
91
+ pm schema add-field gate_evidence \
92
+ --type object \
93
+ --commands create,update,list,search,context \
94
+ --description "Gate improvement or explicit waiver evidence"
95
+ ```
96
+
97
+ `gate_evidence` accepts one of these dispositions:
98
+
99
+ - `gate_added` and `gate_strengthened` require `gate_id`, a runnable `negative_control`, non-empty `local_checks` and `hosted_checks`, and an accountable `owner`;
100
+ - `explicit_waiver` requires an accountable `owner`, a concrete `waiver_reason`, and a future `waiver_expires_at` timestamp.
101
+
102
+ The evidence epoch lets an adopting project ratchet new closures immediately while backfilling historical items deliberately. A valid `completed_at` is authoritative, `closed_at` is the compatibility fallback, and timestamp-less items created after the epoch fail closed; timestamp-less items created before the epoch remain explicitly grandfathered. Reports keep historical escape-class and disposition counts visible even before those older items become closure blockers.
103
+
104
+ ## Captured Boundary Fixtures
105
+
106
+ The repository inventory is [config/boundary-fixtures.json](../config/boundary-fixtures.json). Each externally produced or consumed value must carry either:
107
+
108
+ - a committed JSON sample with `capture_source` set to `captured_redacted` or `captured_verbatim`, capture provenance, explicit redactions, input, and observed output; or
109
+ - an explicit reason, owner, and future expiry for a boundary that cannot yet be captured safely.
110
+
111
+ The evaluator rejects a `self_generated` source because a fixture created by the same implementation cannot reveal disagreement with an external format. It also scans committed JSON for common home-directory, package-token, GitHub-token, and private-key patterns.
112
+
113
+ The Claude Code directory-slug fixture is consumed directly by the author-provenance test. The npm, GitHub Actions, Git commit, and Sentry samples preserve real field shapes while replacing identifiers, paths, URLs, and user data.
114
+
115
+ ## Repository Gate
116
+
117
+ Run the complete local gate after building:
118
+
119
+ ```bash
120
+ pnpm quality:defect-evidence
121
+ node scripts/release/defect-evidence-gate.mjs --negative-control --json
122
+ ```
123
+
124
+ The first command must pass. The negative control must exit `1` after replacing a captured sample with a forbidden source and adding a terminal defect without evidence. Focused provider modes are available as `--boundary-only`, `--evidence-only`, and `--policy-only`.
125
+
126
+ `repository-defect-evidence-required` is part of the blocking `repository-static-quality` assurance composition. That makes local and CI behavior share the same provider result, assertion negative control, enforcement, and immutable verdict semantics.
127
+
128
+ ## Recovery Producer Census
129
+
130
+ `censusPmRecoveryReferenceProducers` scans complete source files for static object-literal recovery fields. It ignores type literals, destructuring patterns, labels, comments, strings, templates, and regular expressions. Aliases such as `candidate_commands`, nested `fallback_candidates[].command`, `next_best_command`, `retry_command`, and `suggested_next_steps` normalize to the same six public recovery kinds used by executable reachability verification.
131
+
132
+ The census fails when a kind has no producer or when a recovery-like envelope field lacks a typed contract. The integration gate scans every `src/**/*.ts` producer; the existing real-entrypoint corpus then executes or resolves every normalized kind and proves recovery, replacement, or behavior-preserving semantics.
133
+
134
+ This separation is intentional: the producer census prevents silent omissions as source grows, while entrypoint execution proves that a reference is not merely syntactically present.
@@ -1,6 +1,6 @@
1
1
  # Dependency-kind contract
2
2
 
3
- Tracker: [pm-4020c5](../.agents/pm/issues/pm-4020c5.toon), [pm-jkbqt8](../.agents/pm/issues/pm-jkbqt8.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon)
3
+ Tracker: [pm-4020c5](../.agents/pm/issues/pm-4020c5.toon), [pm-jkbqt8](../.agents/pm/issues/pm-jkbqt8.toon), [pm-q6n8sj](../.agents/pm/issues/pm-q6n8sj.toon), [pm-ouyq3n](../.agents/pm/issues/pm-ouyq3n.toon)
4
4
 
5
5
  Dependency rows have one canonical stored spelling per relationship meaning. Command inputs remain compatibility-friendly: hyphens normalize to underscores and the aliases below are accepted, but `pm create` and `pm update` persist the canonical kind. Existing historical rows are never rewritten implicitly.
6
6
 
@@ -15,6 +15,16 @@ Dependency rows have one canonical stored spelling per relationship meaning. Com
15
15
 
16
16
  The SDK relationship registry is authoritative. `canonicalizeRelationshipKind()` rejects unknown spellings, while `resolveCanonicalRelationshipKind()` supports validation flows that need an undefined result. `pm contracts` publishes `relationship_kind_contracts` with canonical names, aliases, inverses, and ordering/hierarchy semantics.
17
17
 
18
+ `recurs_from` has no alias: a later occurrence points to an earlier occurrence.
19
+ It is persistent after both items become terminal and carries temporal identity,
20
+ not execution precedence. `supersedes` keeps replacement semantics, while
21
+ `duplicate_of` remains item-level record identity rather than an edge between
22
+ distinct events. Local create, update, and update-many mutations compare the
23
+ endpoint `created_at` values before persistence and reject equal or reverse
24
+ chronology with `dependency_temporal_order_invalid`; explicit cross-workspace
25
+ references remain external because their target metadata is not locally
26
+ available.
27
+
18
28
  ## Direction and actionability
19
29
 
20
30
  `blocked_by` and `blocks` are inverse storage directions with identical scheduling meaning:
@@ -26,6 +36,6 @@ Readiness, `pm next`, context blocker summaries, `pm list-blocked`, downstream `
26
36
 
27
37
  ## Legacy observability
28
38
 
29
- `pm deps` returns `legacy_alias_counts` for the workspace. `pm graph audit` returns the same field beside canonical `profile.edges_by_kind` counts, `profile.edge_share_by_kind` composition ratios, and the `semantic_edges`/`semantic_edge_share` context-preservation census. The semantic census counts `discovered_from`, `incident_from`, `supersedes`, and `verifies` over all deduplicated directed edges. Empty objects and zero shares are explicit, not omitted. These diagnostics are read-only; terminal history remains untouched until an explicitly governed migration is requested.
39
+ `pm deps` returns `legacy_alias_counts` for the workspace. `pm graph audit` returns the same field beside canonical `profile.edges_by_kind` counts, `profile.edge_share_by_kind` composition ratios, and the `semantic_edges`/`semantic_edge_share` context-preservation census. The semantic census counts `discovered_from`, `incident_from`, `recurs_from`, `supersedes`, and `verifies` over all deduplicated directed edges. Empty objects and zero shares are explicit, not omitted. These diagnostics are read-only; terminal history remains untouched until an explicitly governed migration is requested.
30
40
 
31
41
  Assurance `dependency_kind` measurements canonicalize both the declaration and stored row before comparing. A declaration using `related` and one using the accepted `related_to` alias therefore measure the same edge population; alias debt remains separately observable through `legacy_alias_counts`.
package/docs/README.md CHANGED
@@ -54,7 +54,9 @@ pm guide release --json
54
54
  - [SDK Agent Session and Episode Context](SDK_AGENT_SESSION_CONTEXT.md) - inherited role/topic context, cross-process episode identity, and deterministic history grouping.
55
55
  - [Improvement Ledger and History Analytics](IMPROVEMENT_ANALYTICS.md) - audited quantitative observations, live provenance coverage, and bounded observational fleet outcomes.
56
56
  - [Project Assurance Primitives](ASSURANCE.md) - SDK-owned measurements, assertions, lifecycle gates, cost receipts, and durable verdict history shared by CLI and MCP.
57
+ - [Defect Recurrence and Boundary Evidence](DEFECT_RECURRENCE.md) - captured external samples, structured defect-escape evidence, incremental change-risk indexing, and executable recovery-producer census.
57
58
  - [Trustworthy Context and Evidence Contracts](TRUSTWORTHY_CONTEXT_EVIDENCE.md) - full-record assurance, graph composition, boolean health rows, lossless linked-test removal, and role-labelled recovery.
59
+ - [Context Integrity Contracts](CONTEXT_INTEGRITY_CONTRACTS.md) - sparse-read identity, closed extension manifests, lossless remote docs, direction-locked graph impact, and cross-version history epochs.
58
60
  - [SDK Evidence Traceability and Integrity](SDK_EVIDENCE_TRACEABILITY.md) - reverse source-to-item lookup, atomic evidence replacement, no-op history, linked-test collision classification, and telemetry drain receipts.
59
61
  - [SDK Context and Evidence Contracts](SDK_CONTEXT_EVIDENCE_CONTRACTS.md) - material omission receipts, scoped preflight activation, truthful merge preference, claim-race classification, and versioned history hashes.
60
62
  - [Reproducible Workspaces and Snapshots](REPRODUCIBLE_WORKSPACES.md) - deterministic SDK recipes and content-addressed authoritative tracker restore points.
@@ -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-sb0tns](../.agents/pm/issues/pm-sb0tns.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-eugaqy](../.agents/pm/issues/pm-eugaqy.toon), [pm-jt8aa2](../.agents/pm/issues/pm-jt8aa2.toon), [pm-kyjdne](../.agents/pm/issues/pm-kyjdne.toon), [pm-8nev0o](../.agents/pm/issues/pm-8nev0o.toon), [pm-e5gl05](../.agents/pm/issues/pm-e5gl05.toon), and [pm-cha95z](../.agents/pm/tasks/pm-cha95z.toon).
3
+ Tracker references: [pm-hb7ug8](../.agents/pm/features/pm-hb7ug8.toon), [pm-cxr0jb](../.agents/pm/features/pm-cxr0jb.toon), [pm-hid9g1](../.agents/pm/features/pm-hid9g1.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-5t33or](../.agents/pm/features/pm-5t33or.toon), [pm-sb0tns](../.agents/pm/issues/pm-sb0tns.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-eugaqy](../.agents/pm/issues/pm-eugaqy.toon), [pm-jt8aa2](../.agents/pm/issues/pm-jt8aa2.toon), [pm-kyjdne](../.agents/pm/issues/pm-kyjdne.toon), [pm-8nev0o](../.agents/pm/issues/pm-8nev0o.toon), [pm-e5gl05](../.agents/pm/issues/pm-e5gl05.toon), [pm-cha95z](../.agents/pm/tasks/pm-cha95z.toon), and [pm-2qvq7a](../.agents/pm/issues/pm-2qvq7a.toon).
4
4
 
5
5
  ## Agent Quick Context
6
6
 
@@ -122,6 +122,12 @@ list-family `--no-truncate` imply an unbounded cost dimension when the caller
122
122
  does not supply `--output-budget`; they cannot silently return a budget-trimmed
123
123
  subset while claiming to return every matched row. An explicit canonical
124
124
  budget still has precedence and may request a bounded result deliberately.
125
+ The same SDK-native rule applies to every declared complete-result spelling,
126
+ including `contracts --full`: explicit completeness defeats only the implicit
127
+ default ceiling. If an explicit caller budget cannot retain any useful domain
128
+ result, the CLI still prints the parseable omission receipt but exits 2; a
129
+ consumer therefore cannot interpret the missing command or action arrays as a
130
+ successful empty contract.
125
131
 
126
132
  ```bash
127
133
  pm list-open --output-include id,title,status --output-limit 10
@@ -1,6 +1,6 @@
1
1
  # Relationship graph semantics
2
2
 
3
- Tracked by [pm-4jqm](../.agents/pm/decisions/pm-4jqm.toon), [pm-dwj33e](../.agents/pm/decisions/pm-dwj33e.toon), [pm-ju83](../.agents/pm/features/pm-ju83.toon), [pm-8xr8](../.agents/pm/stories/pm-8xr8.toon), [pm-m2il](../.agents/pm/chores/pm-m2il.toon), [pm-jiusod](../.agents/pm/issues/pm-jiusod.toon), [pm-mfvsng](../.agents/pm/issues/pm-mfvsng.toon), [pm-9gzr4r](../.agents/pm/issues/pm-9gzr4r.toon), and [pm-xvt7ps](../.agents/pm/issues/pm-xvt7ps.toon).
3
+ Tracked by [pm-4jqm](../.agents/pm/decisions/pm-4jqm.toon), [pm-dwj33e](../.agents/pm/decisions/pm-dwj33e.toon), [pm-ju83](../.agents/pm/features/pm-ju83.toon), [pm-8xr8](../.agents/pm/stories/pm-8xr8.toon), [pm-m2il](../.agents/pm/chores/pm-m2il.toon), [pm-jiusod](../.agents/pm/issues/pm-jiusod.toon), [pm-mfvsng](../.agents/pm/issues/pm-mfvsng.toon), [pm-9gzr4r](../.agents/pm/issues/pm-9gzr4r.toon), [pm-xvt7ps](../.agents/pm/issues/pm-xvt7ps.toon), and [pm-ouyq3n](../.agents/pm/issues/pm-ouyq3n.toon).
4
4
 
5
5
  ## Decision
6
6
 
@@ -10,7 +10,21 @@ The alternatives were rejected as follows: a closed enum cannot model applicatio
10
10
 
11
11
  ## Contract
12
12
 
13
- Each relationship kind declares direction, inverse, ordering and hierarchy participation, incoming and outgoing cardinality, lifecycle, aliases, payload schema, self-edge policy, and compatibility version. Built-ins normalize legacy `related_to`, `depends_on`, `child_of`, `parent_child`, `epic`, and `task` spellings. Unknown custom kinds remain importable only after their definitions are registered, preventing algorithms from guessing their meaning.
13
+ Each relationship kind declares direction, inverse, ordering and hierarchy participation, optional temporal order, incoming and outgoing cardinality, lifecycle, aliases, payload schema, self-edge policy, and compatibility version. Built-ins normalize legacy `related_to`, `depends_on`, `child_of`, `parent_child`, `epic`, and `task` spellings. Unknown custom kinds remain importable only after their definitions are registered, preventing algorithms from guessing their meaning.
14
+
15
+ `recurs_from` is the canonical recurrence relation: `new --recurs_from--> old`
16
+ means the source is a later event with the same observable failure identity as
17
+ the target. Its `temporalOrder: "source_after_target"` states chronology without
18
+ making recurrence an execution-order dependency. The edge is directed,
19
+ many-to-many, and `persistent`, so it remains valid after either endpoint closes.
20
+ Local mutation adapters enforce that contract against both endpoint
21
+ `created_at` values before writing the item or immutable history; equal and
22
+ reverse timestamps are rejected, including update-many dry runs.
23
+ It does not replace the older event (`supersedes`) and does not assert that two
24
+ records describe one event (`duplicate_of`). Traverse recurrence families with
25
+ `direction: "both"`; impact, paths, dominators, centrality, cut structure, and
26
+ community detection then operate on the connected family without special-case
27
+ labels or retyping historical replacement edges.
14
28
 
15
29
  Ordering-cycle validation considers only kinds whose registry definition sets `ordering: true`. Associative and provenance edges never block execution. Hierarchy cycles remain a separate structural check. Canonical edge identity includes kind and ordered endpoints for directed edges, or sorted endpoints for undirected edges.
16
30
 
package/docs/RELEASING.md CHANGED
@@ -25,7 +25,9 @@ Tracked documentation work: [pm-u9d0](../.agents/pm/epics/pm-u9d0.toon),
25
25
  classification [pm-dqtzva](../.agents/pm/issues/pm-dqtzva.toon).
26
26
  The local/hosted gate selection contract is tracked by
27
27
  [pm-ei6x66](../.agents/pm/tasks/pm-ei6x66.toon). Release-candidate analyzer
28
- provenance is tracked by [pm-u1baah](../.agents/pm/issues/pm-u1baah.toon).
28
+ provenance is tracked by [pm-u1baah](../.agents/pm/issues/pm-u1baah.toon), and
29
+ authoritative blocker-recovery run selection by
30
+ [pm-db8onn](../.agents/pm/issues/pm-db8onn.toon).
29
31
 
30
32
  ## Version Policy
31
33
 
@@ -76,9 +78,10 @@ Policy:
76
78
  created, a non-`github-actions[bot]` closure of the exact bot-created
77
79
  `Auto Release blocked` issue on the same UTC day triggers one preparation
78
80
  retry
79
- - if today's tag already exists, blocker closure reruns and watches the exact
80
- tag-driven Release workflow instead of invoking release preparation or
81
- creating an ordinal replacement; an already-successful run is recorded as
81
+ - if today's tag already exists, blocker closure bypasses release-preparation
82
+ provenance, dependency installation, and build work, then selects immutable
83
+ Release evidence across both tag-push and guarded workflow-dispatch runs; a
84
+ completed success is authoritative over stale failures and is recorded as
82
85
  recovered without republishing
83
86
  - release preparation must pass all quality and compatibility gates before commit+tag push
84
87
  - before dependency installation or build, auto-release verifies that the
@@ -92,9 +95,12 @@ Policy:
92
95
  - when scheduled failures continue across multiple UTC days, auto-release supersedes a stale open blocker with a fresh current-day blocker so same-day retry detection follows the latest scheduled failure
93
96
  - closing the exact bot-created `Auto Release blocked: scheduled run failed`
94
97
  issue as a maintainer or agent records a same-day retry marker, then either
95
- retries preparation when no tag exists or reruns the exact existing tag's
96
- Release workflow; it comments with the recovered tag on success and reopens
97
- the same issue on failure. A second close on the same UTC day is refused
98
+ retries preparation when no tag exists or watches an active exact-tag Release
99
+ workflow. If only failed or missing evidence exists, it dispatches the
100
+ reviewed current `release.yml` from `main` with the immutable tag input; it
101
+ never reruns historical workflow code. It comments with the recovered tag on
102
+ success and reopens the same issue on failure. A second close on the same UTC
103
+ day is refused
98
104
  before release mutation and reported as `retry_already_attempted`, and
99
105
  workflow cleanup closures by `github-actions[bot]` are ignored.
100
106
  - after a scheduled run publishes a tag and the downstream release workflow succeeds, auto-release closes any open `Auto Release blocked` issue so the GitHub tracker reflects current release health
package/docs/SDK.md CHANGED
@@ -42,6 +42,11 @@ semantic command discovery, and append-stable linked tests are tracked by
42
42
  [pm-st7wgu](../.agents/pm/issues/pm-st7wgu.toon),
43
43
  [pm-g543](../.agents/pm/issues/pm-g543.toon), and
44
44
  [pm-x2vx](../.agents/pm/issues/pm-x2vx.toon).
45
+ The supported CLI entrypoint boundary, truthful context-intent receipts, and
46
+ first-class recurrence relationships are tracked by
47
+ [pm-rf120g](../.agents/pm/tasks/pm-rf120g.toon),
48
+ [pm-3crymx](../.agents/pm/issues/pm-3crymx.toon), and
49
+ [pm-ouyq3n](../.agents/pm/issues/pm-ouyq3n.toon).
45
50
 
46
51
  Use it for extension authoring, package authoring, command/action contract discovery, and deterministic app or CI automation. Do not import private `src/core/...` modules from external integrations or packages.
47
52
 
@@ -90,8 +95,14 @@ barrel remains source-compatible:
90
95
  | `@unbrained/pm-cli/sdk/public-surface.json` | Published machine-readable SDK compatibility snapshot |
91
96
  | `@unbrained/pm-cli/sdk` | Compatibility aggregate containing every supported SDK export |
92
97
 
93
- `@unbrained/pm-cli/cli` remains the runtime CLI module entrypoint for package
94
- resolution, not a typed library API. The committed
98
+ `@unbrained/pm-cli/cli` is the supported embeddable CLI entrypoint and exports
99
+ only `runPmCli`. Repository tests import their internal seams from source; those
100
+ helpers are not package API. The surface snapshot records the subpath under the
101
+ `executable_entry` classification, so any future exposure is a classified
102
+ surface change. The bare
103
+ `@unbrained/pm-cli` root export is recorded as an `aggregate_alias` of
104
+ `@unbrained/pm-cli/sdk`: its symbols are not duplicated, but a retarget of its
105
+ declaration path is a snapshot change. The committed
95
106
  [entrypoint import-cost table](performance/sdk-entrypoint-import-costs.md)
96
107
  records fresh-process latency, RSS, and reduction versus the aggregate barrel.
97
108
  Every narrow entrypoint is bundled and type-tested independently.
@@ -137,6 +148,12 @@ from every non-testing SDK subpath must be available from
137
148
  Consumers and release tooling can read the exact shipped artifact from
138
149
  `@unbrained/pm-cli/sdk/public-surface.json` without locating repository files.
139
150
 
151
+ The denominator is the package export map itself, not a list inside the
152
+ generator. Every `exports` entry that declares a `types` path must carry a
153
+ classification, and `pnpm sdk:surface:check` refuses to run while any published
154
+ code export is unclassified — so adding a public entrypoint cannot ship it
155
+ ungoverned.
156
+
140
157
  ## Public Exports
141
158
 
142
159
  Source of truth:
@@ -301,6 +318,7 @@ Command/action contract exports:
301
318
  - Actionability primitives: `collectBlockedByIds`, `resolveItemBlockers`, `collectDependencyBlockedIds`, and `computeActionabilityReport` expose the same edge-aware blocked/ready definition used by `pm next`, `pm context`, and `pm list-blocked`. Embedded schedulers can therefore classify custom lifecycle schemas without importing CLI or core modules.
302
319
  - Dependency-governance primitives: `collectDanglingDependencyReferences`, `collectMissingDependencyTargetIds`, and `assembleWorkspaceRelationshipGraph` normalize hierarchy, scalar blockers, and structured dependencies into one graph while partitioning missing targets into actionable active holders, informational terminal-history holders, and the legacy `no-active-blocker` sentinel without mutating stored history.
303
320
  - Relationship graph primitives: `RelationshipKindRegistry`, `createRelationshipKindRegistry`, `assertRelationshipEdgeAllowed`, `RelationshipGraph`, `RelationshipEventLog`, `RelationshipEventStore`, `planRelationshipEventBackfill`, `buildRelationshipContext`, `buildDepsRelationshipContext`, `hierarchyAncestors`, `hierarchyDescendants`, `orderingPredecessors`, `orderingSuccessors`, `enumerateRelationshipPaths`, `auditWorkspaceRelationshipGraph`, `isOrderingRelationshipKind`, and `dependencyToRelationship` provide application-defined edge semantics, durable replay, deterministic legacy migration, bounded semantic traversal, policy-aware governance, and explainable context queries. Mutation adapters should call `assertRelationshipEdgeAllowed` with the active registry before persistence; it resolves aliases and honors custom `allowSelf` definitions while built-in self edges fail before item or history writes. `RelationshipEventLog.stream/project` and their durable-store equivalents page immutable prefixes and fold them into deterministic application state with exact version, processed-count, and as-of metadata. `RelationshipEventStore.appendBatch` validates a complete import under one cross-process lock and atomically publishes it; `skip_identical` resume mode rejects same-id semantic collisions. `RelationshipGraphAdapter`, `createRelationshipGraphSnapshot`, `syncRelationshipGraphAdapter`, `loadRelationshipGraphAdapter`, and `federateRelationshipGraphSnapshots` form the backend-neutral content-addressed projection boundary for database or remote graph packages. `MemoryRelationshipGraphAdapter`, `assertRelationshipGraphAdapterConformance`, and `createRelationshipGraphScaleFixture` give package authors a reference implementation, reusable compatibility contract, and lazy deterministic fixtures through one million nodes. See [Relationship graph semantics](RELATIONSHIP_GRAPH.md).
321
+ - Built-in `recurs_from` records that the source is a later occurrence of the target. Its registry contract is directed, `source_after_target`, non-ordering, many-to-many, and persistent across terminal lifecycle states. Local mutation paths enforce strictly later source `created_at` metadata before item or history persistence and return structured source/target evidence when chronology is equal, reversed, or unverifiable. It therefore connects an incident family for traversal and analytics without reclassifying `supersedes` replacements or `duplicate_of` identity collapse.
304
322
  - Atomic application transactions: `commitWorkspaceTransaction` coordinates ordered, idempotent item and relationship mutations under one workspace writer lock and a durable replay journal. Interrupted work resumes from step inspection; ordinary failures append reverse-order compensations without rewriting immutable histories.
305
323
  - Multi-branch merge primitives: `mergeItemDocuments`, `mergeHistoryStreams`, `mergeRelationshipEventStreams`, `mergeJsonDocuments`, `runMergeDriver`, `runMergeInstall`, and `runMergeReconcile` provide the same field-aware item, hash-chain-preserving history, sequence-renumbering relationship-event, key-level configuration, and audited post-merge repair-and-verify semantics as `pm merge`; `installMergeFence` and `findGitWorkspaceRoot` let custom init hosts install the same contract with explicit roots, while `buildMergeAttributePatterns`, `refreshMergeAttributeFenceIfInstalled`, and `auditMergeAttributeFence` expose fence coverage, refresh, and validation. See [Multi-Branch Merge Safety](MERGE_SAFETY.md).
306
324
  - Dependency provenance primitives: `EXTERNAL_DEPENDENCY_SOURCE_KIND`, `EXTERNAL_DEPENDENCY_SOURCE_KIND_ALIAS`, `isExternalDependencySourceKind`, and `normalizeDependencySeedId` let custom importers preserve cross-workspace dependency ids explicitly while retaining local prefix normalization for ordinary seeds. `source_kind: "external"` is the human-facing alias and persists canonically as `global`; a `blocked_by` row with that provenance is a real external predecessor, so graph governance does not require a fabricated local item or misreport `stale_lifecycle_block`. Newly created dependency rows also carry the effective `author`, `author_source` (`asserted` or `detected`), and a mutation `source_kind`; legacy rows remain readable without invented provenance. Tracked by [pm-6sc8jq](../.agents/pm/issues/pm-6sc8jq.toon).
@@ -348,9 +366,10 @@ rendering stay at the edge.
348
366
  Embedded hosts can also import the SDK-owned bootstrap normalization primitives
349
367
  (`normalizeBootstrapInvocation`, `parseBootstrapGlobalOptions`, and related
350
368
  contracts) when they intentionally expose pm-compatible argv. Every
351
- `runPmCli()` call constructs a fresh Commander graph, so extension commands,
352
- extension flags, and runtime schema options from one workspace cannot leak into
353
- the next in-process invocation.
369
+ `runPmCli()` call constructs a fresh Commander graph and restores the host's
370
+ existing `process.exitCode` after both successful and failed invocations, so
371
+ extension state and CLI exit state from one workspace cannot leak into the next
372
+ in-process invocation.
354
373
 
355
374
  ### Build a non-PM temporal domain
356
375
 
@@ -653,6 +672,20 @@ representative medium-workspace answers use the live
653
672
  negative control: the gate fails unless that deliberately unsafe request
654
673
  exceeds the default contract.
655
674
 
675
+ Named read intents additionally return `context_intent`. The receipt separates
676
+ the declaration (`declared_token_budget`) from the effective ceiling
677
+ (`token_budget`) and reports their signed `token_budget_override`. Row-oriented
678
+ reads clamp an explicit limit to the budget-derived ceiling and identify the
679
+ binding constraint. `declaration_feasible` evaluates the useful projection
680
+ against the declared ceiling independently of whether a lower or higher caller
681
+ override is effective. `within_budget` evaluates that same projection against
682
+ the effective `token_budget`, so it can legitimately differ from declaration
683
+ feasibility. If even compacted useful output cannot fit,
684
+ `result_omitted` is true, `estimated_tokens` retains the measured pre-omission
685
+ size (and is therefore greater than `token_budget`), and
686
+ `budget_exceeded.restore_with` is an executable bounded retry rather than a
687
+ generic suggestion.
688
+
656
689
  Unfiltered `pm contracts` now selects the summary projection by default. It
657
690
  returns canonical commands, terse intents, the most useful flags for the core
658
691
  agent loop, per-command ceilings, and the shared output policy. Use
@@ -1,6 +1,6 @@
1
1
  # SDK Context Integrity
2
2
 
3
- Tracker: [pm-0k19l7](../.agents/pm/issues/pm-0k19l7.toon), [pm-9stazf](../.agents/pm/issues/pm-9stazf.toon), [pm-tu71](../.agents/pm/issues/pm-tu71.toon), [pm-0xmajx](../.agents/pm/issues/pm-0xmajx.toon), [pm-7rrqsk](../.agents/pm/issues/pm-7rrqsk.toon), [pm-ety1qc](../.agents/pm/issues/pm-ety1qc.toon), [pm-lu6sca](../.agents/pm/features/pm-lu6sca.toon), [pm-5y05kq](../.agents/pm/issues/pm-5y05kq.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-h97qxd](../.agents/pm/issues/pm-h97qxd.toon), [pm-h06944](../.agents/pm/issues/pm-h06944.toon), [pm-5t33or](../.agents/pm/features/pm-5t33or.toon), [pm-in23qu](../.agents/pm/issues/pm-in23qu.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-okgxwa](../.agents/pm/issues/pm-okgxwa.toon), [pm-22rzjp](../.agents/pm/issues/pm-22rzjp.toon), [pm-76fkpp](../.agents/pm/issues/pm-76fkpp.toon), [pm-igdvfq](../.agents/pm/issues/pm-igdvfq.toon), [pm-643e0k](../.agents/pm/issues/pm-643e0k.toon), and [pm-larv4r](../.agents/pm/issues/pm-larv4r.toon).
3
+ Tracker: [pm-0k19l7](../.agents/pm/issues/pm-0k19l7.toon), [pm-9stazf](../.agents/pm/issues/pm-9stazf.toon), [pm-tu71](../.agents/pm/issues/pm-tu71.toon), [pm-0xmajx](../.agents/pm/issues/pm-0xmajx.toon), [pm-7rrqsk](../.agents/pm/issues/pm-7rrqsk.toon), [pm-ety1qc](../.agents/pm/issues/pm-ety1qc.toon), [pm-lu6sca](../.agents/pm/features/pm-lu6sca.toon), [pm-5y05kq](../.agents/pm/issues/pm-5y05kq.toon), [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon), [pm-h97qxd](../.agents/pm/issues/pm-h97qxd.toon), [pm-h06944](../.agents/pm/issues/pm-h06944.toon), [pm-5t33or](../.agents/pm/features/pm-5t33or.toon), [pm-in23qu](../.agents/pm/issues/pm-in23qu.toon), [pm-h8tpeh](../.agents/pm/features/pm-h8tpeh.toon), [pm-okgxwa](../.agents/pm/issues/pm-okgxwa.toon), [pm-22rzjp](../.agents/pm/issues/pm-22rzjp.toon), [pm-76fkpp](../.agents/pm/issues/pm-76fkpp.toon), [pm-igdvfq](../.agents/pm/issues/pm-igdvfq.toon), [pm-643e0k](../.agents/pm/issues/pm-643e0k.toon), [pm-larv4r](../.agents/pm/issues/pm-larv4r.toon), [pm-mcxk8v](../.agents/pm/issues/pm-mcxk8v.toon), and [pm-2zkvxm](../.agents/pm/issues/pm-2zkvxm.toon).
4
4
 
5
5
  ## Agent Quick Context
6
6
 
@@ -81,8 +81,13 @@ text. `verifyPmRecoveryReferences` accepts obligations derived from real error
81
81
  envelopes and observations produced by executing a retry, resolving a declared
82
82
  command path, or linking prose to an already executed recovery. Its report
83
83
  includes the total obligation set, pass fraction, sorted findings, and stable
84
- coverage buckets for `suggested_retry`, `candidate_command`, `example`, and
85
- `next_step`, including zero-population buckets.
84
+ coverage buckets for `suggested_retry`, `candidate_command`, `example`,
85
+ `next_step`, `migration_hint`, and `restore_with`, including zero-population
86
+ buckets. `derivePmRecoveryReferenceObligations` walks emitted envelopes and
87
+ generated read-output contracts, so tests cannot silently omit a producer
88
+ family. Each obligation declares `recovery`, `replacement`, or
89
+ `behavior_preserving` semantics and its proof must demonstrate the same
90
+ promise.
86
91
 
87
92
  The repository integration corpus drives real CLI refusals, executes the
88
93
  emitted retry in a temporary tracker, compares candidate commands with the
@@ -128,17 +133,32 @@ SDK callers use `fullHistory: true`; MCP callers use `full: true`. The default s
128
133
 
129
134
  ## Author acknowledgment coordinates
130
135
 
131
- CLI, SDK, and MCP use the same selector and coordinate parser for `history-author-acknowledge`. A coordinate is `<item-id>:<line>` or `_workspace:<line>`, with a positive one-based line number. Exactly one of explicit events or `all_actionable` is required.
136
+ CLI, SDK, and MCP use the same selector and coordinate parser for `history-author-acknowledge`. A coordinate is `<item-id>:<line>` or `_workspace:<line>`, with a positive one-based line number. Exactly one of explicit events or `all_actionable` is required. Applying is a two-step operation: dry-run returns a deterministic SHA-256 over the complete, ordered coordinate set and every exact source-line hash; apply requires that fingerprint and refuses stale source or selection drift with `CONFLICT` exit 4 before writing history.
132
137
 
133
138
  ```bash
134
139
  pm history-author-acknowledge \
135
140
  --event _workspace:4 \
141
+ --dry-run
142
+
143
+ pm history-author-acknowledge \
144
+ --event _workspace:4 \
145
+ --plan-fingerprint <sha256-from-preview> \
136
146
  --attributed-author import-agent \
137
147
  --reviewer maintainer \
138
148
  --reason "Verified workspace provenance"
139
149
  ```
140
150
 
141
- The SDK exposes `resolveUnknownAuthorAcknowledgmentSelector` and `parseUnknownAuthorHistoryEventCoordinates` so packages never need a private copy of this grammar. Health and validate map actionable unknown-author warnings directly to this append-only acknowledgment command instead of sending callers through another diagnostic loop.
151
+ Preview coordinates are bounded with `--limit`, but the fingerprint and counts always cover the complete selection. Plans distinguish already acknowledged coordinates, and apply reports `effect`, `no_effect` (exit 6), or `partial_effect` (exit 7). Bulk selection appends only newly actionable rows, while explicit coordinates may append a superseding disposition as described below. The SDK exposes `planUnknownAuthorHistoryAcknowledgment`, `resolveUnknownAuthorAcknowledgmentSelector`, and `parseUnknownAuthorHistoryEventCoordinates` so packages never need a private copy of this grammar. Health and validate map actionable unknown-author warnings directly to this append-only acknowledgment command instead of sending callers through another diagnostic loop.
152
+
153
+ An explicit `--event` selection is also the append-only correction path: if a
154
+ coordinate already has a disposition, preview marks it
155
+ `already_acknowledged`, and fingerprint-bound apply appends a later disposition
156
+ that supersedes the earlier attribution. Recover the original coordinates from
157
+ `context.author_acknowledgment.events` in the applicable
158
+ `history/_workspace.jsonl` record, preview those same coordinates, and apply the
159
+ fresh fingerprint with the corrected author and review evidence. By contrast,
160
+ `--all-actionable` intentionally selects only undispositioned rows; an empty
161
+ bulk selection remains `no_effect` and never repeats existing dispositions.
142
162
 
143
163
  ## Health provider boundary
144
164
 
@@ -152,6 +172,14 @@ That agreement check reads only local history and JSON files: mismatched,
152
172
  missing, or unreadable singleton paths become bounded `history_drift` evidence
153
173
  without enabling embeddings, vector-store access, or any other provider I/O.
154
174
 
175
+ Every SDK operation that requires a valid `_workspace` chain refuses the same
176
+ way when verification fails. The typed `workspace_history_chain_invalid`
177
+ conflict includes `verification_errors` in CLI JSON and SDK error context plus
178
+ an executable `pm history _workspace --verify --json` recovery command. This
179
+ keeps deliberate corruption tests and recoverable tracker drift out of the
180
+ unexpected-runtime-error channel without weakening the fail-closed mutation
181
+ boundary.
182
+
155
183
  Brief and summary check-only health projections use the scalar-only metadata
156
184
  reader. Validation uses collection-bearing metadata for evidence and
157
185
  relationship checks and materializes bodies only when strict history-drift
@@ -5,11 +5,11 @@ Tracker references: [pm-23xkss](../.agents/pm/issues/pm-23xkss.toon) and
5
5
 
6
6
  ## Agent Quick Context
7
7
 
8
- An empty tracker, a missing tracker, and an invalid tracker path are different
9
- states. Likewise, an optional local Git optimization and a drifted installed
10
- configuration are different health findings. The SDK preserves these
11
- distinctions so automation does not infer project truth from an ambiguous empty
12
- array or a generic failed verdict.
8
+ An empty tracker, a missing tracker, an invalid tracker path, and an unreadable
9
+ tracker are different states. Likewise, an optional local Git optimization and
10
+ a drifted installed configuration are different health findings. The SDK
11
+ preserves these distinctions so automation does not infer project truth from an
12
+ ambiguous empty array or a generic failed verdict.
13
13
 
14
14
  ## Metadata Root Diagnostics
15
15
 
@@ -24,6 +24,11 @@ A missing root throws `PmCliError` with exit code `NOT_FOUND`, diagnostic code
24
24
  `tracker_root_missing`, and context reason `missing`. A regular file or other
25
25
  non-directory root throws `PmCliError` with exit code `USAGE`, diagnostic code
26
26
  `tracker_root_not_directory`, and context reason `not_a_directory`.
27
+ An existing root that cannot be enumerated throws `PmCliError` with exit code
28
+ `GENERIC_FAILURE`, diagnostic code `tracker_root_unreadable`, and context reason
29
+ `unreadable`. On POSIX hosts, enumeration requires both read and directory-search
30
+ permission: a root whose mode lacks either permission is unreadable, even when a
31
+ privileged process could bypass those mode bits.
27
32
 
28
33
  Consumers should branch on the stable diagnostic code:
29
34
 
@@ -35,6 +40,9 @@ try {
35
40
  if (error instanceof PmCliError && error.code === "tracker_root_missing") {
36
41
  // Ask the caller to select or initialize a tracker.
37
42
  }
43
+ if (error instanceof PmCliError && error.code === "tracker_root_unreadable") {
44
+ // Repair tracker permissions before trusting any project context.
45
+ }
38
46
  }
39
47
  ```
40
48
 
@@ -45,9 +45,17 @@ the stable, path-redacted `host_environment_capacity_fault`,
45
45
  `host_environment_permission_fault`, or `host_environment_resource_fault`
46
46
  contracts. `classifyHostEnvironmentFault` supports diagnostics that need a
47
47
  non-throwing classification, while `translateHostEnvironmentFault` supports an
48
- existing catch boundary. Non-errno failures are returned unchanged and must
48
+ existing catch boundary. The classifier accepts both symbolic Node `code`
49
+ values and declared numeric `errno` values from `node:os.constants.errno`; this
50
+ also recognizes platform errors that Node renders only as a number, such as a
51
+ Linux `-122` quota failure. Non-errno failures are returned unchanged and must
49
52
  not be relabeled as environment faults.
50
53
 
54
+ Linked-test tracker seeding uses this boundary. A required sandbox copy that
55
+ exceeds temporary-filesystem capacity fails with a stable recovery contract,
56
+ while linked tests whose effective context is schema avoid materializing
57
+ tracker data at all.
58
+
51
59
  Existing SDK surfaces can supply category-specific `codes` to preserve their
52
60
  published error vocabulary while still sharing classification, path redaction,
53
61
  and recovery guidance. Workspace snapshots use this compatibility path for
package/docs/TESTING.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This page describes safe local tests, linked tests, coverage, and release-readiness checks.
4
4
 
5
- Tracked implementation updates: [pm-52eh](../.agents/pm/features/pm-52eh.toon), [pm-mcxr](../.agents/pm/issues/pm-mcxr.toon), [pm-u42x](../.agents/pm/issues/pm-u42x.toon), [pm-atfm](../.agents/pm/features/pm-atfm.toon), [pm-xmp5](../.agents/pm/tasks/pm-xmp5.toon), [pm-39cqqx](../.agents/pm/tasks/pm-39cqqx.toon), [pm-5cgm2z](../.agents/pm/chores/pm-5cgm2z.toon), [pm-avv3wx](../.agents/pm/issues/pm-avv3wx.toon), [pm-rizqb6](../.agents/pm/issues/pm-rizqb6.toon).
5
+ Tracked implementation updates: [pm-52eh](../.agents/pm/features/pm-52eh.toon), [pm-mcxr](../.agents/pm/issues/pm-mcxr.toon), [pm-u42x](../.agents/pm/issues/pm-u42x.toon), [pm-atfm](../.agents/pm/features/pm-atfm.toon), [pm-xmp5](../.agents/pm/tasks/pm-xmp5.toon), [pm-39cqqx](../.agents/pm/tasks/pm-39cqqx.toon), [pm-5cgm2z](../.agents/pm/chores/pm-5cgm2z.toon), [pm-avv3wx](../.agents/pm/issues/pm-avv3wx.toon), [pm-rizqb6](../.agents/pm/issues/pm-rizqb6.toon), [pm-95h7pg](../.agents/pm/issues/pm-95h7pg.toon), [pm-giks4s](../.agents/pm/issues/pm-giks4s.toon).
6
6
 
7
7
  ## Agent Quick Context
8
8
 
@@ -353,6 +353,13 @@ The manifest records baseline bytes and estimated tokens for visible review
353
353
  deltas. Updating it cannot raise answer ceilings, which remain owned by
354
354
  `PM_COMMAND_OUTPUT_BUDGET_CONTRACTS`.
355
355
 
356
+ The gate derives every supported harness, model, session, and provenance
357
+ environment key from the SDK-owned harness descriptor registry. It deletes
358
+ those host inputs before each fixture invocation, then supplies only the
359
+ fixture's deterministic author and isolated tracker settings. Unrelated host
360
+ environment values remain available, so the test process stays representative
361
+ without allowing the launching agent or CI harness to change measured output.
362
+
356
363
  ## Linked Tests
357
364
 
358
365
  Add tests to the item that owns the work:
@@ -399,6 +406,16 @@ When a linked command is a PM tracker-read such as `pm validate`, the default mi
399
406
  `--auto-pm-context`, which keeps schema isolation for ordinary commands and routes only tracker-read PM commands
400
407
  through seeded tracker data.
401
408
 
409
+ The runner resolves every selected command's effective context before it
410
+ creates temporary sandboxes. Runs whose effective context is schema initialize
411
+ only their schema roots; a non-PM command explicitly configured with
412
+ `pm_context_mode: "tracker"` still requires tracker data. Tracker roots and item
413
+ data are materialized only when at least one selected command requires tracker
414
+ context. This preserves source isolation without copying an unrelated tracker
415
+ into constrained temporary storage.
416
+ Capacity, permission, and resource failures while seeding a required tracker
417
+ surface as typed, path-redacted host-environment refusals with recovery steps.
418
+
402
419
  Use explicit modes when needed:
403
420
 
404
421
  ```bash
@@ -61,7 +61,7 @@ Each measurement result carries `definition_fingerprint`; assertion verdicts cop
61
61
  }
62
62
  ```
63
63
 
64
- The semantic numerator is the sum of `discovered_from`, `incident_from`, `supersedes`, and `verifies`. Audit baselines preserve the new fields, accept older snapshots with explicit zero defaults, and report signed count/share deltas.
64
+ The semantic numerator is the sum of `discovered_from`, `incident_from`, `recurs_from`, `supersedes`, and `verifies`. Audit baselines preserve the new fields, accept older snapshots with explicit zero defaults, and report signed count/share deltas.
65
65
 
66
66
  ## Health Row Predicate
67
67