@unbrained/pm-cli 2026.9.4 → 2026.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/HARNESS_COMPATIBILITY.md +1 -1
- package/.agents/skills/README.md +2 -2
- package/.agents/skills/pm-developer/SKILL.md +4 -1
- package/.agents/skills/pm-developer/references/COMMAND_PLAYBOOK.md +10 -0
- package/.agents/skills/pm-developer/references/GRAPH_AND_RELATIONSHIPS.md +3 -1
- package/.agents/skills/pm-extensions/SKILL.md +2 -2
- package/.agents/skills/pm-extensions/references/LIFECYCLE.md +3 -3
- package/.agents/skills/pm-extensions/references/TROUBLESHOOTING.md +3 -3
- package/.agents/skills/pm-user/SKILL.md +2 -0
- package/.agents/skills/pm-user/references/BACKLOG_SHAPING.md +5 -0
- package/.agents/skills/pm-user/references/WORKFLOWS.md +20 -5
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +58 -3
- package/dist/cli/commander-usage.d.ts +2 -0
- package/dist/cli/commander-usage.js +15 -12
- package/dist/cli/help-json-payload.js +12 -7
- package/dist/cli/main.js +22 -11
- package/dist/cli/register-list-query.js +4 -2
- package/dist/cli/register-mutation.js +4 -2
- package/dist/cli/register-operations.js +17 -8
- package/dist/cli-bundle/bundle-manifest.json +153 -161
- package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-V72UV7QS.js → chunk-BAX2BYUW.js} +73 -73
- package/dist/cli-bundle/chunks/{chunk-HI6BHPCU.js → chunk-CKOL5U7J.js} +51 -51
- package/dist/cli-bundle/chunks/{chunk-A24WAVE6.js → chunk-JT6XF6GE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-I2AS367G.js → chunk-JX4DH4WC.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YW4QK2G7.js → chunk-NPN5I67J.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +5 -0
- package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +232 -0
- package/dist/cli-bundle/chunks/{chunk-RI4XNOYS.js → chunk-RWWBOWJ5.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +40 -0
- package/dist/cli-bundle/chunks/{chunk-X6CMGV6L.js → chunk-WI2AYPA7.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-Z5YYSJJG.js → register-list-query-5JL52D33.js} +3 -3
- package/dist/cli-bundle/chunks/{register-mutation-ELSP6I4I.js → register-mutation-ZPG7KMVP.js} +4 -4
- package/dist/cli-bundle/chunks/register-operations-I5W3KMGB.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-E2AE72QG.js → register-setup-H4SVAVX7.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-3646BZ4W.js → chunk-3BZEOXLT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-NBMJD6MK.js → chunk-EZR3GHFE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +56 -0
- package/dist/cli-bundle/focused-chunks/{chunk-53IHPICX.js → chunk-LIJIA4TY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-25UJBH4M.js → chunk-M6PBRFSH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-AJR3OP2E.js → chunk-NTPY5GSO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +177 -0
- package/dist/cli-bundle/focused-chunks/{chunk-MHKUIPJW.js → chunk-PEFABF7E.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-6PWPQKDN.js → chunk-QTVCLMSZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-7N2TV7WZ.js → chunk-QTZRBUYA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +10 -0
- package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +2 -0
- package/dist/cli-bundle/main.js +22 -15
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +37 -37
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +42 -39
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +9 -9
- package/dist/core/extensions/extension-types.d.ts +2 -0
- package/dist/core/extensions/extension-types.js +2 -2
- package/dist/core/extensions/module-graph-snapshot.js +5 -4
- package/dist/core/fs/host-environment-errors.d.ts +27 -0
- package/dist/core/fs/host-environment-errors.js +142 -0
- package/dist/core/history/drift-scan.d.ts +5 -0
- package/dist/core/history/drift-scan.js +16 -6
- package/dist/core/history/event-classification.d.ts +1 -1
- package/dist/core/history/event-classification.js +3 -2
- package/dist/core/history/history.js +37 -5
- package/dist/core/history/identity.d.ts +15 -0
- package/dist/core/history/identity.js +31 -0
- package/dist/core/history/projection.js +50 -17
- package/dist/core/history/read.js +6 -3
- package/dist/core/history/replay.d.ts +1 -2
- package/dist/core/history/replay.js +4 -4
- package/dist/core/history/version-address.d.ts +13 -0
- package/dist/core/history/version-address.js +33 -0
- package/dist/core/item/actionability.d.ts +21 -1
- package/dist/core/item/actionability.js +45 -10
- package/dist/core/item/id.js +8 -4
- package/dist/core/item/item-type-definition.d.ts +2 -0
- package/dist/core/item/item-type-definition.js +9 -2
- package/dist/core/item/type-registry.d.ts +5 -1
- package/dist/core/item/type-registry.js +9 -4
- package/dist/core/output/mutation-projection.js +12 -5
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/store/item-metadata-query-index.js +13 -10
- package/dist/core/store/item-metadata-read-work.d.ts +19 -0
- package/dist/core/store/item-metadata-read-work.js +44 -0
- package/dist/core/store/item-store.d.ts +14 -0
- package/dist/core/store/item-store.js +52 -10
- package/dist/core/store/settings-validator.js +3 -2
- package/dist/core/validate/fix-planning.d.ts +1 -1
- package/dist/core/validate/fix-planning.js +2 -2
- package/dist/core/validate/missing-link-owners.d.ts +1 -1
- package/dist/core/validate/missing-link-owners.js +5 -3
- package/dist/core/validate/stale-file-classification.d.ts +6 -4
- package/dist/core/validate/stale-file-classification.js +20 -5
- package/dist/mcp/server.js +12 -5
- package/dist/sdk/actionability.d.ts +1 -1
- package/dist/sdk/actionability.js +3 -3
- package/dist/sdk/cli-contracts/command-aliases.js +11 -2
- package/dist/sdk/cli-contracts/completeness.js +4 -3
- package/dist/sdk/cli-contracts/flag-contracts.d.ts +2 -0
- package/dist/sdk/cli-contracts/flag-contracts.js +31 -5
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +21 -13
- package/dist/sdk/cli-contracts/grammar-contracts.js +11 -2
- package/dist/sdk/cli-contracts/runtime-contracts.js +5 -2
- package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +254 -5
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +52 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +30 -6
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +32 -7
- package/dist/sdk/context/usage-ledger.d.ts +41 -0
- package/dist/sdk/context/usage-ledger.js +186 -0
- package/dist/sdk/context-intent-contracts.js +3 -3
- package/dist/sdk/context-usage.d.ts +18 -9
- package/dist/sdk/context-usage.js +44 -121
- package/dist/sdk/define.d.ts +1 -1
- package/dist/sdk/define.js +2 -2
- package/dist/sdk/dependency-provenance.d.ts +7 -0
- package/dist/sdk/dependency-provenance.js +14 -4
- package/dist/sdk/duplicates.d.ts +2 -0
- package/dist/sdk/duplicates.js +3 -2
- package/dist/sdk/environment/host-environment-errors.d.ts +5 -27
- package/dist/sdk/environment/host-environment-errors.js +4 -137
- package/dist/sdk/extension/install-runtime.js +9 -6
- package/dist/sdk/extension/install-snapshot.js +7 -6
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +104 -56
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +50 -2
- package/dist/sdk/governance/assurance-action.d.ts +3 -2
- package/dist/sdk/governance/assurance-action.js +23 -11
- package/dist/sdk/governance/assurance-runtime.d.ts +2 -0
- package/dist/sdk/governance/assurance-runtime.js +6 -3
- package/dist/sdk/governance/defect-recurrence-coverage.d.ts +93 -0
- package/dist/sdk/governance/defect-recurrence-coverage.js +189 -0
- package/dist/sdk/governance/defect-recurrence-graph.d.ts +33 -0
- package/dist/sdk/governance/defect-recurrence-graph.js +121 -0
- package/dist/sdk/governance/defect-recurrence.d.ts +8 -0
- package/dist/sdk/governance/defect-recurrence.js +118 -17
- package/dist/sdk/governance/health.d.ts +17 -2
- package/dist/sdk/governance/health.js +31 -10
- package/dist/sdk/governance/linked-file-report.d.ts +41 -0
- package/dist/sdk/governance/linked-file-report.js +72 -0
- package/dist/sdk/governance/validate-history-drift.js +16 -5
- package/dist/sdk/governance/validate.d.ts +5 -2
- package/dist/sdk/governance/validate.js +21 -37
- package/dist/sdk/governance.d.ts +2 -0
- package/dist/sdk/governance.js +4 -2
- package/dist/sdk/guide-topics.js +116 -2
- package/dist/sdk/history/salvage.d.ts +35 -0
- package/dist/sdk/history/salvage.js +248 -0
- package/dist/sdk/history-compact.js +32 -37
- package/dist/sdk/history-read.d.ts +3 -2
- package/dist/sdk/history-read.js +6 -3
- package/dist/sdk/history-repair.d.ts +12 -0
- package/dist/sdk/history-repair.js +60 -13
- package/dist/sdk/lifecycle/claim.d.ts +4 -0
- package/dist/sdk/lifecycle/claim.js +9 -3
- package/dist/sdk/lifecycle/close.d.ts +8 -0
- package/dist/sdk/lifecycle/close.js +16 -8
- package/dist/sdk/lifecycle/create.js +9 -12
- package/dist/sdk/lifecycle/restore.d.ts +1 -0
- package/dist/sdk/lifecycle/restore.js +19 -7
- package/dist/sdk/lifecycle/update.js +12 -12
- package/dist/sdk/lifecycle-policy.d.ts +3 -0
- package/dist/sdk/lifecycle-policy.js +2 -2
- package/dist/sdk/merge/abandoned-receipts.d.ts +15 -0
- package/dist/sdk/merge/abandoned-receipts.js +47 -0
- package/dist/sdk/merge/driver.js +4 -2
- package/dist/sdk/merge/index.d.ts +1 -0
- package/dist/sdk/merge/index.js +2 -2
- package/dist/sdk/merge/receipt-operation.d.ts +15 -0
- package/dist/sdk/merge/receipt-operation.js +97 -0
- package/dist/sdk/merge/receipt-schema.d.ts +20 -0
- package/dist/sdk/merge/receipt-schema.js +398 -0
- package/dist/sdk/merge/receipts.d.ts +16 -7
- package/dist/sdk/merge/receipts.js +54 -340
- package/dist/sdk/merge/reconcile.d.ts +2 -0
- package/dist/sdk/merge/reconcile.js +11 -4
- package/dist/sdk/output-projection.d.ts +3 -1
- package/dist/sdk/output-projection.js +11 -3
- package/dist/sdk/public-surface.json +1 -0
- package/dist/sdk/query/context.d.ts +9 -0
- package/dist/sdk/query/context.js +33 -21
- package/dist/sdk/query/duplicate-candidates.d.ts +7 -0
- package/dist/sdk/query/duplicate-candidates.js +71 -0
- package/dist/sdk/query/get.d.ts +2 -2
- package/dist/sdk/query/get.js +9 -8
- package/dist/sdk/query/history.d.ts +11 -0
- package/dist/sdk/query/history.js +34 -10
- package/dist/sdk/query/next.d.ts +15 -1
- package/dist/sdk/query/next.js +43 -20
- package/dist/sdk/query.d.ts +3 -0
- package/dist/sdk/query.js +5 -2
- package/dist/sdk/read-output-session.js +5 -3
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.js +4 -2
- package/dist/sdk/similarity.d.ts +24 -3
- package/dist/sdk/similarity.js +50 -55
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -2
- package/docs/AGENT_GUIDE.md +58 -1
- package/docs/BOUNDED_CONTEXT_READS.md +185 -0
- package/docs/CLOSE_EVIDENCE_RECOVERY.md +35 -0
- package/docs/COMMANDS.md +30 -8
- package/docs/CONTEXT_RELEVANCE.md +16 -4
- package/docs/DEFECT_RECURRENCE.md +80 -6
- package/docs/EXTENSIONS.md +18 -19
- package/docs/HISTORY_RECOVERY.md +146 -0
- package/docs/MERGE_SAFETY.md +50 -0
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +66 -0
- package/docs/PR_REVIEW_LOOP.md +18 -3
- package/docs/README.md +19 -1
- package/docs/RELEASING.md +31 -13
- package/docs/SDK_CONTEXT_TRUTH_CONTRACTS.md +24 -1
- package/docs/SDK_EXECUTION_CONTRACTS.md +105 -0
- package/docs/SDK_LIFECYCLE.md +27 -0
- package/docs/SDK_RUNTIME_BOUNDARIES.md +11 -0
- package/docs/TESTING.md +5 -0
- package/docs/agent-task-token-baseline.json +17 -17
- package/docs/agent-task-transcripts.json +2 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +11 -11
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +11 -3
- package/marketplace.json +2 -2
- package/package.json +8 -6
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/README.md +10 -1
- package/packages/pm-governance-audit/extensions/governance-audit/dedupe-audit.ts +50 -65
- package/packages/pm-governance-audit/extensions/governance-audit/index.ts +2 -2
- package/packages/pm-governance-audit/extensions/governance-audit/sdk.ts +1 -0
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/skills/pm-audit/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-developer/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-planner/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-release/SKILL.md +2 -2
- package/plugins/pm-claude/skills/pm-workflow/SKILL.md +3 -3
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/skills/pm-auditor/SKILL.md +2 -2
- package/plugins/pm-codex/skills/pm-native/SKILL.md +3 -4
- package/plugins/pm-codex/skills/pm-release/SKILL.md +2 -2
- package/scripts/finalize-build.mjs +13 -1
- package/dist/cli-bundle/chunks/chunk-6XSKPNCF.js +0 -230
- package/dist/cli-bundle/chunks/chunk-OGBVU67G.js +0 -5
- package/dist/cli-bundle/chunks/chunk-TXW6VL33.js +0 -38
- package/dist/cli-bundle/chunks/chunk-VGLHECAP.js +0 -9
- package/dist/cli-bundle/chunks/register-operations-OH7R3ZT4.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4YRAVI43.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-5P4HVOWG.js +0 -176
- package/dist/cli-bundle/focused-chunks/chunk-636VVQ7F.js +0 -54
- package/dist/cli-bundle/focused-chunks/chunk-B3A6MJYE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-BFDDJ2T2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-BHUIRZWQ.js +0 -9
- package/dist/cli-bundle/focused-chunks/chunk-JADHHPY6.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-NSKBLHVI.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-P2GOAOQN.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-YARWJM2B.js +0 -2
- package/sdk/public-surface.json +0 -33034
package/docs/EXTENSIONS.md
CHANGED
|
@@ -91,11 +91,15 @@ Package roots declare resources in `package.json` under `pm`:
|
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
Installation activates `pm.extensions`. `pm.docs`, `pm.examples`, `pm.assets`, and `pm.prompts` are catalog metadata (metadata-only — they are discovered and surfaced in the catalog but not executed). Declare agent-facing prompt/slash-command markdown under `pm.prompts` and non-code assets (images, skills, fixtures) under `pm.assets`; their conventional roots are `prompts/` (also `.agents/pm/prompts/`) and `assets/` (also `.agents/pm/assets/`).
|
|
94
|
-
`pm package init` and
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
`pm package init` (and compatible `pm extension init`) creates a publishable root extension (`"extensions": ["."]`):
|
|
95
|
+
|
|
96
|
+
- The artifact includes package metadata, typed `index.ts`, a colocated `node:test` suite, strict type-check-only `tsconfig.json`, and `typecheck`/`test` scripts. Results report canonical `package_name` and exact `invocation_command`; an existing `pm-` prefix is retained once.
|
|
97
|
+
- The manifest points to `./index.ts`, loaded by native TypeScript stripping on Node >=22.18 ([pm-2c28](../.agents/pm/decisions/pm-2c28.toon), [pm-m1uz](../.agents/pm/decisions/pm-m1uz.toon)). Run `npm install` for the peer SDK and type checking before package installation; no build step is required. The README demonstrates the SDK [define* builders](../.agents/pm/decisions/pm-3mph.toon).
|
|
98
|
+
- `--capability` selects `commands`, `hooks`, `search`, `importers`, `schema`, `profile`, `renderers`, `parser`, `preflight`, or `services`. Every starter keeps a runnable command and adds matching SDK `assertRegistered*`/`runRegistered*ForTest` tests. Repeating one selection is idempotent; distinct selections fail with an actionable usage error.
|
|
99
|
+
- Scaffold selectors and manifest capabilities differ: `profile` registers a profile under `schema`. The [capability matrix](SDK.md#minimal-command-extension) explains each registration, schema-governed flags, and why `schema`/`profile` omit narrow `activation.commands` so their contributions stay globally available.
|
|
100
|
+
- Starter manifests declare `trusted: true`, `sandbox_profile: "strict"`, and explicit false permissions for filesystem, network, environment, and subprocess access. Declarative tests import `manifest.json` and call `assertExtensionManifestMatchesBlueprint`, detecting capability drift before publication.
|
|
101
|
+
- Larger packages may use nested extension directories and declare required runtime dependencies and permissions. Validate with `pm package doctor`; its advisory `extension_schema_narrow_activation` finding recommends removing narrow activation when custom item types or fields need global availability.
|
|
102
|
+
Package tests can pair `readPmPackageManifest(packageRoot)` with `assertPackageManifest(manifest, { resources: ... })` from `@unbrained/pm-cli/sdk` to prove aliases and resource paths without duplicating pm's manifest normalization logic.
|
|
99
103
|
|
|
100
104
|
When no package manifest is present, `pm` discovers conventional extension directories:
|
|
101
105
|
|
|
@@ -115,7 +119,11 @@ Runtime path overrides:
|
|
|
115
119
|
- `PM_PATH`: project tracker root
|
|
116
120
|
- `PM_GLOBAL_PATH`: global profile root
|
|
117
121
|
|
|
118
|
-
Extensions are authored
|
|
122
|
+
Extensions are authored and loaded as TypeScript ([pm-2c28](../.agents/pm/decisions/pm-2c28.toon), [pm-m1uz](../.agents/pm/decisions/pm-m1uz.toon)):
|
|
123
|
+
|
|
124
|
+
- A minimal standalone extension has `manifest.json` and `index.ts`. Node >=22.18 loads that entry directly with native type stripping; no compilation or `index.js` is required.
|
|
125
|
+
- Use `import type { ExtensionApi }` for erased SDK types. Standalone entries outside `node_modules` need the host SDK link described below before using runtime SDK imports.
|
|
126
|
+
- Install `typescript` and `@unbrained/pm-cli`, then run `npx tsc --noEmit` to check authoring types.
|
|
119
127
|
|
|
120
128
|
```json
|
|
121
129
|
{
|
|
@@ -279,7 +287,7 @@ Surface tokens include command handlers/overrides, parser/preflight/services/ren
|
|
|
279
287
|
|
|
280
288
|
Some extension surfaces are intentionally single-winner: command handlers and overrides, parser overrides, preflight overrides, and format renderers. Activation is deterministic: lower manifest `priority` values load first, omitted priority defaults to `100`, equal priorities sort by package identity/path, and the last registration wins. If multiple packages register the same single-winner surface, `pm package doctor` / `pm health` report deterministic `extension_*_collision` warnings whose suffix names the winning layer/package before the displaced layer/package. `pm package describe --json` also exposes `command_ownership`: every claimant in activation order, the effective winner, collision state, and the explicit `last_activated_wins` policy. SDK hosts can build the identical table with `buildExtensionDescribeResult` and the exported `ExtensionCommandOwnership` contracts. Renderer ownership is evaluated per command: same-format renderers with disjoint `commands` lists safely coexist, while an unscoped or overlapping claim still warns; runtime `resultDiscriminator` predicates alone cannot prove static disjointness. Tracked by [pm-6mjxgq](../.agents/pm/issues/pm-6mjxgq.toon).
|
|
281
289
|
|
|
282
|
-
For definition-based commands,
|
|
290
|
+
For definition-based commands, a malformed definition is recorded as `extension_command_quarantined:*` with a registration trace. Activation then rolls back all registrations from that extension, preserving atomic package activation. Fix the failed definition before expecting sibling commands to load. Other valid extensions retain their registrations.
|
|
283
291
|
Use the warning details to resolve the overlap:
|
|
284
292
|
|
|
285
293
|
```bash
|
|
@@ -294,12 +302,6 @@ Doctor JSON also includes `triage.collision_plan` with grouped surfaces, ranked
|
|
|
294
302
|
|
|
295
303
|
Use the public SDK barrel. Do not deep-import from `src/core` or `dist/core`.
|
|
296
304
|
|
|
297
|
-
```ts
|
|
298
|
-
import { defineExtension } from "@unbrained/pm-cli/sdk";
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
Common APIs:
|
|
302
|
-
|
|
303
305
|
- `api.extension` is a read-only identity (`name`, `layer`, `version`, `capabilities`, `pm_min_version?`, `pm_max_version?`, `source_package?`) for self-identifying logs and version gating without re-reading the manifest.
|
|
304
306
|
- `api.registerCommand(definition)` adds package-owned commands.
|
|
305
307
|
- `api.registerFlags(command, flags)` adds runtime command flags. A flag may declare `value_type` (canonical; the legacy `type` alias is honored only when `value_type` is absent), `list: true` to accumulate repeated/comma-joined values like core `--tags`, and a `default` applied when the flag is omitted.
|
|
@@ -331,6 +333,8 @@ pm contracts --runtime-only --schema-only --json
|
|
|
331
333
|
pm contracts --command <command> --flags-only --json
|
|
332
334
|
```
|
|
333
335
|
|
|
336
|
+
`CliFlagContract.reservation_scope` tells package authors which host flags are reserved: `inherited` flags (including their aliases) cannot be redeclared by extensions; `root_only` flags belong only to the root command. The public `GLOBAL_FLAG_CONTRACTS` table from `@unbrained/pm-cli/sdk/contracts` exposes the same classification used by runtime validation. For example, an extension may define its own boolean `--explain`; root `pm --explain` keeps its host meaning. Redeclaring inherited `--json` fails validation and rolls back that package's activation. See [pm-2h8t6y](../.agents/pm/issues/pm-2h8t6y.toon).
|
|
337
|
+
|
|
334
338
|
List-valued inline flags and `registerFlags` entries share one ordered
|
|
335
339
|
accumulator across their long and short aliases. For a variadic positional that
|
|
336
340
|
must receive values such as `-h` or `--json`, put the end-of-options separator
|
|
@@ -381,8 +385,6 @@ pm package reload --project
|
|
|
381
385
|
pm package reload --project --watch
|
|
382
386
|
```
|
|
383
387
|
|
|
384
|
-
Compatibility equivalents remain available through `pm extension ...` for existing automation.
|
|
385
|
-
|
|
386
388
|
## Upgrade Workflow
|
|
387
389
|
|
|
388
390
|
`pm package upgrade` is the package-first update entrypoint:
|
|
@@ -443,7 +445,4 @@ Prefer `createExtensionTestHarness(module, { capabilities })` in package unit te
|
|
|
443
445
|
|
|
444
446
|
## Runnable Examples
|
|
445
447
|
|
|
446
|
-
-
|
|
447
|
-
- `docs/examples/policy-restricted-extension/`
|
|
448
|
-
- `docs/examples/sdk-contract-consumer/`
|
|
449
|
-
- `docs/examples/sdk-app-embedding/`
|
|
448
|
+
See the [starter](examples/starter-extension/README.md), [policy-restricted](examples/policy-restricted-extension/README.md), [SDK contract consumer](examples/sdk-contract-consumer/README.md), and [SDK application](examples/sdk-app-embedding/README.md) examples.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# History durability and recovery
|
|
2
|
+
|
|
3
|
+
Tracked by [pm-96fsma](../.agents/pm/issues/pm-96fsma.toon),
|
|
4
|
+
[pm-m0yjtg](../.agents/pm/issues/pm-m0yjtg.toon),
|
|
5
|
+
[pm-qw1uw6](../.agents/pm/issues/pm-qw1uw6.toon),
|
|
6
|
+
[pm-e3gn0z](../.agents/pm/issues/pm-e3gn0z.toon), and
|
|
7
|
+
[pm-wlqxg3](../.agents/pm/tasks/pm-wlqxg3.toon).
|
|
8
|
+
|
|
9
|
+
Project management depends on trustworthy context. History is not just an
|
|
10
|
+
activity feed: it is the reconstructable source for prior item states, including
|
|
11
|
+
their evidence, relationships, and lifecycle transitions. Recovery must not
|
|
12
|
+
manufacture missing context or silently change an item's identity.
|
|
13
|
+
|
|
14
|
+
## Stable addresses after compaction
|
|
15
|
+
|
|
16
|
+
`pm get <id> --at <version>` and `pm restore <id> <version>` use durable,
|
|
17
|
+
one-based version addresses. Compaction checkpoints the last compacted state
|
|
18
|
+
at its original version. Retained entries keep their addresses, including after
|
|
19
|
+
repeated compactions. Versions before the checkpoint fail with
|
|
20
|
+
`history_version_pruned`; they never select a different retained entry.
|
|
21
|
+
|
|
22
|
+
The checkpoint records `history_compaction.version_offset`. Add that offset to
|
|
23
|
+
a physical one-based stream position to obtain its durable version. `pm history`
|
|
24
|
+
reports `version_addressing`, and compact rows include their `version` alongside
|
|
25
|
+
the physical `index`. Verification error ordinals and diff indices remain
|
|
26
|
+
physical positions in the current stream. The checkpoint timestamp is the last
|
|
27
|
+
compacted entry's timestamp; the maintenance audit event records compaction time.
|
|
28
|
+
|
|
29
|
+
Legacy checkpoints without a recorded offset cannot prove their original
|
|
30
|
+
numeric addresses. Numeric reads fail with `history_version_mapping_unavailable`.
|
|
31
|
+
Use a retained timestamp instead; the SDK then returns `as_of_version: null`.
|
|
32
|
+
SDK consumers must handle this nullable value. `target.historyIndex` is always
|
|
33
|
+
the resolved physical zero-based position, not an original version number.
|
|
34
|
+
Default and timestamp-based compaction remain available for these legacy
|
|
35
|
+
streams. They preserve an unknown offset as `null`, including no-op results;
|
|
36
|
+
compaction never manufactures a numeric mapping from physical positions.
|
|
37
|
+
|
|
38
|
+
## Recover an unreadable item file
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pm history <id> --full
|
|
42
|
+
pm restore <id> <version>
|
|
43
|
+
pm history <id> --verify --strict-exit
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Restore accepts an absent file or an unparsable item document when intact
|
|
47
|
+
history can reconstruct it. It verifies the history before using the recovered
|
|
48
|
+
state, preserves the original unreadable bytes for rollback, and uses the normal
|
|
49
|
+
ownership and lock checks. Successful recovery reports
|
|
50
|
+
`restore_unreadable_item_recovered`. Permission errors and unresolved merge
|
|
51
|
+
conflicts are not treated as missing files. A missing initial baseline returns
|
|
52
|
+
`history_baseline_unavailable` with recovery guidance rather than inventing
|
|
53
|
+
metadata from a partial patch.
|
|
54
|
+
|
|
55
|
+
CLI shape errors name the item ID, file path, and zero-length files. The SDK
|
|
56
|
+
error context also includes byte length and an explicit empty-file flag.
|
|
57
|
+
`pm health --check-only` names malformed item paths and invalid
|
|
58
|
+
history lines without mutating either file; use those diagnostics to select the
|
|
59
|
+
specific recovery operation above.
|
|
60
|
+
|
|
61
|
+
Invalid UTF-8 is a separate refusal (`item_document_encoding_invalid`), not a
|
|
62
|
+
recoverable text parse failure. Preserve a binary backup before recovering such
|
|
63
|
+
a file; text decoding must never silently replace original bytes.
|
|
64
|
+
Its SDK error context identifies the item ID, path, byte length, and nonempty
|
|
65
|
+
state just as text-shape diagnostics do.
|
|
66
|
+
|
|
67
|
+
## Recover an invalid history tail
|
|
68
|
+
|
|
69
|
+
Keep a local backup before applying destructive history maintenance. Preview
|
|
70
|
+
exactly one stream, inspect the receipt, then explicitly apply:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pm history-repair <id> --salvage-tail --dry-run --json
|
|
74
|
+
pm history-repair <id> --salvage-tail --json
|
|
75
|
+
pm history <id> --verify --strict-exit
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Salvage requires a nonempty, hash-verified prefix and retains its bytes unchanged.
|
|
79
|
+
The receipt records the first invalid physical line, discarded UTF-8 byte count,
|
|
80
|
+
discarded-suffix SHA-256, and retained record count. An appended `history_salvage`
|
|
81
|
+
event records that receipt without copying potentially private damaged contents.
|
|
82
|
+
Salvage does not rehash prior entries, reconcile item state, or normalize
|
|
83
|
+
provenance. It refuses bulk selection, conflicting repair modes, merge conflict
|
|
84
|
+
markers, parseable records after corruption, and potentially complete records
|
|
85
|
+
with attached corruption. Recover those cases from version control or a backup.
|
|
86
|
+
Non-UTF-8 streams are also refused, so receipt hashes and rollback snapshots
|
|
87
|
+
always describe the original bytes rather than a lossy decoded approximation.
|
|
88
|
+
|
|
89
|
+
The public SDK uses the same operation:
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { PmClient } from "@unbrained/pm-cli";
|
|
93
|
+
|
|
94
|
+
const client = new PmClient({ pmRoot: "/project/.agents/pm" });
|
|
95
|
+
const preview = await client.historyRepair("pm-example", {
|
|
96
|
+
salvageTail: true,
|
|
97
|
+
dryRun: true,
|
|
98
|
+
});
|
|
99
|
+
console.log(preview.salvage);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The CLI and MCP expose this SDK-owned contract; package authors do not need a
|
|
103
|
+
separate recovery implementation.
|
|
104
|
+
|
|
105
|
+
## Permanent item identities
|
|
106
|
+
|
|
107
|
+
Deleting an item retains its identity reservation through its history file.
|
|
108
|
+
Generated IDs skip those reservations, even under reproducible execution.
|
|
109
|
+
Explicit recreation fails with `item_identity_reserved`; use restore to recover
|
|
110
|
+
the original subject, or create a new ID for unrelated work.
|
|
111
|
+
The first `create` append exclusively creates its effective history file, so
|
|
112
|
+
concurrent SDK callers and extension redirects cannot both reserve it. A failed
|
|
113
|
+
partial first write keeps the reservation for diagnosis; it is never deleted
|
|
114
|
+
to make the identity reusable. Subsequent large-record appenders still need the
|
|
115
|
+
normal item lock or an equivalent caller-owned serialization boundary.
|
|
116
|
+
|
|
117
|
+
Verification refuses a second `create` event, including one imported through
|
|
118
|
+
branch union, and names both physical ordinals. Point-in-time reads cannot cross
|
|
119
|
+
that discontinuity silently. Recover the original streams rather than rehashing
|
|
120
|
+
two unrelated subjects into a single supposedly valid item.
|
|
121
|
+
|
|
122
|
+
`pm validate --check-history-drift` reports this as an error, with item ID,
|
|
123
|
+
original and repeated genesis ordinals, and the observed sequence. The public
|
|
124
|
+
`findHistoryIdentityDiscontinuities` SDK primitive provides the same evidence
|
|
125
|
+
for importers. A delete followed by create is distinguished from multiple creates
|
|
126
|
+
or a checkpoint followed by create; these observations do not prove which
|
|
127
|
+
writer or branch introduced the records. Old drift caches are invalidated, and
|
|
128
|
+
known-invalid streams are reread even in metadata-cache mode.
|
|
129
|
+
|
|
130
|
+
## Regression verification
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
node scripts/run-tests.mjs test -- tests/integration/history-durability.integration.spec.ts
|
|
134
|
+
node scripts/run-tests.mjs test -- tests/integration/history-maintenance-replay.integration.spec.ts
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The fixture drives real CLI lifecycle mutations, independently captures each
|
|
138
|
+
serialized state, removes the live item file, and compares every addressable
|
|
139
|
+
version against those captures. Companion cases exercise repeated compaction,
|
|
140
|
+
legacy mapping refusal, seeded identity reuse, invalid-tail preservation,
|
|
141
|
+
unreadable-file recovery, and missing baselines. Maintenance fixtures additionally
|
|
142
|
+
perform redaction and a real divergent Git merge, compare every version with an
|
|
143
|
+
independent strict patch fold, and compare the final state with a separately
|
|
144
|
+
read item. Concurrent writes and binary corruption are negative controls, not
|
|
145
|
+
mocked successful outcomes. All fixtures use temporary trackers, never repository
|
|
146
|
+
tracker data.
|
package/docs/MERGE_SAFETY.md
CHANGED
|
@@ -186,6 +186,53 @@ receipt file that the older writer never created. Incomplete, contradictory, or
|
|
|
186
186
|
modern summaries still fail closed. `runMergeReceiptReport` remains the
|
|
187
187
|
compatible valid-only report.
|
|
188
188
|
|
|
189
|
+
## Historical receipt reader compatibility
|
|
190
|
+
|
|
191
|
+
Tracked by [pm-2xtv84](../.agents/pm/issues/pm-2xtv84.toon) and
|
|
192
|
+
[pm-v66zir](../.agents/pm/issues/pm-v66zir.toon). Version-1 preferred-era and
|
|
193
|
+
identified `requested_preference`/`clone_local` receipts may omit `base`, `ours`,
|
|
194
|
+
or `theirs` when the original value was undefined. Readers normalize those slots to the explicit missing-value marker
|
|
195
|
+
in memory. They still require retained/discarded evidence and valid collections;
|
|
196
|
+
reading never rewrites the original file. Collection failures expose a bounded
|
|
197
|
+
`validation_path`, such as `union_fields` or `decisions[0]`. The diagnostic
|
|
198
|
+
category `collections` is not a property that should be added to a receipt.
|
|
199
|
+
The writer now encodes all five scalar slots itself, including undefined
|
|
200
|
+
retained/discarded values supplied directly through the SDK, before JSON storage.
|
|
201
|
+
|
|
202
|
+
Paired clone-local and historical hash-only copies accept the original scalar
|
|
203
|
+
hash encoding throughout inspection and settlement. Compatibility does not
|
|
204
|
+
apply to durable copies declaring the modern value policy. Changed values or
|
|
205
|
+
immutable coordinates remain copy-provenance failures. Hash-only evidence
|
|
206
|
+
does not recover the original private value.
|
|
207
|
+
|
|
208
|
+
## Receipts from an aborted rebase
|
|
209
|
+
|
|
210
|
+
Tracked by [pm-466m0j](../.agents/pm/issues/pm-466m0j.toon). New receipts
|
|
211
|
+
created during a rebase capture only its original commit and item blob in the
|
|
212
|
+
typed `MergeReceiptOperation` contract. After aborting, run:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
pm merge reconcile --dry-run --json
|
|
216
|
+
pm merge reconcile --message "Record restored original rebase state" --json
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Settlement requires Git to have left every active merge/rebase/cherry-pick/revert
|
|
220
|
+
operation, HEAD to match the original commit, and the item in HEAD, index, and
|
|
221
|
+
working tree to match the original blob. The item history must already be clean.
|
|
222
|
+
The history transaction rechecks the proof against its exact protected item
|
|
223
|
+
snapshot. Apply appends an explicit `merge_reconcile` event with
|
|
224
|
+
`abandoned_receipts` and the reason `original_git_state_restored`; it then marks
|
|
225
|
+
both copies reconciled with that settlement reason. The result counts these in
|
|
226
|
+
`receipts.abandoned`, separately from applied merge decisions. Preview performs
|
|
227
|
+
the same eligibility checks and leaves both history and receipts untouched.
|
|
228
|
+
If receipt persistence fails after the audit commits, retry reuses the identical
|
|
229
|
+
verified disposition and finishes the receipt writes without appending another
|
|
230
|
+
audit event. An unrelated earlier audit does not satisfy this check.
|
|
231
|
+
|
|
232
|
+
Old receipts without operation coordinates remain pending for ordinary review.
|
|
233
|
+
Tracked `merge-receipts/` sidecars are durable provenance and must remain tracked.
|
|
234
|
+
Deleting or ignoring them would lose the evidence needed by other clones.
|
|
235
|
+
|
|
189
236
|
## Cross-branch id collision safety
|
|
190
237
|
|
|
191
238
|
Item ids are `<prefix>` plus random base36 characters, and uniqueness is only probed against the local working tree — two agents branching from the same commit can mint the same id for different items (GH-600 / pm-pibw). Two controls bound that risk:
|
|
@@ -210,6 +257,9 @@ pm merge reconcile --force --message "Accept reviewed merge decisions" --json
|
|
|
210
257
|
```
|
|
211
258
|
|
|
212
259
|
The preview reports every drifted stream and pending receipt without mutation.
|
|
260
|
+
It applies the same exact-snapshot proof requirement as apply: stale or
|
|
261
|
+
unprovable receipts appear as failed streams in both modes, tracked by
|
|
262
|
+
[pm-ao0bu9](../.agents/pm/issues/pm-ao0bu9.toon).
|
|
213
263
|
Lossless receipts do not become discarded-value decisions and reconcile without
|
|
214
264
|
`--force`, but `pm health` reports `merge_receipts_pending:<n>` and remains
|
|
215
265
|
non-green until the apply pass settles them. `pm history-repair` cannot clear
|
|
@@ -265,11 +265,77 @@ These are corpus-generated figures, not live tracker payloads. The generated
|
|
|
265
265
|
corpus contains 2,243 items; the `status:all` query intentionally excludes 245
|
|
266
266
|
canceled fixtures under the command's current status-selection contract.
|
|
267
267
|
|
|
268
|
+
## Health Verdicts
|
|
269
|
+
|
|
270
|
+
Tracked by [pm-fkohe8](../.agents/pm/issues/pm-fkohe8.toon) and
|
|
271
|
+
[pm-du93sr](../.agents/pm/issues/pm-du93sr.toon).
|
|
272
|
+
|
|
268
273
|
`health --check-only` defaults to a summary verdict: all checks still run, but
|
|
269
274
|
passing check evidence bodies are empty. Use `health --check-only --full` when
|
|
270
275
|
diagnostic evidence is required. Explicit `--brief` or `--summary` retains the
|
|
271
276
|
existing fast check-only mode that skips expensive optional scans.
|
|
272
277
|
|
|
278
|
+
Use top-level `ok` to decide health. Each `checks[].ok` uses the same rule:
|
|
279
|
+
true means no gate-failing findings belong to that check. A check can therefore
|
|
280
|
+
have `status: "warn"` and `ok: true` when all its findings are advisory.
|
|
281
|
+
`failed_because` names every deciding warning, including findings beyond the
|
|
282
|
+
bounded warning sample. `findings[].severity` distinguishes advisory from
|
|
283
|
+
`gate_failing` evidence without parsing prose.
|
|
284
|
+
|
|
285
|
+
The `verdict` receipt names `authority: "ok"` and the invocation's `exit_code`.
|
|
286
|
+
`strict_exit: true` and `require_merge_drivers: true` appear only when enabled;
|
|
287
|
+
omission means false. The default invocation reports blocking findings without
|
|
288
|
+
changing the process exit code. `--strict-exit` (alias `--fail-on-warn`) requires
|
|
289
|
+
clone-local merge drivers and exits `1` when `ok` is false. Other advisory
|
|
290
|
+
warnings retain their policy. Compare invocations with the same scan and policy
|
|
291
|
+
options: enabling strict mode can legitimately change a missing-driver finding
|
|
292
|
+
from advisory to blocking. The SDK accepts `strictExit` and `failOnWarn` with
|
|
293
|
+
the same semantics, including MCP dispatch. Required merge-driver enforcement
|
|
294
|
+
always runs the integrity check, even when `skipIntegrity` or an explicit compact
|
|
295
|
+
check-only projection would otherwise skip optional integrity work.
|
|
296
|
+
|
|
297
|
+
The required token corpus measures `health --check-only` on its medium workspace
|
|
298
|
+
under the `health-default` ceiling. Its positive and negative controls run in
|
|
299
|
+
the same repository quality composition as the other answer budgets. Full
|
|
300
|
+
evidence remains an explicit restore path; the verdict receipt does not raise
|
|
301
|
+
the existing default token ceiling.
|
|
302
|
+
|
|
303
|
+
## Linked-File Repair Rows
|
|
304
|
+
|
|
305
|
+
Tracked by [pm-zw9188](../.agents/pm/issues/pm-zw9188.toon).
|
|
306
|
+
|
|
307
|
+
`validate --check-files` joins each missing path with its holders, lifecycle
|
|
308
|
+
states, link fields, and candidate destinations before applying output limits.
|
|
309
|
+
`missing_linked_path_rows` contains structured objects in both default and
|
|
310
|
+
`--verbose-file-lists` output. The default caps paths and holders per path at
|
|
311
|
+
40; verbose output restores both collections. `items_truncated` and
|
|
312
|
+
`missing_linked_path_rows_truncated` identify the two independent omissions.
|
|
313
|
+
|
|
314
|
+
`validate --counts` omits false `*_truncated` markers to keep its summary compact.
|
|
315
|
+
True truncation markers, ordinary false values, and every zero count remain;
|
|
316
|
+
its projection receipt declares that diagnostic rows were omitted.
|
|
317
|
+
|
|
318
|
+
Counts describe the complete scanned population:
|
|
319
|
+
|
|
320
|
+
- `missing_linked_links_count` counts distinct path, holder, and field triples.
|
|
321
|
+
- `missing_linked_path_rows_count` counts distinct paths.
|
|
322
|
+
- `active_missing_linked_links_count` and `active_missing_linked_paths_count`
|
|
323
|
+
identify actionable work under the configured workflow registry.
|
|
324
|
+
- `legacy_closed_missing_linked_links_count` is the close-status subset of
|
|
325
|
+
`legacy_terminal_missing_linked_links_count`.
|
|
326
|
+
|
|
327
|
+
Only active missing paths cause the missing-link warning. Historical terminal
|
|
328
|
+
links remain visible for context reconstruction. Unknown statuses and absent
|
|
329
|
+
holder metadata remain actionable. Rows and holders prioritize active work.
|
|
330
|
+
Package authors can build the same pure report with
|
|
331
|
+
`buildLinkedFileRepairReport` from `@unbrained/pm-cli/sdk/governance` and choose
|
|
332
|
+
an explicit finite ceiling or `Infinity` for full output.
|
|
333
|
+
|
|
334
|
+
Same-basename destinations are possibilities requiring review. Missing CSV or
|
|
335
|
+
`path:note` literals receive `malformed` classification and no inferred move;
|
|
336
|
+
explicit pruning never removes that category. Existing literal filenames are
|
|
337
|
+
checked before classification, including names containing commas or colons.
|
|
338
|
+
|
|
273
339
|
## Completion Resolver Contract
|
|
274
340
|
|
|
275
341
|
`resolveCompletionTimestamp` accepts legacy metadata where all timestamp fields
|
package/docs/PR_REVIEW_LOOP.md
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
# Pull Request Review Loop
|
|
2
2
|
|
|
3
|
-
Trackers: [pm-hq28](../.agents/pm/tasks/pm-hq28.toon), [pm-cp5pbo](../.agents/pm/tasks/pm-cp5pbo.toon)
|
|
3
|
+
Trackers: [pm-hq28](../.agents/pm/tasks/pm-hq28.toon), [pm-cp5pbo](../.agents/pm/tasks/pm-cp5pbo.toon), [pm-8we38i](../.agents/pm/issues/pm-8we38i.toon)
|
|
4
4
|
|
|
5
5
|
Use `scripts/reviews/pr-review-loop.mjs` to inventory every GitHub pull-request
|
|
6
6
|
conversation surface before deciding that review is complete. The inventory includes
|
|
7
7
|
top-level comments, submitted reviews, inline review threads, edited timestamps,
|
|
8
8
|
reaction state, thread resolution, outdated markers, and the reviewed head SHA.
|
|
9
9
|
|
|
10
|
+
GitHub command responses have a 64 MiB transport bound and fail visibly on overflow;
|
|
11
|
+
an overflow never certifies a complete inventory. Acknowledgement lookups retain
|
|
12
|
+
every page but project only comment IDs, bodies, and reply-parent IDs before
|
|
13
|
+
capture, avoiding repeated diff hunks that are irrelevant to marker matching.
|
|
14
|
+
|
|
10
15
|
```bash
|
|
11
16
|
node scripts/reviews/pr-review-loop.mjs inventory --pr 123 > /tmp/pr-123-review-inventory.json
|
|
12
17
|
node scripts/reviews/pr-review-loop.mjs watch --pr 123 --interval 30 > /tmp/pr-123-review-inventory.json
|
|
13
18
|
node scripts/reviews/pr-review-loop.mjs react --node-id IC_kw... --reaction THUMBS_UP
|
|
14
|
-
node scripts/reviews/pr-review-loop.mjs acknowledge --pr 123 --node-id PRR_kw... --reaction THUMBS_UP --body "CodeRabbit feedback implemented: https://github.com/owner/repo/pull/123#pullrequestreview-456. The suggested edge case is covered by test X."
|
|
19
|
+
node scripts/reviews/pr-review-loop.mjs acknowledge --pr 123 --node-id PRR_kw... --revision '<revision>' --reaction THUMBS_UP --body "CodeRabbit feedback implemented: https://github.com/owner/repo/pull/123#pullrequestreview-456. The suggested edge case is covered by test X."
|
|
15
20
|
node scripts/reviews/pr-review-loop.mjs reply-inline --pr 123 --comment-id 456 --body "Addressed in abc123."
|
|
16
|
-
node scripts/reviews/pr-review-loop.mjs acknowledge-inline --pr 123 --comment-id 456 --node-id PRRC_kw... --reaction THUMBS_UP --body "Addressed in abc123."
|
|
21
|
+
node scripts/reviews/pr-review-loop.mjs acknowledge-inline --pr 123 --comment-id 456 --node-id PRRC_kw... --revision '<revision>' --reaction THUMBS_UP --body "Addressed in abc123."
|
|
17
22
|
```
|
|
18
23
|
|
|
19
24
|
Choose `THUMBS_UP` when feedback is useful or correct and `THUMBS_DOWN` when a
|
|
@@ -28,6 +33,16 @@ retry, so a lost response cannot create duplicate acknowledgements. It reports a
|
|
|
28
33
|
partial result and exits unsuccessfully when either the comment or reaction write
|
|
29
34
|
fails, allowing the missing write to be retried safely.
|
|
30
35
|
|
|
36
|
+
Each comment and review also carries a `revision`: a SHA-256 identity of its
|
|
37
|
+
body and review state. Compare these identities after each completed check watch
|
|
38
|
+
and immediately before merge. A changed body or review verdict needs fresh
|
|
39
|
+
triage even when its node ID already has an acknowledgement. Reaction timestamp
|
|
40
|
+
changes alone do not create a new revision. Pass the observed revision to both
|
|
41
|
+
`acknowledge` and `acknowledge-inline` with `--revision <revision>`; their hidden
|
|
42
|
+
markers then distinguish revised feedback and suppress duplicate retry replies
|
|
43
|
+
for that same revision. Inline markers are matched only within the selected
|
|
44
|
+
reply thread. Legacy calls without the flag retain their existing behavior.
|
|
45
|
+
|
|
31
46
|
After every push or reviewer retrigger, run `watch`. It delegates waiting to
|
|
32
47
|
`gh pr checks --watch`, because reviewer agents report completion through GitHub
|
|
33
48
|
checks, and only fetches the complete conversation inventory after those checks
|
package/docs/README.md
CHANGED
|
@@ -81,6 +81,7 @@ pm guide release --json
|
|
|
81
81
|
- [Extension Lifecycle Contracts](EXTENSION_LIFECYCLE.md) - source identity, durable migrations, and scoped preflight ownership.
|
|
82
82
|
- [Extension Author Contracts](EXTENSION_AUTHOR_CONTRACTS.md) - the stability guarantees and contract surface package authors build against.
|
|
83
83
|
- [SDK](SDK.md) - public import surfaces and typed authoring examples.
|
|
84
|
+
- [SDK execution and recovery contracts](SDK_EXECUTION_CONTRACTS.md): schema-driven scheduling, handoff, and command recovery.
|
|
84
85
|
- [Multi-Branch Merge Safety](MERGE_SAFETY.md) - semantic tracker merge drivers, post-merge integrity gates, delete/modify policy, and recovery-receipt retention.
|
|
85
86
|
- [Codex Plugin](CODEX_PLUGIN.md) - native MCP plugin install, tools, skills, and safety notes.
|
|
86
87
|
- [Native ChatGPT and Codex Plugin Implementation Plan](CHATGPT_CODEX_PLUGIN_IMPLEMENTATION.md) - official-source
|
|
@@ -90,6 +91,17 @@ pm guide release --json
|
|
|
90
91
|
- [Releasing](RELEASING.md) - maintainer release checklist and failure handling.
|
|
91
92
|
- [starter extension](examples/starter-extension/README.md) - compact extension scaffold reference.
|
|
92
93
|
|
|
94
|
+
Additional SDK, operations, and generated contracts:
|
|
95
|
+
|
|
96
|
+
- [Item Read Projections](ITEM_READ_PROJECTIONS.md) - identity, projections, and read completeness.
|
|
97
|
+
- [MCP Capability Surfaces](MCP_CAPABILITY_SURFACES.md) - negotiated MCP discovery contracts.
|
|
98
|
+
- [PR Review Loop](PR_REVIEW_LOOP.md) - complete review inventories and feedback acknowledgment.
|
|
99
|
+
- [SDK Lifecycle](SDK_LIFECYCLE.md) - lifecycle primitives and package integration.
|
|
100
|
+
- [SDK Runtime Boundaries](SDK_RUNTIME_BOUNDARIES.md) - runtime ownership and import boundaries.
|
|
101
|
+
- [Sentry Contract Epochs](SENTRY_CONTRACT_EPOCHS.md) - diagnostic compatibility and release epochs.
|
|
102
|
+
- [Generated Agent Command Surface](generated/AGENT_COMMAND_SURFACE.md) - command routing inventory.
|
|
103
|
+
- [Generated Flag Lexicon Budgets](generated/FLAG_LEXICON_BUDGETS.md) - flag vocabulary and budget inventory.
|
|
104
|
+
|
|
93
105
|
## Guide Topic Map
|
|
94
106
|
|
|
95
107
|
| Optional `pm guide` topic | Primary docs |
|
|
@@ -151,4 +163,10 @@ Public docs must not link to ignored local operations artifacts, unpublished evi
|
|
|
151
163
|
- Put a short "Agent Quick Context" near the top of deep docs.
|
|
152
164
|
- Prefer commands that agents can copy exactly.
|
|
153
165
|
- Use `pm` item IDs as durable references when docs explain tracked work.
|
|
154
|
-
- Run
|
|
166
|
+
- Run `pnpm quality:docs-links` before closing documentation tasks. Every Markdown
|
|
167
|
+
page under `docs/` must be reachable transitively from this index, and links to
|
|
168
|
+
heading fragments must resolve. Fenced examples do not create navigation edges.
|
|
169
|
+
- A deliberately standalone page requires an individual path and nonempty reason
|
|
170
|
+
in `scripts/release/docs-reachability-exceptions.json`; stale exceptions fail.
|
|
171
|
+
This policy is tracked by [pm-s4y3z4](../.agents/pm/chores/pm-s4y3z4.toon)
|
|
172
|
+
and [pm-esbt](../.agents/pm/tasks/pm-esbt.toon).
|
package/docs/RELEASING.md
CHANGED
|
@@ -30,7 +30,10 @@ authoritative blocker-recovery run selection by
|
|
|
30
30
|
[pm-db8onn](../.agents/pm/issues/pm-db8onn.toon), and queued automatic
|
|
31
31
|
same-day recovery by [pm-dm2vfz](../.agents/pm/issues/pm-dm2vfz.toon).
|
|
32
32
|
Bounded Sentry request latency is tracked by
|
|
33
|
-
[pm-b9g2cs](../.agents/pm/issues/pm-b9g2cs.toon)
|
|
33
|
+
[pm-b9g2cs](../.agents/pm/issues/pm-b9g2cs.toon), and exact-tag changelog
|
|
34
|
+
stabilization by [pm-e63v1x](../.agents/pm/issues/pm-e63v1x.toon). Dual-phase
|
|
35
|
+
package sizing around Sentry injection is tracked by
|
|
36
|
+
[pm-llbnua](../.agents/pm/issues/pm-llbnua.toon).
|
|
34
37
|
|
|
35
38
|
## Version Policy
|
|
36
39
|
|
|
@@ -278,8 +281,12 @@ The automatic release commit is the sole non-identical-tree derivation. The
|
|
|
278
281
|
gate requires one parent, the canonical release subject and body, an immutable
|
|
279
282
|
`v<version>` tag resolving to the candidate, the complete expected manifest
|
|
280
283
|
inventory, exact old-version to new-version substitutions in every manifest,
|
|
281
|
-
and an exact `Unreleased` changelog-heading replacement.
|
|
282
|
-
|
|
284
|
+
and an exact `Unreleased` changelog-heading replacement. The package-generated
|
|
285
|
+
replacement may be `## <version>` or the historical
|
|
286
|
+
`## <version> - <YYYY-MM-DD>` form, with the date matching the calendar version.
|
|
287
|
+
The complete heading must match and every other changelog byte must remain
|
|
288
|
+
unchanged. The gate then resolves the parent through the same exact or reviewed
|
|
289
|
+
identical-tree analyzer contract.
|
|
283
290
|
Added, deleted, renamed, missing, or otherwise modified paths are refused, as
|
|
284
291
|
are malformed manifests, changelog edits, untagged commits, and parents without
|
|
285
292
|
successful analyzer evidence. The receipt reports
|
|
@@ -333,7 +340,12 @@ The static phase includes `pnpm sdk:surface:check`,
|
|
|
333
340
|
`pnpm benchmark:transport:check`. The packaging phase runs
|
|
334
341
|
`pnpm quality:package-artifact`, which evaluates npm's actual packlist against
|
|
335
342
|
the committed unpacked-size, file-count, required-runtime-file, and forbidden
|
|
336
|
-
source-map budgets.
|
|
343
|
+
source-map budgets. Release additionally reruns the packlist gate immediately
|
|
344
|
+
after Sentry debug-ID injection and before any Sentry upload or finalization,
|
|
345
|
+
using the separately committed `sentry-injected` ceiling. CI constrains the base
|
|
346
|
+
build, publication constrains the exact mutated artifact users install, and a
|
|
347
|
+
rejected package cannot leave finalized observability artifacts. Additive SDK
|
|
348
|
+
exports require a reviewed
|
|
337
349
|
snapshot refresh. A removal or semantic signature change fails until the
|
|
338
350
|
maintainer supplies
|
|
339
351
|
`pnpm sdk:surface:update -- --acknowledge-breaking "<release rationale>"`;
|
|
@@ -353,23 +365,27 @@ git push origin v<version>
|
|
|
353
365
|
`.github/workflows/release.yml` runs on `v*.*.*` tags and handles:
|
|
354
366
|
|
|
355
367
|
- full-history checkout
|
|
356
|
-
- manual `workflow_dispatch` by tag for recovery. An isolated anonymous exact-version probe keeps already-published recovery on the reviewed dispatch-time `main` source; when the immutable tag exists but npm publication never completed, recovery
|
|
368
|
+
- manual `workflow_dispatch` by tag for recovery. An isolated anonymous exact-version probe keeps already-published recovery on the reviewed dispatch-time `main` source; when the immutable tag exists but npm publication never completed, recovery preserves the reviewed package gate and budget in runner-temporary storage before checking out that exact tagged source. The controls inspect the untouched tagged package without becoming part of it, so recovery applies the current fail-closed distribution policy while retaining the original version guard and immutable package bytes.
|
|
357
369
|
- pnpm install with frozen lockfile
|
|
358
370
|
- version policy and tag guard
|
|
359
371
|
- secret scan
|
|
360
372
|
- build, clone-local merge-driver installation, typecheck, test, and coverage
|
|
361
373
|
- generated changelog verification and `pm-changelog` installation before the
|
|
362
374
|
tracker-bearing static gate, so a clean checkout does not misclassify the
|
|
363
|
-
managed extension's linked files as missing.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
375
|
+
managed extension's linked files as missing. Every exact-tag source,
|
|
376
|
+
including an ordinary tag push and recovery of an unpublished immutable tag,
|
|
377
|
+
regenerates only `CHANGELOG.md` with the tagged checkout's canonical package
|
|
378
|
+
script and fails if that operation changes any other tracked source path
|
|
379
|
+
(apart from managed-extension install metadata). Reviewed `main` recovery
|
|
380
|
+
sources retain the non-mutating drift check.
|
|
367
381
|
- static quality gate (shared complexity, duplication, dead/orphan module, file/folder hygiene, source/exported docstring coverage profile)
|
|
368
382
|
- temporary-project compatibility gate against latest published tracker data
|
|
369
383
|
- reliability threshold gate (Sentry severity threshold, bounded to a recent-activity window via `--sentry-window-days` (default `14`, `0` = unbounded) so a stale benign unresolved issue cannot block every scheduled release; Sentry requests use the fail-closed bounded `--sentry-request-timeout-ms` contract (default `120000`, maximum `300000`); `--telemetry-mode` gate policy: `off` | `best-effort` | `required`). Scheduled `auto-release.yml` failures open/update an `Auto Release blocked` GitHub issue so blocked daily releases are never silently skipped.
|
|
370
384
|
- sandboxed `pm` coverage
|
|
371
|
-
-
|
|
372
|
-
-
|
|
385
|
+
- a base npm pack dry run, optional Sentry debug-ID injection, a second
|
|
386
|
+
`sentry-injected` packlist budget over the exact publishable bytes, and only
|
|
387
|
+
then optional Sentry release metadata/upload/finalization and the npx tarball
|
|
388
|
+
smoke test
|
|
373
389
|
- generated release notes from changelog plus sanitized tracker metadata
|
|
374
390
|
- artifact uploads
|
|
375
391
|
- `npm publish --access public --provenance --tag latest`, skipped on retry
|
|
@@ -458,8 +474,10 @@ Use the npm registry package for maintainer global updates. Do not use `npm inst
|
|
|
458
474
|
the existing immutable tag, reapplies the version guard, installs the managed
|
|
459
475
|
changelog extension, regenerates the package changelog with the tagged
|
|
460
476
|
checkout's canonical policy under a tracked-path mutation guard, and permits
|
|
461
|
-
first publication only from that tagged source.
|
|
462
|
-
|
|
477
|
+
first publication only from that tagged source. Ordinary tag-push releases
|
|
478
|
+
use the same guarded regeneration because their tag did not exist when the
|
|
479
|
+
release commit's changelog was prepared. Other registry failures stop before
|
|
480
|
+
source selection or publication.
|
|
463
481
|
- If an immutable published package contains a defect that cannot be repaired
|
|
464
482
|
by rerunning the same tag workflow, document the incident and ship the code
|
|
465
483
|
fix in the next UTC day's release.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# SDK Context Truth Contracts
|
|
2
2
|
|
|
3
3
|
Tracker references: [pm-23xkss](../.agents/pm/issues/pm-23xkss.toon) and
|
|
4
|
-
[pm-r8u2g6](../.agents/pm/issues/pm-r8u2g6.toon)
|
|
4
|
+
[pm-r8u2g6](../.agents/pm/issues/pm-r8u2g6.toon),
|
|
5
|
+
[pm-79gv6q](../.agents/pm/issues/pm-79gv6q.toon), and
|
|
6
|
+
[pm-08mt4k](../.agents/pm/issues/pm-08mt4k.toon).
|
|
5
7
|
|
|
6
8
|
## Agent Quick Context
|
|
7
9
|
|
|
@@ -68,3 +70,24 @@ silently route tracker files through the wrong merge behavior. Run
|
|
|
68
70
|
This policy does not weaken storage, history, merge-fence, or pending-receipt
|
|
69
71
|
checks. It only distinguishes an optional never-installed clone capability
|
|
70
72
|
from a broken capability that the repository appears to rely on.
|
|
73
|
+
|
|
74
|
+
## Population and Focus Are Separate
|
|
75
|
+
|
|
76
|
+
`context.summary.scope` is `matching_items`: lifecycle totals describe all items
|
|
77
|
+
matching the request filters and parent subtree before the focus limit, intent
|
|
78
|
+
projection, and token packing. Without filters this is the workspace population.
|
|
79
|
+
`active_items`, `in_progress`, `open`, and `blocked` use that same population as
|
|
80
|
+
`total_items`, `closed`, and `canceled`. `open` includes active statuses other than
|
|
81
|
+
in-progress; `blocked` is an overlapping classification that includes unresolved
|
|
82
|
+
dependency edges as well as blocked lifecycle states.
|
|
83
|
+
|
|
84
|
+
`summary.returned_focus` reports the bounded focus selection. The existing
|
|
85
|
+
`high_level` and `low_level` counts describe their emitted rows. An orient or
|
|
86
|
+
handoff response limited to one row can therefore still report hundreds of open
|
|
87
|
+
items. `omission_receipt.summary_scope` repeats `matching_items` so a consumer
|
|
88
|
+
reading projection metadata cannot confuse omitted detail with absent work.
|
|
89
|
+
|
|
90
|
+
Never infer a population count from an array length. To visit individual items,
|
|
91
|
+
follow the response's continuation and omission receipts. To schedule work, use
|
|
92
|
+
the shared [execution contracts](SDK_EXECUTION_CONTRACTS.md), which keep human
|
|
93
|
+
input, gates, and containers visible without dispatching them by default.
|