diff --git a/.agents/pm/extensions/.managed-extensions.json b/.agents/pm/extensions/.managed-extensions.json index 9d271bd73..f1607ed18 100644 --- a/.agents/pm/extensions/.managed-extensions.json +++ b/.agents/pm/extensions/.managed-extensions.json @@ -1,6 +1,6 @@ { "version": 1, - "updated_at": "2026-08-03T09:53:27.290Z", + "updated_at": "2026-08-03T15:02:53.911Z", "entries": [ { "name": "pm-changelog", diff --git a/.agents/pm/history/pm-6z0wzf.jsonl b/.agents/pm/history/pm-6z0wzf.jsonl index df8c1bdd1..3af735898 100644 --- a/.agents/pm/history/pm-6z0wzf.jsonl +++ b/.agents/pm/history/pm-6z0wzf.jsonl @@ -17,3 +17,38 @@ {"ts":"2026-08-03T08:53:22.724Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"a213c85617537dcbdcf0c4f1","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T08:53:22.724Z"},{"op":"replace","path":"/metadata/status","value":"open"}],"before_hash":"c9387d2afa2c2d11ff594526aab6215a4e03c292843457084308f479de8decb7","after_hash":"cafc752829691a7b129a1f428141d8e88ad876318cde16b60fe25df239a84fb0","message":"Pause after shipping ownership discovery; retain bundled-exemplar namespace residual"} {"ts":"2026-08-03T08:53:23.297Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"a213c85617537dcbdcf0c4f1","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T08:53:23.297Z"}],"before_hash":"cafc752829691a7b129a1f428141d8e88ad876318cde16b60fe25df239a84fb0","after_hash":"cd8b98dd93ea4bbd4249160b15689ecb795b0a8d1b77925ddc938425a3ce3d19"} {"ts":"2026-08-03T09:06:52.703Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"a213c85617537dcbdcf0c4f1","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-08-03T09:06:52.703Z","author":"harness:codex","text":"PR evidence for delivered ownership-discovery scope: https://github.com/unbraind/pm-cli/pull/880. The canonical item remains open for the separately stated bundled VCS exemplar namespacing residual."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T09:06:52.703Z"}],"before_hash":"cd8b98dd93ea4bbd4249160b15689ecb795b0a8d1b77925ddc938425a3ce3d19","after_hash":"e8033f5d27b0069be18f4c161a3a3280ff6f360d51ba09d2221b5cbb2030f48b"} +{"ts":"2026-08-03T13:22:26.503Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:22:26.503Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#344812f67e28edfc2574ced0"}],"before_hash":"e8033f5d27b0069be18f4c161a3a3280ff6f360d51ba09d2221b5cbb2030f48b","after_hash":"254c6991b38a9d47d818f90289b5e03cbb6f686a7909026311e85c500c7a7260"} +{"ts":"2026-08-03T13:22:27.557Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:22:27.557Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"254c6991b38a9d47d818f90289b5e03cbb6f686a7909026311e85c500c7a7260","after_hash":"4be6890cc4862b58fe45774051ee23b87f91e7c2010594f2c6a9b68507ba6694","message":"Continue residual bundled VCS namespace and health-collision implementation after PR #880"} +{"ts":"2026-08-03T13:31:58.393Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/4/note","value":"public ownership SDK exports"},{"op":"replace","path":"/metadata/files/4/path","value":"src/sdk/index.ts"},{"op":"replace","path":"/metadata/files/3/note","value":"deterministic command ownership projection"},{"op":"replace","path":"/metadata/files/3/path","value":"src/sdk/extension/describe.ts"},{"op":"replace","path":"/metadata/files/2/note","value":"CLI lifecycle result integration"},{"op":"replace","path":"/metadata/files/2/path","value":"src/sdk/extension.ts"},{"op":"replace","path":"/metadata/files/1/note","value":"public command ownership contracts snapshot"},{"op":"replace","path":"/metadata/files/1/path","value":"sdk/public-surface.json"},{"op":"replace","path":"/metadata/files/0/note","value":"collision-free package identity and canonical alias"},{"op":"replace","path":"/metadata/files/0/path","value":"packages/pm-vcs/package.json"},{"op":"add","path":"/metadata/files/5","value":{"path":"tests/unit/extensions/extension-describe.spec.ts","scope":"project","note":"winner and claimant contract coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:31:58.393Z"}],"before_hash":"4be6890cc4862b58fe45774051ee23b87f91e7c2010594f2c6a9b68507ba6694","after_hash":"d7a07d4371ea8b7ca5bc9e15d4b44a9b21985bb5537e6999cd6ecbd4e35572fc"} +{"ts":"2026-08-03T13:31:59.253Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/5/note","value":"public ownership SDK exports"},{"op":"replace","path":"/metadata/files/5/path","value":"src/sdk/index.ts"},{"op":"replace","path":"/metadata/files/4/note","value":"deterministic command ownership projection"},{"op":"replace","path":"/metadata/files/4/path","value":"src/sdk/extension/describe.ts"},{"op":"replace","path":"/metadata/files/3/note","value":"CLI lifecycle result integration"},{"op":"replace","path":"/metadata/files/3/path","value":"src/sdk/extension.ts"},{"op":"replace","path":"/metadata/files/2/note","value":"public command ownership contracts snapshot"},{"op":"replace","path":"/metadata/files/2/path","value":"sdk/public-surface.json"},{"op":"replace","path":"/metadata/files/1/note","value":"collision-free package identity and canonical alias"},{"op":"replace","path":"/metadata/files/1/path","value":"packages/pm-vcs/package.json"},{"op":"replace","path":"/metadata/files/0/note","value":"canonical namespaced commands with internal compatibility spellings"},{"op":"replace","path":"/metadata/files/0/path","value":"packages/pm-vcs/extensions/vcs/index.ts"},{"op":"add","path":"/metadata/files/6","value":{"path":"tests/unit/extensions/extension-describe.spec.ts","scope":"project","note":"winner and claimant contract coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:31:59.253Z"}],"before_hash":"d7a07d4371ea8b7ca5bc9e15d4b44a9b21985bb5537e6999cd6ecbd4e35572fc","after_hash":"f56335a3ac5bcec8a3a78788987d3c367e94a454e348073f1b4a0531edff1861"} +{"ts":"2026-08-03T13:32:00.074Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/6/note","value":"public ownership SDK exports"},{"op":"replace","path":"/metadata/files/6/path","value":"src/sdk/index.ts"},{"op":"replace","path":"/metadata/files/5/note","value":"deterministic command ownership projection"},{"op":"replace","path":"/metadata/files/5/path","value":"src/sdk/extension/describe.ts"},{"op":"replace","path":"/metadata/files/4/note","value":"CLI lifecycle result integration"},{"op":"replace","path":"/metadata/files/4/path","value":"src/sdk/extension.ts"},{"op":"replace","path":"/metadata/files/3/note","value":"public command ownership contracts snapshot"},{"op":"replace","path":"/metadata/files/3/path","value":"sdk/public-surface.json"},{"op":"replace","path":"/metadata/files/2/note","value":"collision-free package identity and canonical alias"},{"op":"replace","path":"/metadata/files/2/path","value":"packages/pm-vcs/package.json"},{"op":"replace","path":"/metadata/files/1/note","value":"namespaced bundled extension identity"},{"op":"replace","path":"/metadata/files/1/path","value":"packages/pm-vcs/extensions/vcs/manifest.json"},{"op":"add","path":"/metadata/files/7","value":{"path":"tests/unit/extensions/extension-describe.spec.ts","scope":"project","note":"winner and claimant contract coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:00.074Z"}],"before_hash":"f56335a3ac5bcec8a3a78788987d3c367e94a454e348073f1b4a0531edff1861","after_hash":"3598190c156e7e520f4c7c5840a1224b97aef7667ce1ef505b911f1a2bbe713c"} +{"ts":"2026-08-03T13:32:00.882Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/8","value":{"path":"tests/unit/packages/vcs-extension.spec.ts","scope":"project","note":"canonical and legacy command acceptance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:00.882Z"}],"before_hash":"3598190c156e7e520f4c7c5840a1224b97aef7667ce1ef505b911f1a2bbe713c","after_hash":"0faaa878c6869f74073cdd6a78df6ce0c94afd2a70e4e4c77571632747ee8678"} +{"ts":"2026-08-03T13:32:01.700Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/8/note","value":"winner and claimant contract coverage"},{"op":"replace","path":"/metadata/files/8/path","value":"tests/unit/extensions/extension-describe.spec.ts"},{"op":"replace","path":"/metadata/files/7/note","value":"bundled catalog and wildcard activation identity coverage"},{"op":"replace","path":"/metadata/files/7/path","value":"tests/unit/extensions/extension-command.spec.ts"},{"op":"add","path":"/metadata/files/9","value":{"path":"tests/unit/packages/vcs-extension.spec.ts","scope":"project","note":"canonical and legacy command acceptance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:01.700Z"}],"before_hash":"0faaa878c6869f74073cdd6a78df6ce0c94afd2a70e4e4c77571632747ee8678","after_hash":"c563f53565b487b7d4f9718e3468eae0b2df52c52012fcb2d3063f6c4dad09c5"} +{"ts":"2026-08-03T13:32:02.588Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/1","value":{"path":"packages/pm-vcs/README.md","scope":"project","note":"canonical install and command migration guidance"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:02.588Z"}],"before_hash":"c563f53565b487b7d4f9718e3468eae0b2df52c52012fcb2d3063f6c4dad09c5","after_hash":"7f448357318a5b50fe4a3208fed4c8dc0e957aeac28d7b6e5ec07051fc480786"} +{"ts":"2026-08-03T13:32:03.512Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/1/note","value":"SDK exemplar namespace assessment"},{"op":"replace","path":"/metadata/docs/1/path","value":"packages/pm-vcs/GAP_REPORT.md"},{"op":"add","path":"/metadata/docs/2","value":{"path":"packages/pm-vcs/README.md","scope":"project","note":"canonical install and command migration guidance"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:03.512Z"}],"before_hash":"7f448357318a5b50fe4a3208fed4c8dc0e957aeac28d7b6e5ec07051fc480786","after_hash":"d11843ca376de5a26c09791e485a353639f8a998657e1415b397f3cf17ecc678"} +{"ts":"2026-08-03T13:32:04.295Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"node scripts/run-tests.mjs test -- tests/unit/packages/vcs-extension.spec.ts tests/unit/extensions/extension-command.spec.ts","scope":"project","timeout_seconds":300}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:04.295Z"}],"before_hash":"d11843ca376de5a26c09791e485a353639f8a998657e1415b397f3cf17ecc678","after_hash":"92c23dd19abc508f807658b816a1d7f4723e29020e6bad89ebe62a350a4d8e8c"} +{"ts":"2026-08-03T13:32:19.851Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-08-03T13:32:19.851Z","author":"harness:codex","text":"TDD evidence: canonical vcs-exemplar command expectations and package identity assertions were updated first; focused package/catalog tests now pass with legacy vcs command compatibility retained at internal tier."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:19.851Z"}],"before_hash":"92c23dd19abc508f807658b816a1d7f4723e29020e6bad89ebe62a350a4d8e8c","after_hash":"92c503524969885415fa7d9c03c0501656083cfea81bfcac7e86fc8bca9d4602"} +{"ts":"2026-08-03T13:51:36.428Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-08-03T13:51:36.428Z","author":"harness:codex","text":"TDD/manual acceptance evidence: package describe now resolves the persisted install alias through managed source provenance and bundled package identity. Focused extension-describe suite passes 20/20, typecheck and build pass, and the original isolated command PM_PATH=/tmp/pm-package-platform.0QLv6q/project/.agents/pm PM_GLOBAL_PATH=/tmp/pm-package-platform.0QLv6q/global/.agents/pm node dist/cli.js package describe vcs-exemplar --project --json returns ok=true, target=vcs-exemplar, total=1, canonical builtin-vcs-sdk-exemplar ownership, and all 14 canonical plus compatibility command paths."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:51:36.428Z"}],"before_hash":"92c503524969885415fa7d9c03c0501656083cfea81bfcac7e86fc8bca9d4602","after_hash":"1445f2a02dce45d86538b04522e5ee1e9b813ec1b50c3b78735313a94fd267b4"} +{"ts":"2026-08-03T13:52:34.472Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-08-03T13:52:34.472Z","author":"harness:codex","text":"Live GitHub cross-check 2026-08-03: GH-832 has a direct pm item .toon link comment; all 23 open repository issues have at least one direct pm .toon link comment; there are zero open PRs, zero Dependabot alerts, zero code-scanning alerts, and zero secret-scanning alerts. Current main CI/Security/CodeQL/Scorecard/CodSpeed runs are green."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:52:34.472Z"}],"before_hash":"1445f2a02dce45d86538b04522e5ee1e9b813ec1b50c3b78735313a94fd267b4","after_hash":"442dcc44a32e69177c44916a105faaace8013e4914b701536b2b872fb74907d4"} +{"ts":"2026-08-03T14:34:03.763Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/9/note","value":"winner and claimant contract coverage"},{"op":"replace","path":"/metadata/files/9/path","value":"tests/unit/extensions/extension-describe.spec.ts"},{"op":"replace","path":"/metadata/files/8/note","value":"bundled catalog and wildcard activation identity coverage"},{"op":"replace","path":"/metadata/files/8/path","value":"tests/unit/extensions/extension-command.spec.ts"},{"op":"replace","path":"/metadata/files/7/note","value":"public ownership SDK exports"},{"op":"replace","path":"/metadata/files/7/path","value":"src/sdk/index.ts"},{"op":"replace","path":"/metadata/files/6/note","value":"deterministic command ownership projection"},{"op":"replace","path":"/metadata/files/6/path","value":"src/sdk/extension/describe.ts"},{"op":"replace","path":"/metadata/files/5/note","value":"CLI lifecycle result integration"},{"op":"replace","path":"/metadata/files/5/path","value":"src/sdk/extension.ts"},{"op":"replace","path":"/metadata/files/4/note","value":"Public loaded-extension install-source alias identity contract"},{"op":"replace","path":"/metadata/files/4/path","value":"src/core/extensions/extension-types.ts"},{"op":"add","path":"/metadata/files/10","value":{"path":"tests/unit/packages/vcs-extension.spec.ts","scope":"project","note":"canonical and legacy command acceptance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:03.763Z"}],"before_hash":"442dcc44a32e69177c44916a105faaace8013e4914b701536b2b872fb74907d4","after_hash":"2eac91e5d05e46bd1ea223ff1cb601f87a8dcc110c987a7a3682cbe3081f8a10"} +{"ts":"2026-08-03T14:34:04.430Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/10/note","value":"winner and claimant contract coverage"},{"op":"replace","path":"/metadata/files/10/path","value":"tests/unit/extensions/extension-describe.spec.ts"},{"op":"replace","path":"/metadata/files/9/note","value":"bundled catalog and wildcard activation identity coverage"},{"op":"replace","path":"/metadata/files/9/path","value":"tests/unit/extensions/extension-command.spec.ts"},{"op":"replace","path":"/metadata/files/8/note","value":"public ownership SDK exports"},{"op":"replace","path":"/metadata/files/8/path","value":"src/sdk/index.ts"},{"op":"replace","path":"/metadata/files/7/note","value":"deterministic command ownership projection"},{"op":"replace","path":"/metadata/files/7/path","value":"src/sdk/extension/describe.ts"},{"op":"replace","path":"/metadata/files/6/note","value":"CLI lifecycle result integration"},{"op":"replace","path":"/metadata/files/6/path","value":"src/sdk/extension.ts"},{"op":"replace","path":"/metadata/files/5/note","value":"Persist managed install identities into loaded extension context"},{"op":"replace","path":"/metadata/files/5/path","value":"src/core/extensions/loader.ts"},{"op":"add","path":"/metadata/files/11","value":{"path":"tests/unit/packages/vcs-extension.spec.ts","scope":"project","note":"canonical and legacy command acceptance coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:04.430Z"}],"before_hash":"2eac91e5d05e46bd1ea223ff1cb601f87a8dcc110c987a7a3682cbe3081f8a10","after_hash":"b7d5dd4cebfe39209d5500804cdb69318fbea2f0fc8a8e60ffab694146b715fb"} +{"ts":"2026-08-03T14:34:05.102Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/2/note","value":"SDK exemplar namespace assessment"},{"op":"replace","path":"/metadata/docs/2/path","value":"packages/pm-vcs/GAP_REPORT.md"},{"op":"replace","path":"/metadata/docs/1/note","value":"ownership policy and discovery workflow"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/EXTENSIONS.md"},{"op":"replace","path":"/metadata/docs/0/note","value":"Generated release-facing namespace and alias resolution entry"},{"op":"replace","path":"/metadata/docs/0/path","value":"CHANGELOG.md"},{"op":"add","path":"/metadata/docs/3","value":{"path":"packages/pm-vcs/README.md","scope":"project","note":"canonical install and command migration guidance"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:05.102Z"}],"before_hash":"b7d5dd4cebfe39209d5500804cdb69318fbea2f0fc8a8e60ffab694146b715fb","after_hash":"7547491eee8505ec3d866be4ab71c4364a099530b28148f79d6a9f575b15c339"} +{"ts":"2026-08-03T14:34:06.957Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-08-03T14:34:06.957Z","author":"harness:codex","text":"Final local verification: repository coverage passes 100/100/100/100 across 425 files and 6,782 tests; full static/docstring/SDK parity/context/token gates pass; packed npx smoke and 88-command package-first dogfood pass. Exact install alias is now a loader-projected SDK identity rather than CLI-only special handling."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:06.957Z"}],"before_hash":"7547491eee8505ec3d866be4ab71c4364a099530b28148f79d6a9f575b15c339","after_hash":"ea838c1f64941cd72d3cccb6ff4fb6924de6bc78c0415e685373773f59d5edef"} +{"ts":"2026-08-03T14:34:37.540Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:37.540Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-msdbyul9-genmgh","kind":"test","status":"passed","started_at":"2026-08-03T14:34:08.910Z","finished_at":"2026-08-03T14:34:37.533Z","recorded_at":"2026-08-03T14:34:37.533Z","passed":2,"failed":0,"skipped":0}]}],"before_hash":"ea838c1f64941cd72d3cccb6ff4fb6924de6bc78c0415e685373773f59d5edef","after_hash":"97107fd297ed4e6a56450a1a294ebd1995aceac644eca6af4a87b92ee5894304","message":"Track test run summary (test-local-msdbyul9-genmgh)"} +{"ts":"2026-08-03T14:35:31.137Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:31.137Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-03T14:35:31.124Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-03T14:35:31.124Z"},{"op":"add","path":"/metadata/close_reason","value":"Delivered collision-free VCS SDK exemplar package and vcs-exemplar namespace with internal legacy command compatibility, loader-projected install-alias discovery, CLI/SDK ownership context, 100% coverage, packed and dogfood acceptance."}],"before_hash":"97107fd297ed4e6a56450a1a294ebd1995aceac644eca6af4a87b92ee5894304","after_hash":"43a58efe3df4ce83466d16b03db1c25873370d9bdf12965ceb322487e78526a6"} +{"ts":"2026-08-03T14:35:31.760Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:31.760Z"}],"before_hash":"43a58efe3df4ce83466d16b03db1c25873370d9bdf12965ceb322487e78526a6","after_hash":"df4e1b77afbe597680192c80be88ec82f9ae67b4ae56be79980998b6d1ddccc1"} +{"ts":"2026-08-03T14:35:49.730Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"The bundled package installs as @unbrained/pm-vcs-sdk-exemplar via vcs-exemplar; canonical vcs-exemplar commands and internal vcs compatibility commands both work, and package describe resolves the install alias with deterministic ownership."},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:49.730Z"},{"op":"add","path":"/metadata/resolution","value":"Namespaced the private VCS SDK exemplar and its canonical commands, retained internal legacy invocations, and projected managed install aliases plus command ownership through loader/describe contracts."}],"before_hash":"df4e1b77afbe597680192c80be88ec82f9ae67b4ae56be79980998b6d1ddccc1","after_hash":"5281c6480c14d5b0f89c28d81d9cb84a7fcd8e59266db986a8e0e2be4ad0786c","message":"Backfill final resolution evidence"} +{"ts":"2026-08-03T14:37:48.835Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-08-03T14:37:48.835Z","author":"harness:codex","text":"PR evidence: https://github.com/unbraind/pm-cli/pull/883 at initial exact head 3a184d480. Awaiting hosted checks and full Greptile/CodeRabbit review."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:37:48.835Z"}],"before_hash":"5281c6480c14d5b0f89c28d81d9cb84a7fcd8e59266db986a8e0e2be4ad0786c","after_hash":"01d4930ec5223be7b436f97b5ddd55af1149ec83affb076bde4b84fbeb767165"} +{"ts":"2026-08-03T14:46:43.498Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"remove","path":"/metadata/completed_at"},{"op":"remove","path":"/metadata/closed_at"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:46:43.498Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"01d4930ec5223be7b436f97b5ddd55af1149ec83affb076bde4b84fbeb767165","after_hash":"7692916ebaa5d7d171a488c394e15ee36341253d74c55a2129eb961f9495a3f6","message":"Reopen for PR #883 exact-head hosted static-gate follow-up"} +{"ts":"2026-08-03T14:46:44.146Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:46:44.146Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#344812f67e28edfc2574ced0"}],"before_hash":"7692916ebaa5d7d171a488c394e15ee36341253d74c55a2129eb961f9495a3f6","after_hash":"0fa66625225ea3bdf6441c27e8ac4e2cfa271550441964571a6e0e86426f9ce6"} +{"ts":"2026-08-03T14:46:44.765Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/11","value":{"created_at":"2026-08-03T14:46:44.765Z","author":"harness:codex","text":"Hosted CI evidence at PR #883 head 98448a77950e: Gates (static) failed only because readManagedExtensionSourcePackages reached complexity 17 against the mandatory maximum 16. Simplified parsed managed-state validation and alias normalization without weakening lint or changing the SDK identity contract; focused ESLint now passes and extension loader/describe tests pass 130/130."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:46:44.765Z"}],"before_hash":"0fa66625225ea3bdf6441c27e8ac4e2cfa271550441964571a6e0e86426f9ce6","after_hash":"d7022d4a9ad41f45b89d029c1bdfa071dd553586d9ceda66d950e2a6317dc351"} +{"ts":"2026-08-03T14:46:54.546Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/tests/1/command","value":"node scripts/run-tests.mjs test -- tests/unit/extensions/extension-loader.spec.ts tests/unit/extensions/extension-describe.spec.ts"},{"op":"add","path":"/metadata/tests/2","value":{"command":"node scripts/run-tests.mjs test -- tests/unit/packages/vcs-extension.spec.ts tests/unit/extensions/extension-command.spec.ts","scope":"project","timeout_seconds":300}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:46:54.546Z"}],"before_hash":"d7022d4a9ad41f45b89d029c1bdfa071dd553586d9ceda66d950e2a6317dc351","after_hash":"a77f7fab2a42aea2e3c282436a94a42e8d929134265bb4aec0805fbe6cdec28d"} +{"ts":"2026-08-03T14:47:55.746Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-msdcfyho-0v80bn","kind":"test","status":"passed","started_at":"2026-08-03T14:47:20.233Z","finished_at":"2026-08-03T14:47:55.740Z","recorded_at":"2026-08-03T14:47:55.740Z","passed":3,"failed":0,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:47:55.746Z"}],"before_hash":"a77f7fab2a42aea2e3c282436a94a42e8d929134265bb4aec0805fbe6cdec28d","after_hash":"754f56bfb6273cfe6488aafa3f528f795c17137640cf70264e3f3446a70f3662","message":"Track test run summary (test-local-msdcfyho-0v80bn)"} +{"ts":"2026-08-03T14:48:06.691Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/12","value":{"created_at":"2026-08-03T14:48:06.691Z","author":"harness:codex","text":"Follow-up verification complete: repo-wide pnpm lint:eslint passes; all three linked sandbox-safe test commands pass (19 + 130 + 141 tests), and the contract-preserving simplification is ready for exact-head hosted rerun."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:48:06.691Z"}],"before_hash":"754f56bfb6273cfe6488aafa3f528f795c17137640cf70264e3f3446a70f3662","after_hash":"42d2b9fbfea9fca7e54ec6aff7f798abc19d80703116ce857b5997f3a5569f77"} +{"ts":"2026-08-03T14:48:07.497Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:48:07.497Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-03T14:48:07.483Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-03T14:48:07.483Z"},{"op":"add","path":"/metadata/close_reason","value":"Resolved PR #883 hosted static complexity regression without weakening the quality gate; repo-wide ESLint and all linked extension/VCS tests pass."}],"before_hash":"42d2b9fbfea9fca7e54ec6aff7f798abc19d80703116ce857b5997f3a5569f77","after_hash":"8c1fa4729ba8ab78fcfe296bbf599ceee61eb7a41406cfd42f61ec3fbda4423a"} +{"ts":"2026-08-03T14:48:08.184Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:48:08.184Z"}],"before_hash":"8c1fa4729ba8ab78fcfe296bbf599ceee61eb7a41406cfd42f61ec3fbda4423a","after_hash":"2bf945e3d3b4dc7ac4aa459b8c659bc7f2530d511d2ccac4669c65d56aaae6b2"} +{"ts":"2026-08-03T14:54:16.348Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"remove","path":"/metadata/completed_at"},{"op":"remove","path":"/metadata/closed_at"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:54:16.348Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"2bf945e3d3b4dc7ac4aa459b8c659bc7f2530d511d2ccac4669c65d56aaae6b2","after_hash":"d21a04eaa4614f856a0087c50534c6f30698f45b811e167757d39cd75c479054","message":"Reopen for PR #883 generated changelog exact-head follow-up"} +{"ts":"2026-08-03T14:54:16.915Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:54:16.915Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#344812f67e28edfc2574ced0"}],"before_hash":"d21a04eaa4614f856a0087c50534c6f30698f45b811e167757d39cd75c479054","after_hash":"fdabac8880da7bac49d167c3b24f14db3ef9a724cb24368902bc348f3c3d49be"} +{"ts":"2026-08-03T14:54:17.503Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/13","value":{"created_at":"2026-08-03T14:54:17.503Z","author":"harness:codex","text":"Second hosted static-gate evidence at exact head c0f92b72d: code lint and all later checks pass; the remaining failure is deterministic CHANGELOG.md drift caused by the just-recorded PM close evidence. Regenerating exclusively through installed pm-changelog 2026.8.3, then checking idempotence."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:54:17.503Z"}],"before_hash":"fdabac8880da7bac49d167c3b24f14db3ef9a724cb24368902bc348f3c3d49be","after_hash":"38ed5d7ca552087f0e5bbc5897edcc38af0a4a3ee90d63fff394c599a9d4b7f7"} +{"ts":"2026-08-03T14:54:22.223Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:54:22.223Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-03T14:54:22.217Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-03T14:54:22.217Z"},{"op":"add","path":"/metadata/close_reason","value":"PR #883 follow-up is fully verified; strict complexity passes and CHANGELOG.md is regenerated from the final closed PM state with pm-changelog 2026.8.3."}],"before_hash":"38ed5d7ca552087f0e5bbc5897edcc38af0a4a3ee90d63fff394c599a9d4b7f7","after_hash":"8acc818209556df8aeb34665f5c84f2f8fbcb71ca401c1914b3ec07c661ba0a7"} +{"ts":"2026-08-03T14:54:22.935Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:54:22.935Z"}],"before_hash":"8acc818209556df8aeb34665f5c84f2f8fbcb71ca401c1914b3ec07c661ba0a7","after_hash":"0497933c40f9574b2fdbabcfb43c35228a77940c265e517cc3689a3947e25b68"} diff --git a/.agents/pm/history/pm-998juj.jsonl b/.agents/pm/history/pm-998juj.jsonl index 0577697d4..a6a2b07fc 100644 --- a/.agents/pm/history/pm-998juj.jsonl +++ b/.agents/pm/history/pm-998juj.jsonl @@ -4,3 +4,34 @@ {"ts":"2026-07-25T07:12:24.197Z","author":"harness:claude-code","author_source":"detected","op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-07-25T07:12:24.186Z","author":"harness:claude-code","text":"Composition evidence: npm view @unbrained/pm-cli dist.unpackedSize=40660446 dist.fileCount=1668. Local dist 31MB total: cli-bundle 12MB (182 chunks), sdk 8.7MB, cli 5.6MB, core 5.4MB, mcp 152K. 491 .js.map files total 20MB; dist/sdk splits as 2.6MB JS, 1.2MB d.ts, 5.0MB maps — the ratio is driven by tsconfig inlineSources:true. scripts sentry:upload runs 'sentry-cli sourcemaps upload --validate dist/' at release, so symbolication already has the maps out-of-band. grep across src, packages, scripts and docs finds zero references to the declared optional peer 'typebox'."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-07-25T07:12:24.197Z"}],"before_hash":"b525cb1326bdc7854fc6f4251f988d1b63c623f506b264ed1e54b2a11a0d27da","after_hash":"1f397eeb66f16c9f8ce5b83600adbfc6ec39222a584c3a9fb02d66ca470c4994"} {"ts":"2026-07-25T21:18:48.882Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","op":"note_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-25T21:18:48.882Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-07-25T21:18:48.881Z","author":"harness:claude-code","text":"Artifact-weight re-measurement 2026-07-25 (evening ecosystem review), measured on the freshly built dist/ tree at version 2026.7.25 (pnpm build, exit 0, \"Already up to date\").\n\ndist/ totals 40MB across 1,460 files. Of that, 526 .map files account for 28MB — roughly 70% of the whole published artifact is sourcemaps. The previously recorded baseline on this item was 40.66MB / 1,668 files with ~20MB of inlineSources sourcemaps, so total size and file count are flat-to-slightly-down while the sourcemap share has grown from about half to about seven tenths. The ratio is moving the wrong way even though the headline number is not.\n\nThat reinforces this item's existing framing rather than changing it: the sourcemaps are already uploaded to Sentry, so shipping them to every npm consumer buys nothing at install time, and they are now the dominant cost by a wide margin. The other two components this item tracks are unchanged — the artifact still carries both the tsc emit and the esbuild bundle, and the dead `typebox` peer is still declared in package.json (line 178, \"typebox\": \"*\", with a peerDependenciesMeta entry) against zero occurrences of the string typebox anywhere under src/. Confirmed by grep this pass.\n\nLive-state cross-check performed at the same time, all healthy: npm dist-tags.latest 2026.7.25 matching the local build, GitHub release v2026.7.25 present, and the last completed runs of CI, CodeQL, CodSpeed, OSSF Scorecard and Security and Script Quality all conclusion=success."}]}],"before_hash":"1f397eeb66f16c9f8ce5b83600adbfc6ec39222a584c3a9fb02d66ca470c4994","after_hash":"d3d6736899835344864b3883d1f72dcebd4bffb658974a53bc0803c137a7cc96"} {"ts":"2026-07-26T05:55:34.770Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","op":"update","patch":[{"op":"add","path":"/metadata/dependencies/4","value":{"id":"pm-u9d0","kind":"implements","created_at":"2026-07-26T05:55:34.518Z"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-07-26T05:55:34.770Z"}],"before_hash":"d3d6736899835344864b3883d1f72dcebd4bffb658974a53bc0803c137a7cc96","after_hash":"6ed88b6cfface89760932fa68327eb95cb6a4a9492dbb222a358a6954255d1a3","message":"Strategic reachability edge: mirror the hierarchy rung into the typed layer so every active item resolves to an outcome milestone through an explainable implements path (pm-bzmeaa invariant), which the parent chain alone cannot express because it terminates at the roadmap root rather than at an outcome"} +{"ts":"2026-08-03T13:22:30.359Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:22:30.359Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#344812f67e28edfc2574ced0"}],"before_hash":"6ed88b6cfface89760932fa68327eb95cb6a4a9492dbb222a358a6954255d1a3","after_hash":"d68f51246c91be890c8f812c3f85b17d5931488dd9ee91742daaaf618b10b61b"} +{"ts":"2026-08-03T13:22:31.253Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:22:31.253Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"d68f51246c91be890c8f812c3f85b17d5931488dd9ee91742daaaf618b10b61b","after_hash":"0b2dc9b1588a2604aeb4af2686a4443f232fb3b8c4cf8f4cf1a9bf0b33d16937","message":"Implement bounded published artifact composition and package size gates"} +{"ts":"2026-08-03T13:32:11.497Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:11.497Z"},{"op":"add","path":"/metadata/files","value":[{"path":"package.json","scope":"project","note":"packlist excludes source maps and removes unused peer"}]}],"before_hash":"0b2dc9b1588a2604aeb4af2686a4443f232fb3b8c4cf8f4cf1a9bf0b33d16937","after_hash":"cadea82074dfc943b183bad726cd2ba2f93b7e9f78e8f263e0160e9305667d82"} +{"ts":"2026-08-03T13:32:12.244Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"pnpm-lock.yaml","scope":"project","note":"unused typebox root peer removal"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:12.244Z"}],"before_hash":"cadea82074dfc943b183bad726cd2ba2f93b7e9f78e8f263e0160e9305667d82","after_hash":"1aa52a26587be7295573f86a45bc20e2b858e6410942aa90dec22a7512b0de42"} +{"ts":"2026-08-03T13:32:13.107Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/2","value":{"path":"scripts/release/package-artifact-gate.mjs","scope":"project","note":"npm packlist artifact contract gate"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:13.107Z"}],"before_hash":"1aa52a26587be7295573f86a45bc20e2b858e6410942aa90dec22a7512b0de42","after_hash":"212283fafe752de27a657bed1ee353bf2f755bea6328bd2b1369c676b224b1d1"} +{"ts":"2026-08-03T13:32:14.017Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/note","value":"reviewable artifact size and contents budgets"},{"op":"replace","path":"/metadata/files/2/path","value":"scripts/release/package-artifact-budget.json"},{"op":"add","path":"/metadata/files/3","value":{"path":"scripts/release/package-artifact-gate.mjs","scope":"project","note":"npm packlist artifact contract gate"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:14.017Z"}],"before_hash":"212283fafe752de27a657bed1ee353bf2f755bea6328bd2b1369c676b224b1d1","after_hash":"ff94bd58f7426ce1ce1160e9302f1ec9ca3bdb15e4c192bee260b57d48a372b1"} +{"ts":"2026-08-03T13:32:14.985Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/3/note","value":"reviewable artifact size and contents budgets"},{"op":"replace","path":"/metadata/files/3/path","value":"scripts/release/package-artifact-budget.json"},{"op":"replace","path":"/metadata/files/2/note","value":"unused typebox root peer removal"},{"op":"replace","path":"/metadata/files/2/path","value":"pnpm-lock.yaml"},{"op":"replace","path":"/metadata/files/1/note","value":"packlist excludes source maps and removes unused peer"},{"op":"replace","path":"/metadata/files/1/path","value":"package.json"},{"op":"replace","path":"/metadata/files/0/note","value":"mandatory PR artifact gate"},{"op":"replace","path":"/metadata/files/0/path","value":".github/workflows/ci.yml"},{"op":"add","path":"/metadata/files/4","value":{"path":"scripts/release/package-artifact-gate.mjs","scope":"project","note":"npm packlist artifact contract gate"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:14.985Z"}],"before_hash":"ff94bd58f7426ce1ce1160e9302f1ec9ca3bdb15e4c192bee260b57d48a372b1","after_hash":"e7df335b9f04ba06036b9d2764bdedc67eaa5bfe1e130ddc4daaf2fee4af92fe"} +{"ts":"2026-08-03T13:32:15.734Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/4/note","value":"reviewable artifact size and contents budgets"},{"op":"replace","path":"/metadata/files/4/path","value":"scripts/release/package-artifact-budget.json"},{"op":"replace","path":"/metadata/files/3/note","value":"unused typebox root peer removal"},{"op":"replace","path":"/metadata/files/3/path","value":"pnpm-lock.yaml"},{"op":"replace","path":"/metadata/files/2/note","value":"packlist excludes source maps and removes unused peer"},{"op":"replace","path":"/metadata/files/2/path","value":"package.json"},{"op":"replace","path":"/metadata/files/1/note","value":"mandatory release artifact gate"},{"op":"replace","path":"/metadata/files/1/path","value":".github/workflows/release.yml"},{"op":"add","path":"/metadata/files/5","value":{"path":"scripts/release/package-artifact-gate.mjs","scope":"project","note":"npm packlist artifact contract gate"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:15.734Z"}],"before_hash":"e7df335b9f04ba06036b9d2764bdedc67eaa5bfe1e130ddc4daaf2fee4af92fe","after_hash":"4ab308e9d4cf53a15f7febd0babec74681ac071844b69b4f7cda2b58a4541e60"} +{"ts":"2026-08-03T13:32:16.548Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/6","value":{"path":"tests/unit/scripts/release/package-artifact-gate.spec.ts","scope":"project","note":"fail-closed artifact negative controls"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:16.548Z"}],"before_hash":"4ab308e9d4cf53a15f7febd0babec74681ac071844b69b4f7cda2b58a4541e60","after_hash":"af6872bbf393403412f54e6ae2635b7d6927c6908ea94f4b3a0854e0755c0189"} +{"ts":"2026-08-03T13:32:17.447Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/6/note","value":"hosted gate enforcement coverage"},{"op":"replace","path":"/metadata/files/6/path","value":"tests/integration/ci-workflow-contract.spec.ts"},{"op":"add","path":"/metadata/files/7","value":{"path":"tests/unit/scripts/release/package-artifact-gate.spec.ts","scope":"project","note":"fail-closed artifact negative controls"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:17.447Z"}],"before_hash":"af6872bbf393403412f54e6ae2635b7d6927c6908ea94f4b3a0854e0755c0189","after_hash":"4bee08bce54525be9683063e72a0b7ecabd1797c89cc45b4e0b02d0316af53e7"} +{"ts":"2026-08-03T13:32:18.243Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:18.243Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/RELEASING.md","scope":"project","note":"artifact budget policy and maintainer workflow"}]}],"before_hash":"4bee08bce54525be9683063e72a0b7ecabd1797c89cc45b4e0b02d0316af53e7","after_hash":"05039a2eae77e2afa6aa4abd41d6752439773b6695797db848e741ffbdd5e64a"} +{"ts":"2026-08-03T13:32:19.022Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:19.022Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/unit/scripts/release/package-artifact-gate.spec.ts tests/integration/ci-workflow-contract.spec.ts","scope":"project","timeout_seconds":240}]}],"before_hash":"05039a2eae77e2afa6aa4abd41d6752439773b6695797db848e741ffbdd5e64a","after_hash":"a90a956ceda048a7a887bd6dc29d7005265d7c7ee899d4b4731ac3cd95b6b649"} +{"ts":"2026-08-03T13:32:21.580Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-03T13:32:21.580Z","author":"harness:codex","text":"TDD evidence: artifact negative controls reject oversize, excessive-file, source-map, missing-runtime-path, and malformed npm pack reports. Live npm pack projection passes at 15,225,239 unpacked bytes, 1,308 files, and zero .map files versus the recorded 40,660,446-byte/1,668-file baseline."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:21.580Z"}],"before_hash":"a90a956ceda048a7a887bd6dc29d7005265d7c7ee899d4b4731ac3cd95b6b649","after_hash":"044a5d23b885cfc6b099fa8e5b9c16a4290efb5fc5fb5c89c5c27609c572e6a5"} +{"ts":"2026-08-03T13:52:35.742Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-03T13:52:35.742Z","author":"harness:codex","text":"Security/dependency evidence 2026-08-03: pnpm audit reports no known vulnerabilities; pnpm security:scan reports no credential-like secrets; GitHub reports zero open Dependabot, code-scanning, and secret-scanning alerts. The package artifact gate independently reports 15,225,239 unpacked bytes, 1,308 files, required runtime/type entrypoints present, and zero source maps."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:52:35.742Z"}],"before_hash":"044a5d23b885cfc6b099fa8e5b9c16a4290efb5fc5fb5c89c5c27609c572e6a5","after_hash":"12f38b859d6817a2bb678be08ee5f9504af7cb49efd1f90556f1118a0e08f57f"} +{"ts":"2026-08-03T14:09:08.822Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/7/note","value":"hosted gate enforcement coverage"},{"op":"replace","path":"/metadata/files/7/path","value":"tests/integration/ci-workflow-contract.spec.ts"},{"op":"replace","path":"/metadata/files/6/note","value":"npm packlist artifact contract gate"},{"op":"replace","path":"/metadata/files/6/path","value":"scripts/release/package-artifact-gate.mjs"},{"op":"replace","path":"/metadata/files/5/note","value":"reviewable artifact size and contents budgets"},{"op":"replace","path":"/metadata/files/5/path","value":"scripts/release/package-artifact-budget.json"},{"op":"replace","path":"/metadata/files/4/note","value":"Prune obsolete hashed bundle chunks after locked graph rebuilds so repeated builds stay package-deterministic"},{"op":"replace","path":"/metadata/files/4/path","value":"scripts/bundle-cli.mjs"},{"op":"add","path":"/metadata/files/8","value":{"path":"tests/unit/scripts/release/package-artifact-gate.spec.ts","scope":"project","note":"fail-closed artifact negative controls"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:09:08.822Z"}],"before_hash":"12f38b859d6817a2bb678be08ee5f9504af7cb49efd1f90556f1118a0e08f57f","after_hash":"c5b1aabaaf7bab8766b7768145fd4cb986c9599186886c6bccd2402d7bc95866"} +{"ts":"2026-08-03T14:09:09.554Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/8/note","value":"Verify all obsolete bundle outputs are removed after a successful graph rebuild"},{"op":"replace","path":"/metadata/files/8/path","value":"tests/unit/scripts/bundle-cli.spec.ts"},{"op":"add","path":"/metadata/files/9","value":{"path":"tests/unit/scripts/release/package-artifact-gate.spec.ts","scope":"project","note":"fail-closed artifact negative controls"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:09:09.554Z"}],"before_hash":"c5b1aabaaf7bab8766b7768145fd4cb986c9599186886c6bccd2402d7bc95866","after_hash":"f5c30f4ee241042b946694be9216695b114a65858036eb9e7ca7071beb5a15e6"} +{"ts":"2026-08-03T14:09:10.202Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-08-03T14:09:10.202Z","author":"harness:codex","text":"Fail-closed gate finding and fix: repeated builds retained fresh obsolete hashed chunks for 10 minutes, causing npm pack to grow from 15,225,239 bytes/1,308 files to 22,043,512 bytes/1,489 files. Bundle output cleanup now occurs immediately after both new graphs complete under the existing build lock (never before rebuild). Focused tests pass 24/24; two consecutive builds now produce a stable passing artifact at 15,228,302 bytes, 1,308 files, zero source maps."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:09:10.202Z"}],"before_hash":"f5c30f4ee241042b946694be9216695b114a65858036eb9e7ca7071beb5a15e6","after_hash":"6f27c7cf47cd01d06c6efa78812f713dcc687c3275461e40d381bec2eede161b"} +{"ts":"2026-08-03T14:34:06.337Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/0/note","value":"Generated release-facing artifact budget entry"},{"op":"replace","path":"/metadata/docs/0/path","value":"CHANGELOG.md"},{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/RELEASING.md","scope":"project","note":"artifact budget policy and maintainer workflow"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:06.337Z"}],"before_hash":"6f27c7cf47cd01d06c6efa78812f713dcc687c3275461e40d381bec2eede161b","after_hash":"70eefe247d80b28eb058e322e61d4d854874bfe36b9e816fde986fa905b97821"} +{"ts":"2026-08-03T14:34:08.224Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-08-03T14:34:08.224Z","author":"harness:codex","text":"Final local verification: full coverage passes 100/100/100/100 (48,230 statements, 34,881 branches, 9,855 functions, 46,764 lines); static/docstring/security/context gates pass; repeated-build artifact is stable at 15,228,302 bytes/1,308 files/zero maps; packed npx and 88-command dogfood pass. Hosted-analysis is the only pre-PR limitation because DeepScan has no result for base SHA d2bf9f146; it will be re-evaluated on the PR exact head."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:08.224Z"}],"before_hash":"70eefe247d80b28eb058e322e61d4d854874bfe36b9e816fde986fa905b97821","after_hash":"51d8b14bb49bb3336ee65f4d7403989d384976ff6439b54e4dac739246a24a55"} +{"ts":"2026-08-03T14:34:53.508Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:53.508Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-msdbz6wt-4n92fd","kind":"test","status":"passed","started_at":"2026-08-03T14:34:45.211Z","finished_at":"2026-08-03T14:34:53.501Z","recorded_at":"2026-08-03T14:34:53.501Z","passed":1,"failed":0,"skipped":0}]}],"before_hash":"51d8b14bb49bb3336ee65f4d7403989d384976ff6439b54e4dac739246a24a55","after_hash":"0767acae1eb6bbbf2dde7b0732349b3a732cccc5d355ba57f025aa7e399faf24","message":"Track test run summary (test-local-msdbz6wt-4n92fd)"} +{"ts":"2026-08-03T14:35:34.390Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:34.390Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-03T14:35:34.373Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-03T14:35:34.373Z"},{"op":"add","path":"/metadata/close_reason","value":"Delivered deterministic package artifact budgets, source-map exclusion, unused peer removal, immediate post-build stale-chunk cleanup, mandatory CI/release gates, 100% coverage, packed and dogfood proof."}],"before_hash":"0767acae1eb6bbbf2dde7b0732349b3a732cccc5d355ba57f025aa7e399faf24","after_hash":"ac0f2ab41685afbf321f63d56a7b87b1aee9968cfc1c473399990637210099a8"} +{"ts":"2026-08-03T14:35:35.199Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:35.199Z"}],"before_hash":"ac0f2ab41685afbf321f63d56a7b87b1aee9968cfc1c473399990637210099a8","after_hash":"0e915379b3597e59f48b2064497b5d7a21aeeb0535528243a92ff6ce413b748b"} +{"ts":"2026-08-03T14:35:51.029Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:51.029Z"},{"op":"add","path":"/metadata/resolution","value":"Excluded source maps from npm artifacts, removed the unused typebox peer, added fail-closed size/content budgets to CI and release, and made locked repeated bundle builds prune obsolete chunks."},{"op":"add","path":"/metadata/expected_result","value":"Published artifacts remain deterministic, bounded, runtime-complete, free of source maps and unused peers, and cannot silently grow across repeated builds."},{"op":"add","path":"/metadata/actual_result","value":"Two consecutive builds pack 1,308 files and 15,228,302 unpacked bytes with zero maps; required CLI/SDK/type entrypoints, 100% coverage, packed smoke, and package-first dogfood pass."}],"before_hash":"0e915379b3597e59f48b2064497b5d7a21aeeb0535528243a92ff6ce413b748b","after_hash":"7915feaeaff01408710f1a2976a956e33ee21711ff5ef99f7c50ac2531391adc","message":"Backfill final resolution evidence"} +{"ts":"2026-08-03T14:37:50.072Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-08-03T14:37:50.072Z","author":"harness:codex","text":"PR evidence: https://github.com/unbraind/pm-cli/pull/883 at initial exact head 3a184d480. Awaiting hosted checks and full Greptile/CodeRabbit review."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:37:50.072Z"}],"before_hash":"7915feaeaff01408710f1a2976a956e33ee21711ff5ef99f7c50ac2531391adc","after_hash":"ef0afc7e4c8035600adde30370d6520e3d5f0d7688085f59b51785b94f778c53"} +{"ts":"2026-08-03T15:01:42.807Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"remove","path":"/metadata/close_reason"},{"op":"remove","path":"/metadata/completed_at"},{"op":"remove","path":"/metadata/closed_at"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:01:42.807Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"ef0afc7e4c8035600adde30370d6520e3d5f0d7688085f59b51785b94f778c53","after_hash":"804a0463f4ed991a1790921a7518c384be8641d1a2475ed3a59b2a47d40de2af","message":"Reopen for PR #883 strict artifact-gate complexity follow-up"} +{"ts":"2026-08-03T15:01:43.397Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:01:43.397Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#344812f67e28edfc2574ced0"}],"before_hash":"804a0463f4ed991a1790921a7518c384be8641d1a2475ed3a59b2a47d40de2af","after_hash":"fea5cbb1d074ce7ac9e12a27677b5ca5d275db488f57d65c77b6373ccd7be4bb"} +{"ts":"2026-08-03T15:01:44.018Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-08-03T15:01:44.018Z","author":"harness:codex","text":"Hosted exact-head static-quality evidence at bcc9b1679: all workflow checks except static pass; CodeFactor-parity identifies validatePackageArtifact at complexity 17 versus the mandatory maximum 16. Refactoring required-path accumulation without suppression or threshold changes."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:01:44.018Z"}],"before_hash":"fea5cbb1d074ce7ac9e12a27677b5ca5d275db488f57d65c77b6373ccd7be4bb","after_hash":"334380616b4ced791ee6453558a57b0b5e196e2643c0e351b6d35e6628be7dd0"} +{"ts":"2026-08-03T15:02:38.633Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"test_run_track","patch":[{"op":"add","path":"/metadata/test_runs/1","value":{"run_id":"test-local-msdcyvq9-7qk5l2","kind":"test","status":"passed","started_at":"2026-08-03T15:02:27.462Z","finished_at":"2026-08-03T15:02:38.625Z","recorded_at":"2026-08-03T15:02:38.625Z","passed":1,"failed":0,"skipped":0}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:02:38.633Z"}],"before_hash":"334380616b4ced791ee6453558a57b0b5e196e2643c0e351b6d35e6628be7dd0","after_hash":"a906bb1744dc64bc33df715dc998e37975ae567c4bfbae6bce5433c3f7bb686a","message":"Track test run summary (test-local-msdcyvq9-7qk5l2)"} +{"ts":"2026-08-03T15:02:39.365Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-08-03T15:02:39.365Z","author":"harness:codex","text":"Exact local static-quality reproduction now passes with zero CodeFactor-complexity violations; focused artifact/workflow tests pass 19/19 and the live npm pack gate passes at 15,228,774 bytes, 1,308 files, zero source maps."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:02:39.365Z"}],"before_hash":"a906bb1744dc64bc33df715dc998e37975ae567c4bfbae6bce5433c3f7bb686a","after_hash":"d230ba00beed986871848ad39b3544c0cef1cd28c69d2c3057988d30daab3ebd"} +{"ts":"2026-08-03T15:02:40.498Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:02:40.498Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-03T15:02:40.473Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-03T15:02:40.473Z"},{"op":"add","path":"/metadata/close_reason","value":"Reduced artifact validator complexity below all mandatory analyzers without suppression; exact static-quality, focused tests, and live pack artifact gate pass."}],"before_hash":"d230ba00beed986871848ad39b3544c0cef1cd28c69d2c3057988d30daab3ebd","after_hash":"9187c2e6566c792d9ac628895e484eccf69b2562100abf5ccde59a761548bd1f"} +{"ts":"2026-08-03T15:02:41.225Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T15:02:41.225Z"}],"before_hash":"9187c2e6566c792d9ac628895e484eccf69b2562100abf5ccde59a761548bd1f","after_hash":"c9edf0546b642d0d105cb71342dc770753c9cad1f5db07aa5ec757c437648ea3"} diff --git a/.agents/pm/history/pm-csuce0.jsonl b/.agents/pm/history/pm-csuce0.jsonl index 692845284..ae573e9b8 100644 --- a/.agents/pm/history/pm-csuce0.jsonl +++ b/.agents/pm/history/pm-csuce0.jsonl @@ -7,3 +7,21 @@ {"ts":"2026-07-27T12:56:05.190Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","agent_instance":"7f54eebf070fafe6ac8ee439","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"}},"op":"update","patch":[{"op":"add","path":"/metadata/dependencies/7","value":{"id":"pm-q91qyd","kind":"related","created_at":"2026-07-27T12:56:04.978Z","author":"harness:claude-code","source_kind":"cli:update:dep","author_source":"detected"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-07-27T12:56:05.190Z"}],"before_hash":"cd24667525899eaf9bcfe7bffd43bdc57c157632daead2046f463925555ecf40","after_hash":"c622fc573cb8cf5e990394a00d32ec68d050c128ad501446c8fbc5fcd31d29b0","message":"Link the tag-without-artifact case to the ledger reconciliation item"} {"ts":"2026-07-27T12:56:15.814Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","agent_instance":"7f54eebf070fafe6ac8ee439","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"}},"op":"update","patch":[{"op":"replace","path":"/metadata/acceptance_criteria","value":"npm latest for @unbrained/pm-cli always resolves to a version that satisfies ordinary stable peer ranges used by first-party packages; Release tooling fails the publish when the calendar ordinal about to be tagged latest would violate the documented peer contract; Package scaffolds and SDK authoring docs state the supported peer range shape for date-based versions; A regression check installs the published latest against a first-party package peer range and fails on incompatibility; A same-day replacement version sorts strictly above the version it replaces and is selected by an ordinary range, so a range resolver never returns the artifact the replacement was cut to supersede, with the published 2026.7.24 and 2026.7.24-3 pair as the regression fixture"},{"op":"replace","path":"/metadata/updated_at","value":"2026-07-27T12:56:15.814Z"}],"before_hash":"c622fc573cb8cf5e990394a00d32ec68d050c128ad501446c8fbc5fcd31d29b0","after_hash":"c97f3971ef41f3d74a67ddf6b1a162d9c334192b440282fbcfda16c590277c5c","message":"Add the ordering-inversion half: latest resolution and range resolution are different paths and only the first is covered today"} {"ts":"2026-07-28T15:15:25.025Z","author":"harness:claude-code","author_source":"detected","agent_harness":"claude-code","agent_instance":"f2bb9c2fdaed86b50270c7c8","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"}},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-07-28T15:15:25.025Z"},{"op":"add","path":"/metadata/risk","value":"high"},{"op":"add","path":"/metadata/confidence","value":90}],"before_hash":"c97f3971ef41f3d74a67ddf6b1a162d9c334192b440282fbcfda16c590277c5c","after_hash":"5b1e28809bcd19390d6f703c622135833d22b9c9ec2fb8393cbaabfb12039f06","message":"Backfill risk and confidence for active-item metadata completeness"} +{"ts":"2026-08-03T13:22:28.533Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:22:28.533Z"},{"op":"add","path":"/metadata/assignee","value":"harness:codex"},{"op":"add","path":"/metadata/claim_principal","value":"harness:codex#344812f67e28edfc2574ced0"}],"before_hash":"5b1e28809bcd19390d6f703c622135833d22b9c9ec2fb8393cbaabfb12039f06","after_hash":"d01c3a19a46933b72477014c50fc79a540009c75a7ad42780535b972d5133338"} +{"ts":"2026-08-03T13:22:29.476Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:22:29.476Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"d01c3a19a46933b72477014c50fc79a540009c75a7ad42780535b972d5133338","after_hash":"13a7874a0ecf783d67656502f14e35f675f6439f3bf23f059f37f73286ea7bc0","message":"Implement SemVer-safe release and first-party peer compatibility contracts"} +{"ts":"2026-08-03T13:32:05.403Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:05.403Z"},{"op":"add","path":"/metadata/files","value":[{"path":"scripts/release-version.mjs","scope":"project","note":"fail-closed same-day stable release diagnostic"}]}],"before_hash":"13a7874a0ecf783d67656502f14e35f675f6439f3bf23f059f37f73286ea7bc0","after_hash":"11e4d426d011082331e89bcac956d053a79f9648c8b1b9c6293c98f05a87743d"} +{"ts":"2026-08-03T13:32:06.308Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/1","value":{"path":"src/sdk/extension/scaffold.ts","scope":"project","note":"stable peer-range authoring scaffold"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:06.308Z"}],"before_hash":"11e4d426d011082331e89bcac956d053a79f9648c8b1b9c6293c98f05a87743d","after_hash":"06231d42d92a94a237ad969ac86b9cc14b36661b3a0b9ad246c902eabbba3326"} +{"ts":"2026-08-03T13:32:07.221Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"add","path":"/metadata/files/2","value":{"path":"tests/unit/scripts/release-version.spec.ts","scope":"project","note":"historical ordinal and same-day refusal regression coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:07.221Z"}],"before_hash":"06231d42d92a94a237ad969ac86b9cc14b36661b3a0b9ad246c902eabbba3326","after_hash":"101ab70cd2e6bfb0f4c104b33210001c857ad9fa1ee3e96bce39b29f6733bbe9"} +{"ts":"2026-08-03T13:32:08.075Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/files/2/note","value":"generated stable peer-range guidance coverage"},{"op":"replace","path":"/metadata/files/2/path","value":"tests/unit/extensions/extension-scaffold-define-guidance.spec.ts"},{"op":"add","path":"/metadata/files/3","value":{"path":"tests/unit/scripts/release-version.spec.ts","scope":"project","note":"historical ordinal and same-day refusal regression coverage"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:08.075Z"}],"before_hash":"101ab70cd2e6bfb0f4c104b33210001c857ad9fa1ee3e96bce39b29f6733bbe9","after_hash":"e53d66e4bc7e69a078ba4c049ac6b90a576c13ae0571e6d48c006a8869bdc2aa"} +{"ts":"2026-08-03T13:32:08.935Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:08.935Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/RELEASING.md","scope":"project","note":"immutable daily release and peer-range policy"}]}],"before_hash":"e53d66e4bc7e69a078ba4c049ac6b90a576c13ae0571e6d48c006a8869bdc2aa","after_hash":"43e29fbe1f081ce315835ed168ee44530efe4ed173879cd8b89da6cd59aa01ea"} +{"ts":"2026-08-03T13:32:09.758Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/1","value":{"path":"docs/SDK.md","scope":"project","note":"first-party package stable peer guidance"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:09.758Z"}],"before_hash":"43e29fbe1f081ce315835ed168ee44530efe4ed173879cd8b89da6cd59aa01ea","after_hash":"8a1666b953820ff96e46cfff034cdd3c59addac28c59443c54844a397b1aa22e"} +{"ts":"2026-08-03T13:32:10.615Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:10.615Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node scripts/run-tests.mjs test -- tests/unit/scripts/release-version.spec.ts tests/unit/extensions/extension-scaffold-define-guidance.spec.ts","scope":"project","timeout_seconds":240}]}],"before_hash":"8a1666b953820ff96e46cfff034cdd3c59addac28c59443c54844a397b1aa22e","after_hash":"dc111ed75a2b826d4941d501f909e6e6cff0044805c9fe9377e4b1f4bacd52d2"} +{"ts":"2026-08-03T13:32:20.785Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-08-03T13:32:20.785Z","author":"harness:codex","text":"TDD evidence: the historical ordinal-producing next-version expectation now fails by design; release-version refuses a second same-day version with stable peer-range recovery guidance, and generated SDK package docs pin the ordinary >= stable range contract."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:32:20.785Z"}],"before_hash":"dc111ed75a2b826d4941d501f909e6e6cff0044805c9fe9377e4b1f4bacd52d2","after_hash":"2050bb3d1b0e74ab8e12affdf96bba2bd7674edd77eaa89c90480e8533348989"} +{"ts":"2026-08-03T13:52:35.107Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-08-03T13:52:35.107Z","author":"harness:codex","text":"Live GitHub cross-check 2026-08-03: GH-681 has a direct pm item .toon link comment. Across the repository all 23 open issues have direct pm .toon link comments; zero open PRs and zero GitHub security/dependency alerts remain before this tranche."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T13:52:35.107Z"}],"before_hash":"2050bb3d1b0e74ab8e12affdf96bba2bd7674edd77eaa89c90480e8533348989","after_hash":"b582983a72784b716491d4aaa2b2fa57830646fe87783626a0ae680790a43af4"} +{"ts":"2026-08-03T14:34:05.727Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/1/note","value":"immutable daily release and peer-range policy"},{"op":"replace","path":"/metadata/docs/1/path","value":"docs/RELEASING.md"},{"op":"replace","path":"/metadata/docs/0/note","value":"Generated release-facing stable version policy entry"},{"op":"replace","path":"/metadata/docs/0/path","value":"CHANGELOG.md"},{"op":"add","path":"/metadata/docs/2","value":{"path":"docs/SDK.md","scope":"project","note":"first-party package stable peer guidance"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:05.727Z"}],"before_hash":"b582983a72784b716491d4aaa2b2fa57830646fe87783626a0ae680790a43af4","after_hash":"76933afdd3e90a28c7ba5d6c96b627725f38377ae45454b97fa4baa53a0c1d54"} +{"ts":"2026-08-03T14:34:07.611Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-08-03T14:34:07.611Z","author":"harness:codex","text":"Final local verification: release-version suite passes 36 tests; full 6,782-test coverage is 100/100/100/100; version policy/sync, release automation contracts, packed npx smoke, and package-first dogfood pass. Same-day production ordinals fail closed and historical ordinal verification remains explicitly rejected."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:07.611Z"}],"before_hash":"76933afdd3e90a28c7ba5d6c96b627725f38377ae45454b97fa4baa53a0c1d54","after_hash":"5f462239c6123220bf9c5b3f341dca6aaae00a25e627fe5a904cef628f1f6548"} +{"ts":"2026-08-03T14:34:44.575Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"test_run_track","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:34:44.575Z"},{"op":"add","path":"/metadata/test_runs","value":[{"run_id":"test-local-msdbz00q-05wj08","kind":"test","status":"passed","started_at":"2026-08-03T14:34:38.120Z","finished_at":"2026-08-03T14:34:44.570Z","recorded_at":"2026-08-03T14:34:44.570Z","passed":1,"failed":0,"skipped":0}]}],"before_hash":"5f462239c6123220bf9c5b3f341dca6aaae00a25e627fe5a904cef628f1f6548","after_hash":"16e1ffdabcfb4476bd02da497480f4ff6eb3a8b2eb3fd3999e419b82930e7780","message":"Track test run summary (test-local-msdbz00q-05wj08)"} +{"ts":"2026-08-03T14:35:32.679Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"close","patch":[{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:32.679Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-03T14:35:32.661Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-03T14:35:32.661Z"},{"op":"add","path":"/metadata/close_reason","value":"Delivered stable SemVer peer-range guidance and fail-closed once-per-day production version policy with historical ordinal verification rejection, complete tests, docs, and release automation proof."}],"before_hash":"16e1ffdabcfb4476bd02da497480f4ff6eb3a8b2eb3fd3999e419b82930e7780","after_hash":"2a45a0b4053718617a809287e2ec6035b5e5c6f94f052af980914b98a83322a9"} +{"ts":"2026-08-03T14:35:33.610Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:33.610Z"}],"before_hash":"2a45a0b4053718617a809287e2ec6035b5e5c6f94f052af980914b98a83322a9","after_hash":"a1e8ebfd296f59511c66f817cd8efdee831f7e9c86c2b2c804fa64030c4a8777"} +{"ts":"2026-08-03T14:35:50.344Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:35:50.344Z"},{"op":"add","path":"/metadata/resolution","value":"Removed same-day production ordinal generation from the active release path, reject historical ordinal verification, and document stable >=date peer ranges in SDK scaffolds."},{"op":"add","path":"/metadata/expected_result","value":"Every automatic production date has at most one stable release and generated packages use peer ranges that npm stable resolution can satisfy."},{"op":"add","path":"/metadata/actual_result","value":"Second same-day production releases now fail closed; stable date versions remain compatible with ordinary peer ranges; historical ordinal tags remain immutable recovery evidence only."}],"before_hash":"a1e8ebfd296f59511c66f817cd8efdee831f7e9c86c2b2c804fa64030c4a8777","after_hash":"6c25a1a289dac542ff0b1ce2740ba67a6f1433786090598be13a63481e167bf2","message":"Backfill final resolution evidence"} +{"ts":"2026-08-03T14:37:49.411Z","author":"harness:codex","author_source":"detected","agent_harness":"codex","agent_instance":"344812f67e28edfc2574ced0","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-08-03T14:37:49.411Z","author":"harness:codex","text":"PR evidence: https://github.com/unbraind/pm-cli/pull/883 at initial exact head 3a184d480. Awaiting hosted checks and full Greptile/CodeRabbit review."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-03T14:37:49.411Z"}],"before_hash":"6c25a1a289dac542ff0b1ce2740ba67a6f1433786090598be13a63481e167bf2","after_hash":"21d26e61b231c300a6b955d51ee98a65276fef6dab881b464f47c4c8af98e9b6"} diff --git a/.agents/pm/issues/pm-6z0wzf.toon b/.agents/pm/issues/pm-6z0wzf.toon index 280248738..d6ded96ff 100644 --- a/.agents/pm/issues/pm-6z0wzf.toon +++ b/.agents/pm/issues/pm-6z0wzf.toon @@ -2,11 +2,13 @@ id: pm-6z0wzf title: "GH-832: package command namespace ownership and collision diagnostics are not discoverable" description: "Track the public-package collision with the bundled private pm-vcs exemplar and define deterministic, inspectable command namespace ownership for extension authors and operators." type: Issue -status: open +status: closed priority: 1 tags: [] created_at: "2026-07-31T07:01:54.979Z" -updated_at: "2026-08-03T09:06:52.703Z" +updated_at: "2026-08-03T14:54:22.935Z" +closed_at: "2026-08-03T14:54:22.217Z" +completed_at: "2026-08-03T14:54:22.217Z" author: "harness:codex" estimated_minutes: 180 acceptance_criteria: Expose command-path and alias ownership through SDK and contracts; fail closed or resolve collisions by a documented deterministic policy naming all claimants; report collisions in health; namespace bundled exemplars without breaking existing invocations; cover scope-preserving package identity and dual-package activation @@ -14,28 +16,53 @@ parent: pm-tnud risk: medium confidence: high severity: high +resolution: "Namespaced the private VCS SDK exemplar and its canonical commands, retained internal legacy invocations, and projected managed install aliases plus command ownership through loader/describe contracts." expected_result: "Package authors can preflight command and alias ownership, activation resolves collisions deterministically, and diagnostics name every claimant without silently dropping sibling commands." -actual_result: A private bundled exemplar and a public package independently claim vcs aliases and command paths; fresh workspaces cannot discover ownership or the collision outcome. +actual_result: "The bundled package installs as @unbrained/pm-vcs-sdk-exemplar via vcs-exemplar; canonical vcs-exemplar commands and internal vcs compatibility commands both work, and package describe resolves the install alias with deterministic ownership." component: extensions/command-registry dependencies[3]{id,kind,created_at,author,source_kind,author_source}: pm-4vwcvq,related_to,"2026-07-31T07:01:54.979Z","harness:codex","cli:create:dep",detected pm-v1yo,related_to,"2026-07-31T07:01:54.979Z","harness:codex","cli:create:dep",detected pm-tnud,implements,"2026-07-31T10:15:13.251Z","harness:codex","cli:update:dep",detected -comments[6]{created_at,author,text}: +comments[14]{created_at,author,text}: "2026-07-31T07:01:54.979Z","harness:codex","Duplicate check evidence: searched all statuses for VCS alias, command registration, and collision claimants; pm-v1yo covers core-group aliases and pm-4vwcvq covers partial activation, while GH-832 is the distinct package-to-package namespace ownership gap. Source: https://github.com/unbraind/pm-cli/issues/832" "2026-07-31T10:15:15.393Z","harness:codex","Organization rationale 2026-07-31: this issue is the discoverability acceptance gap for pm-tnud, not a parallel package epic. Estimate 180m, medium risk, high confidence; the consolidation task now records it as an explicit completion prerequisite." "2026-08-03T07:39:30.021Z","harness:codex","TDD evidence: duplicate handler ownership assertion failed before the describe projection and now reports activation-ordered claimants, the effective final winner, collision state, and last_activated_wins policy through CLI results and public SDK types." "2026-08-03T08:23:07.826Z","harness:codex","Manual acceptance: package describe --json in fresh Node and Bun workspaces reports the installed command-kit handler, project claimant, last_activated_wins policy, winner, and collision=false. The packed consumer imports buildExtensionDescribeResult from @unbrained/pm-cli/sdk." "2026-08-03T08:53:22.136Z","harness:codex","Tranche boundary: this PR delivers deterministic activation-ordered command claimant discovery, winner/collision projection, public SDK types, CLI JSON/Markdown output, documentation, focused tests, and Node/Bun packed acceptance. The item remains open because the acceptance criterion to namespace the bundled VCS exemplar without breaking legacy invocations is intentionally not claimed by this tranche." "2026-08-03T09:06:52.703Z","harness:codex","PR evidence for delivered ownership-discovery scope: https://github.com/unbraind/pm-cli/pull/880. The canonical item remains open for the separately stated bundled VCS exemplar namespacing residual." -files[5]{path,scope,note}: + "2026-08-03T13:32:19.851Z","harness:codex","TDD evidence: canonical vcs-exemplar command expectations and package identity assertions were updated first; focused package/catalog tests now pass with legacy vcs command compatibility retained at internal tier." + "2026-08-03T13:51:36.428Z","harness:codex","TDD/manual acceptance evidence: package describe now resolves the persisted install alias through managed source provenance and bundled package identity. Focused extension-describe suite passes 20/20, typecheck and build pass, and the original isolated command PM_PATH=/tmp/pm-package-platform.0QLv6q/project/.agents/pm PM_GLOBAL_PATH=/tmp/pm-package-platform.0QLv6q/global/.agents/pm node dist/cli.js package describe vcs-exemplar --project --json returns ok=true, target=vcs-exemplar, total=1, canonical builtin-vcs-sdk-exemplar ownership, and all 14 canonical plus compatibility command paths." + "2026-08-03T13:52:34.472Z","harness:codex","Live GitHub cross-check 2026-08-03: GH-832 has a direct pm item .toon link comment; all 23 open repository issues have at least one direct pm .toon link comment; there are zero open PRs, zero Dependabot alerts, zero code-scanning alerts, and zero secret-scanning alerts. Current main CI/Security/CodeQL/Scorecard/CodSpeed runs are green." + "2026-08-03T14:34:06.957Z","harness:codex","Final local verification: repository coverage passes 100/100/100/100 across 425 files and 6,782 tests; full static/docstring/SDK parity/context/token gates pass; packed npx smoke and 88-command package-first dogfood pass. Exact install alias is now a loader-projected SDK identity rather than CLI-only special handling." + "2026-08-03T14:37:48.835Z","harness:codex","PR evidence: https://github.com/unbraind/pm-cli/pull/883 at initial exact head 3a184d480. Awaiting hosted checks and full Greptile/CodeRabbit review." + "2026-08-03T14:46:44.765Z","harness:codex","Hosted CI evidence at PR #883 head 98448a77950e: Gates (static) failed only because readManagedExtensionSourcePackages reached complexity 17 against the mandatory maximum 16. Simplified parsed managed-state validation and alias normalization without weakening lint or changing the SDK identity contract; focused ESLint now passes and extension loader/describe tests pass 130/130." + "2026-08-03T14:48:06.691Z","harness:codex","Follow-up verification complete: repo-wide pnpm lint:eslint passes; all three linked sandbox-safe test commands pass (19 + 130 + 141 tests), and the contract-preserving simplification is ready for exact-head hosted rerun." + "2026-08-03T14:54:17.503Z","harness:codex","Second hosted static-gate evidence at exact head c0f92b72d: code lint and all later checks pass; the remaining failure is deterministic CHANGELOG.md drift caused by the just-recorded PM close evidence. Regenerating exclusively through installed pm-changelog 2026.8.3, then checking idempotence." +files[12]{path,scope,note}: + packages/pm-vcs/extensions/vcs/index.ts,project,canonical namespaced commands with internal compatibility spellings + packages/pm-vcs/extensions/vcs/manifest.json,project,namespaced bundled extension identity + packages/pm-vcs/package.json,project,collision-free package identity and canonical alias sdk/public-surface.json,project,public command ownership contracts snapshot + src/core/extensions/extension-types.ts,project,Public loaded-extension install-source alias identity contract + src/core/extensions/loader.ts,project,Persist managed install identities into loaded extension context src/sdk/extension.ts,project,CLI lifecycle result integration src/sdk/extension/describe.ts,project,deterministic command ownership projection src/sdk/index.ts,project,public ownership SDK exports + tests/unit/extensions/extension-command.spec.ts,project,bundled catalog and wildcard activation identity coverage tests/unit/extensions/extension-describe.spec.ts,project,winner and claimant contract coverage -tests[1]{command,scope,timeout_seconds}: + tests/unit/packages/vcs-extension.spec.ts,project,canonical and legacy command acceptance coverage +tests[3]{command,scope,timeout_seconds}: node scripts/run-tests.mjs test -- tests/unit/extensions/extension-describe.spec.ts,project,240 -docs[1]{path,scope,note}: + node scripts/run-tests.mjs test -- tests/unit/extensions/extension-loader.spec.ts tests/unit/extensions/extension-describe.spec.ts,project,300 + node scripts/run-tests.mjs test -- tests/unit/packages/vcs-extension.spec.ts tests/unit/extensions/extension-command.spec.ts,project,300 +test_runs[2]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-msdbyul9-genmgh,test,passed,"2026-08-03T14:34:08.910Z","2026-08-03T14:34:37.533Z","2026-08-03T14:34:37.533Z",2,0,0 + test-local-msdcfyho-0v80bn,test,passed,"2026-08-03T14:47:20.233Z","2026-08-03T14:47:55.740Z","2026-08-03T14:47:55.740Z",3,0,0 +docs[4]{path,scope,note}: + CHANGELOG.md,project,Generated release-facing namespace and alias resolution entry docs/EXTENSIONS.md,project,ownership policy and discovery workflow + packages/pm-vcs/GAP_REPORT.md,project,SDK exemplar namespace assessment + packages/pm-vcs/README.md,project,canonical install and command migration guidance +close_reason: PR #883 follow-up is fully verified; strict complexity passes and CHANGELOG.md is regenerated from the final closed PM state with pm-changelog 2026.8.3. body: "" diff --git a/.agents/pm/issues/pm-csuce0.toon b/.agents/pm/issues/pm-csuce0.toon index 3bafe53fe..0f49981ff 100644 --- a/.agents/pm/issues/pm-csuce0.toon +++ b/.agents/pm/issues/pm-csuce0.toon @@ -2,17 +2,22 @@ id: pm-csuce0 title: "GH-681: latest calendar ordinal must satisfy stable package peer ranges" description: "Resolve the npm latest channel and peer-range incompatibility where a production calendar ordinal such as 2026.7.24-3 is selected by latest but does not satisfy ordinary stable peer ranges used by pm packages. Coordinate the core release policy, SDK scaffold peer guidance, and affected package repositories without relaxing npm peer validation." type: Issue -status: open +status: closed priority: 1 tags[6]: gh-issue,npm,packages,release,sdk,semver created_at: "2026-07-25T00:15:27.200Z" -updated_at: "2026-07-28T15:15:25.025Z" +updated_at: "2026-08-03T14:37:49.411Z" +closed_at: "2026-08-03T14:35:32.661Z" +completed_at: "2026-08-03T14:35:32.661Z" author: codex-root estimated_minutes: 240 acceptance_criteria: "npm latest for @unbrained/pm-cli always resolves to a version that satisfies ordinary stable peer ranges used by first-party packages; Release tooling fails the publish when the calendar ordinal about to be tagged latest would violate the documented peer contract; Package scaffolds and SDK authoring docs state the supported peer range shape for date-based versions; A regression check installs the published latest against a first-party package peer range and fails on incompatibility; A same-day replacement version sorts strictly above the version it replaces and is selected by an ordinary range, so a range resolver never returns the artifact the replacement was cut to supersede, with the published 2026.7.24 and 2026.7.24-3 pair as the regression fixture" parent: pm-u9d0 risk: high confidence: 90 +resolution: "Removed same-day production ordinal generation from the active release path, reject historical ordinal verification, and document stable >=date peer ranges in SDK scaffolds." +expected_result: Every automatic production date has at most one stable release and generated packages use peer ranges that npm stable resolution can satisfy. +actual_result: Second same-day production releases now fail closed; stable date versions remain compatible with ordinary peer ranges; historical ordinal tags remain immutable recovery evidence only. dependencies[8]: - id: pm-4s24d2 kind: related @@ -41,9 +46,27 @@ dependencies[8]: author: "harness:claude-code" source_kind: "cli:update:dep" author_source: detected -comments[2]{created_at,author,text}: +comments[6]{created_at,author,text}: "2026-07-25T00:15:27.200Z",codex-root,"Duplicate check: searched all statuses for GH-681, npm latest prerelease stable dist-tag peer resolution, and calendar ordinal compatibility. The closed pm-gis0qo owns the intentional production latest-tag policy and pm-4s24d2 owns the one-auto-release-per-day invariant, but neither owns ecosystem peer-range compatibility. This residual cross-package contract is distinct and remains open/unclaimed unless safely included in the active SDK bundle." "2026-07-26T18:30:31.222Z","harness:claude-code","Live registry verification 2026-07-26: npm dist-tags for @unbrained/pm-cli show a single latest tag at 2026.7.26 with no prerelease pointer, and both npx -y @unbrained/pm-cli@latest --version and bunx @unbrained/pm-cli@latest --version resolve, install and print 2026.7.26. The stable-peer-range failure mode described by GH-681 does not reproduce against the current registry state. Full release-health sweep recorded on pm-7zs0." + "2026-08-03T13:32:20.785Z","harness:codex","TDD evidence: the historical ordinal-producing next-version expectation now fails by design; release-version refuses a second same-day version with stable peer-range recovery guidance, and generated SDK package docs pin the ordinary >= stable range contract." + "2026-08-03T13:52:35.107Z","harness:codex","Live GitHub cross-check 2026-08-03: GH-681 has a direct pm item .toon link comment. Across the repository all 23 open issues have direct pm .toon link comments; zero open PRs and zero GitHub security/dependency alerts remain before this tranche." + "2026-08-03T14:34:07.611Z","harness:codex","Final local verification: release-version suite passes 36 tests; full 6,782-test coverage is 100/100/100/100; version policy/sync, release automation contracts, packed npx smoke, and package-first dogfood pass. Same-day production ordinals fail closed and historical ordinal verification remains explicitly rejected." + "2026-08-03T14:37:49.411Z","harness:codex","PR evidence: https://github.com/unbraind/pm-cli/pull/883 at initial exact head 3a184d480. Awaiting hosted checks and full Greptile/CodeRabbit review." notes[1]{created_at,author,text}: "2026-07-27T12:56:03.083Z","harness:claude-code","Evidence 2026-07-27: the same-day suffix is a semver prerelease, so the replacement sorts below the thing it replaces and is unreachable from every ordinary range.\n\nVerified against the live registry rather than by reading the spec. The command npm view for the range caret 2026.7.24 lists 2026.7.24, 2026.7.25, 2026.7.26 and 2026.7.27. It does not list 2026.7.24-3, which is published and installable by exact version. npm excludes it because the hyphen makes it a prerelease of 2026.7.24, and prereleases are outside every range that does not name them.\n\nThree consequences follow, and only the first is currently in this item's acceptance criteria.\n\nOrdering inversion. 2026.7.24-3 is strictly less than 2026.7.24 under semver. The artifact published at 09:46 on 2026-07-24 to replace the one published at 05:51 that morning sorts beneath it. Anyone resolving a range that day received the version the replacement was cut to supersede, and will continue to, permanently. The dist-tag rescue that pm-gis0qo shipped fixes what \"latest\" points at; it cannot fix what a range resolves to, because dist-tags and ranges are different resolution paths.\n\nTwo auto-releases in one day. The retry path is documented as producing a replacement rather than a second release, and the workflow comment says so explicitly. On 2026-07-24 both 2026.7.24 and 2026.7.24-3 reached npm, four hours apart, from the automated pipeline. Whatever the intent, the observable outcome is two published auto-releases on one calendar day, which is the invariant the release policy is supposed to hold.\n\nA tag with no artifact. v2026.7.24-2 exists in git and was never published. That is the general case of the ledger divergence tracked by pm-q91qyd.\n\nThe underlying question this item can settle: a date-based scheme needs a same-day disambiguator that increases monotonically and stays inside the release range. A hyphen suffix cannot do that under semver by construction. A fourth numeric position is not available in semver, so the disambiguator has to be inside one of the three components." +files[4]{path,scope,note}: + scripts/release-version.mjs,project,fail-closed same-day stable release diagnostic + src/sdk/extension/scaffold.ts,project,stable peer-range authoring scaffold + tests/unit/extensions/extension-scaffold-define-guidance.spec.ts,project,generated stable peer-range guidance coverage + tests/unit/scripts/release-version.spec.ts,project,historical ordinal and same-day refusal regression coverage +tests[1]{command,scope,timeout_seconds}: + node scripts/run-tests.mjs test -- tests/unit/scripts/release-version.spec.ts tests/unit/extensions/extension-scaffold-define-guidance.spec.ts,project,240 +test_runs[1]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-msdbz00q-05wj08,test,passed,"2026-08-03T14:34:38.120Z","2026-08-03T14:34:44.570Z","2026-08-03T14:34:44.570Z",1,0,0 +docs[3]{path,scope,note}: + CHANGELOG.md,project,Generated release-facing stable version policy entry + docs/RELEASING.md,project,immutable daily release and peer-range policy + docs/SDK.md,project,first-party package stable peer guidance +close_reason: "Delivered stable SemVer peer-range guidance and fail-closed once-per-day production version policy with historical ordinal verification rejection, complete tests, docs, and release automation proof." body: "" diff --git a/.agents/pm/tasks/pm-998juj.toon b/.agents/pm/tasks/pm-998juj.toon index f06e7370a..bab4506b7 100644 --- a/.agents/pm/tasks/pm-998juj.toon +++ b/.agents/pm/tasks/pm-998juj.toon @@ -2,11 +2,13 @@ id: pm-998juj title: "Published artifact weight: the npm tarball ships 20MB of inline-source sourcemaps plus duplicate tsc and bundle outputs" description: "The published package is 40.66MB unpacked across 1,668 files (npm view @unbrained/pm-cli dist.unpackedSize/dist.fileCount, 2026.7.25). Local dist is 31MB, of which 491 .js.map files account for 20MB — tsconfig.json sets both sourceMap:true and inlineSources:true, so every map embeds the full TypeScript source (dist/sdk alone: 2.6MB JS, 1.2MB d.ts, 5.0MB maps). Those maps are already uploaded to Sentry at release time by the sentry:upload script, which reads dist/ directly, so the tarball copy is redundant for symbolication. On top of that the tarball ships both build outputs: the tsc emit (dist/cli 5.6MB, dist/core 5.4MB, dist/sdk 8.7MB) and the esbuild bundle (dist/cli-bundle 12MB, 182 chunks) that bin/exports actually resolve to. package.json also declares an unused optional peerDependency on 'typebox' — no source, package, script, or doc file references it. Duplicate check: searched install/size/tarball/sourcemap/footprint all-status. pm-oxq2 (closed) removed the nested 25MB host copy from project-scope extension installs and its own body raised 'publish a slim SDK-only package' without acting on it; pm-feecbs owns install-latency policy for the 18 external packages, not the host artifact; pm-hcrmye deliberately kept production source maps and did not examine tarball composition." type: Task -status: open +status: closed priority: 2 tags[5]: "area:release",distribution,ecosystem,packaging,performance created_at: "2026-07-25T07:10:06.541Z" -updated_at: "2026-07-26T05:55:34.770Z" +updated_at: "2026-08-03T15:02:41.225Z" +closed_at: "2026-08-03T15:02:40.473Z" +completed_at: "2026-08-03T15:02:40.473Z" author: unknown estimated_minutes: 300 acceptance_criteria: "The published tarball no longer ships .js.map files (or ships only what symbolication provably needs), with Sentry release symbolication verified against a real captured event after the change; a documented decision records whether both the tsc emit and the esbuild bundle must ship, and any redundant output is dropped from package.json files or justified in writing; the unused typebox peer dependency is removed or a source reference is added; a size assertion in the release gates fails when unpacked size or file count regresses beyond a committed budget; npx and global install still work from a packed tarball (existing smoke:npx and package-first dogfood proofs stay green) and no runtime feature, type, or export is removed" @@ -17,15 +19,45 @@ why_now: The artifact grew from the 25MB recorded in pm-oxq2 to 40.66MB with no parent: pm-u9d0 risk: low confidence: high -dependencies[5]{id,kind,created_at,author,source_kind}: - pm-feecbs,related,"2026-07-25T07:11:55.544Z",null,null - pm-oxq2,discovered_from,"2026-07-25T07:11:55.544Z",null,null - pm-quzx,related,"2026-07-25T07:11:55.544Z",null,null - pm-yse5dt,related,"2026-07-25T07:11:55.544Z",null,null - pm-u9d0,implements,"2026-07-26T05:55:34.518Z",null,null -comments[2]{created_at,author,text}: +resolution: "Excluded source maps from npm artifacts, removed the unused typebox peer, added fail-closed size/content budgets to CI and release, and made locked repeated bundle builds prune obsolete chunks." +expected_result: "Published artifacts remain deterministic, bounded, runtime-complete, free of source maps and unused peers, and cannot silently grow across repeated builds." +actual_result: "Two consecutive builds pack 1,308 files and 15,228,302 unpacked bytes with zero maps; required CLI/SDK/type entrypoints, 100% coverage, packed smoke, and package-first dogfood pass." +dependencies[5]{id,kind,created_at}: + pm-feecbs,related,"2026-07-25T07:11:55.544Z" + pm-oxq2,discovered_from,"2026-07-25T07:11:55.544Z" + pm-quzx,related,"2026-07-25T07:11:55.544Z" + pm-yse5dt,related,"2026-07-25T07:11:55.544Z" + pm-u9d0,implements,"2026-07-26T05:55:34.518Z" +comments[9]{created_at,author,text}: "2026-07-25T07:12:23.380Z","harness:claude-code","Duplicate-check evidence (all-status pm search over install, size, tarball, sourcemap, footprint, packaging): matched closed pm-oxq2, pm-59gj, pm-vnjh, pm-hcrmye and open pm-feecbs, pm-quzx. pm-oxq2 fixed the nested host copy inside project-scope extension installs and explicitly parked the slim-package idea; pm-feecbs governs the 18 external packages, not the host tarball; pm-hcrmye kept production source maps as part of its fix without examining tarball composition. No open item owns host artifact size." "2026-07-25T07:12:24.186Z","harness:claude-code","Composition evidence: npm view @unbrained/pm-cli dist.unpackedSize=40660446 dist.fileCount=1668. Local dist 31MB total: cli-bundle 12MB (182 chunks), sdk 8.7MB, cli 5.6MB, core 5.4MB, mcp 152K. 491 .js.map files total 20MB; dist/sdk splits as 2.6MB JS, 1.2MB d.ts, 5.0MB maps — the ratio is driven by tsconfig inlineSources:true. scripts sentry:upload runs 'sentry-cli sourcemaps upload --validate dist/' at release, so symbolication already has the maps out-of-band. grep across src, packages, scripts and docs finds zero references to the declared optional peer 'typebox'." + "2026-08-03T13:32:21.580Z","harness:codex","TDD evidence: artifact negative controls reject oversize, excessive-file, source-map, missing-runtime-path, and malformed npm pack reports. Live npm pack projection passes at 15,225,239 unpacked bytes, 1,308 files, and zero .map files versus the recorded 40,660,446-byte/1,668-file baseline." + "2026-08-03T13:52:35.742Z","harness:codex","Security/dependency evidence 2026-08-03: pnpm audit reports no known vulnerabilities; pnpm security:scan reports no credential-like secrets; GitHub reports zero open Dependabot, code-scanning, and secret-scanning alerts. The package artifact gate independently reports 15,225,239 unpacked bytes, 1,308 files, required runtime/type entrypoints present, and zero source maps." + "2026-08-03T14:09:10.202Z","harness:codex","Fail-closed gate finding and fix: repeated builds retained fresh obsolete hashed chunks for 10 minutes, causing npm pack to grow from 15,225,239 bytes/1,308 files to 22,043,512 bytes/1,489 files. Bundle output cleanup now occurs immediately after both new graphs complete under the existing build lock (never before rebuild). Focused tests pass 24/24; two consecutive builds now produce a stable passing artifact at 15,228,302 bytes, 1,308 files, zero source maps." + "2026-08-03T14:34:08.224Z","harness:codex","Final local verification: full coverage passes 100/100/100/100 (48,230 statements, 34,881 branches, 9,855 functions, 46,764 lines); static/docstring/security/context gates pass; repeated-build artifact is stable at 15,228,302 bytes/1,308 files/zero maps; packed npx and 88-command dogfood pass. Hosted-analysis is the only pre-PR limitation because DeepScan has no result for base SHA d2bf9f146; it will be re-evaluated on the PR exact head." + "2026-08-03T14:37:50.072Z","harness:codex","PR evidence: https://github.com/unbraind/pm-cli/pull/883 at initial exact head 3a184d480. Awaiting hosted checks and full Greptile/CodeRabbit review." + "2026-08-03T15:01:44.018Z","harness:codex","Hosted exact-head static-quality evidence at bcc9b1679: all workflow checks except static pass; CodeFactor-parity identifies validatePackageArtifact at complexity 17 versus the mandatory maximum 16. Refactoring required-path accumulation without suppression or threshold changes." + "2026-08-03T15:02:39.365Z","harness:codex","Exact local static-quality reproduction now passes with zero CodeFactor-complexity violations; focused artifact/workflow tests pass 19/19 and the live npm pack gate passes at 15,228,774 bytes, 1,308 files, zero source maps." notes[1]{created_at,author,text}: "2026-07-25T21:18:48.881Z","harness:claude-code","Artifact-weight re-measurement 2026-07-25 (evening ecosystem review), measured on the freshly built dist/ tree at version 2026.7.25 (pnpm build, exit 0, \"Already up to date\").\n\ndist/ totals 40MB across 1,460 files. Of that, 526 .map files account for 28MB — roughly 70% of the whole published artifact is sourcemaps. The previously recorded baseline on this item was 40.66MB / 1,668 files with ~20MB of inlineSources sourcemaps, so total size and file count are flat-to-slightly-down while the sourcemap share has grown from about half to about seven tenths. The ratio is moving the wrong way even though the headline number is not.\n\nThat reinforces this item's existing framing rather than changing it: the sourcemaps are already uploaded to Sentry, so shipping them to every npm consumer buys nothing at install time, and they are now the dominant cost by a wide margin. The other two components this item tracks are unchanged — the artifact still carries both the tsc emit and the esbuild bundle, and the dead `typebox` peer is still declared in package.json (line 178, \"typebox\": \"*\", with a peerDependenciesMeta entry) against zero occurrences of the string typebox anywhere under src/. Confirmed by grep this pass.\n\nLive-state cross-check performed at the same time, all healthy: npm dist-tags.latest 2026.7.25 matching the local build, GitHub release v2026.7.25 present, and the last completed runs of CI, CodeQL, CodSpeed, OSSF Scorecard and Security and Script Quality all conclusion=success." +files[10]{path,scope,note}: + .github/workflows/ci.yml,project,mandatory PR artifact gate + .github/workflows/release.yml,project,mandatory release artifact gate + package.json,project,packlist excludes source maps and removes unused peer + pnpm-lock.yaml,project,unused typebox root peer removal + scripts/bundle-cli.mjs,project,Prune obsolete hashed bundle chunks after locked graph rebuilds so repeated builds stay package-deterministic + scripts/release/package-artifact-budget.json,project,reviewable artifact size and contents budgets + scripts/release/package-artifact-gate.mjs,project,npm packlist artifact contract gate + tests/integration/ci-workflow-contract.spec.ts,project,hosted gate enforcement coverage + tests/unit/scripts/bundle-cli.spec.ts,project,Verify all obsolete bundle outputs are removed after a successful graph rebuild + tests/unit/scripts/release/package-artifact-gate.spec.ts,project,fail-closed artifact negative controls +tests[1]{command,scope,timeout_seconds}: + node scripts/run-tests.mjs test -- tests/unit/scripts/release/package-artifact-gate.spec.ts tests/integration/ci-workflow-contract.spec.ts,project,240 +test_runs[2]{run_id,kind,status,started_at,finished_at,recorded_at,passed,failed,skipped}: + test-local-msdbz6wt-4n92fd,test,passed,"2026-08-03T14:34:45.211Z","2026-08-03T14:34:53.501Z","2026-08-03T14:34:53.501Z",1,0,0 + test-local-msdcyvq9-7qk5l2,test,passed,"2026-08-03T15:02:27.462Z","2026-08-03T15:02:38.625Z","2026-08-03T15:02:38.625Z",1,0,0 +docs[2]{path,scope,note}: + CHANGELOG.md,project,Generated release-facing artifact budget entry + docs/RELEASING.md,project,artifact budget policy and maintainer workflow +close_reason: "Reduced artifact validator complexity below all mandatory analyzers without suppression; exact static-quality, focused tests, and live pack artifact gate pass." body: "" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58ddbd38a..d87c3479e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -189,7 +189,7 @@ jobs: pnpm sdk:surface:check pnpm security:scan pnpm lint - npm pack --dry-run + node scripts/release/package-artifact-gate.mjs - name: Enforce discovery and answer token budgets if: matrix.gate == 'static' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13c106c2c..70a86f304 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -160,7 +160,7 @@ jobs: pnpm exec sentry-cli releases finalize "$RELEASE" --org "$SENTRY_ORG" --project "$SENTRY_PROJECT" - name: Packaging smoke check - run: npm pack --dry-run + run: node scripts/release/package-artifact-gate.mjs - name: npx tarball smoke check run: pnpm smoke:npx diff --git a/CHANGELOG.md b/CHANGELOG.md index a94fc73d4..dc61cfce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,18 @@ ### Fixed +- GH-832: package command namespace ownership and collision diagnostics are not discoverable ([pm-6z0wzf](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-6z0wzf.toon)) +- GH-681: latest calendar ordinal must satisfy stable package peer ranges ([pm-csuce0](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-csuce0.toon)) - The model provenance resolver derives the harness session-file path with an incomplete slug encoding, so it silently resolves nothing in any workspace whose path contains an underscore - including this repository ([pm-9gvazz](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-9gvazz.toon)) - GH-878: nested workspace snapshot and help paths are enumerated but not resolvable by structured help ([pm-7wx1f9](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-7wx1f9.toon)) - Warn when custom schema fields collide with MCP transport or tool-specific inputs ([pm-yfdav2](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-yfdav2.toon)) - GH-844: local npm package archives are rejected as install sources ([pm-lw6acw](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-lw6acw.toon)) - The one-release-per-day guard compares a prefix glob against unpadded date keys, so it is correct only by accident of tag creation order and silently skips a real release for any out-of-order tag ([pm-ki67py](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/issues/pm-ki67py.toon)) +### Other + +- Published artifact weight: the npm tarball ships 20MB of inline-source sourcemaps plus duplicate tsc and bundle outputs ([pm-998juj](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/tasks/pm-998juj.toon)) + ## 2026.8.3 - 2026-08-03 ### Added diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 5114befa8..dca17aa29 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -18,7 +18,9 @@ For local progressive-disclosure routing, install `guide-shell` with `pm install Tracked documentation work: [pm-u9d0](../.agents/pm/epics/pm-u9d0.toon), [pm-4s24d2](../.agents/pm/issues/pm-4s24d2.toon), -[pm-39cqqx](../.agents/pm/tasks/pm-39cqqx.toon). +[pm-39cqqx](../.agents/pm/tasks/pm-39cqqx.toon), stable peer compatibility +[pm-csuce0](../.agents/pm/issues/pm-csuce0.toon), and artifact budgets +[pm-998juj](../.agents/pm/tasks/pm-998juj.toon). ## Version Policy @@ -34,10 +36,12 @@ Inspect the next SemVer-compatible calendar version for diagnostics: pnpm version:next ``` -This diagnostic preserves compatibility with historical ordinal tags. Its -output does not override the production pipeline's one-release-per-UTC-day -guard. An explicit pipeline `--version` must equal the current UTC calendar -date; past, future, malformed, and ordinal targets fail before Git inspection. +This diagnostic preserves validation compatibility with historical ordinal +tags, but never proposes one. When today's stable release already exists it +fails with immutable-tag recovery guidance, because an ordinal would be a +SemVer prerelease excluded from ordinary stable package peer ranges. An +explicit pipeline `--version` must equal the current UTC calendar date; past, +future, malformed, and ordinal targets fail before Git inspection. Validate the current package version: @@ -205,7 +209,10 @@ pnpm release:pipeline The static phase includes `pnpm sdk:surface:check`, `pnpm benchmark:sdk-entrypoints:check`, and -`pnpm benchmark:transport:check`. Additive SDK exports require a reviewed +`pnpm benchmark:transport:check`. The packaging phase runs +`pnpm quality:package-artifact`, which evaluates npm's actual packlist against +the committed unpacked-size, file-count, required-runtime-file, and forbidden +source-map budgets. Additive SDK exports require a reviewed snapshot refresh. A removal or semantic signature change fails until the maintainer supplies `pnpm sdk:surface:update -- --acknowledge-breaking ""`; diff --git a/docs/SDK.md b/docs/SDK.md index c0e698248..eb30cbdb3 100644 --- a/docs/SDK.md +++ b/docs/SDK.md @@ -3167,6 +3167,10 @@ is not interpreted as a missing input. native rendering. - Declare only capabilities in use. - Set `pm_min_version` when the package requires SDK or runtime behavior added after older pm releases. +- Declare `@unbrained/pm-cli` as an ordinary stable peer range (the scaffold uses + `>=`). Do not pin or target historical `YYYY.M.D-N` ordinals: + SemVer treats those as prereleases, so normal first-party stable ranges + deliberately exclude them while accepting later daily `YYYY.M.D` releases. - Include examples and failure hints in dynamic commands. - Add `pm package doctor` diagnostics to testing instructions. diff --git a/package.json b/package.json index cc9fc6e8a..f4467100c 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ }, "files": [ "dist/**", + "!dist/**/*.map", "README.md", "CHANGELOG.md", "CONTRIBUTING.md", @@ -129,6 +130,7 @@ "quality:retrieval-eval": "pnpm build && node scripts/release/retrieval-eval-gate.mjs", "quality:retrieval-eval:update": "pnpm build && node scripts/release/retrieval-eval-gate.mjs --update", "quality:gate-registry": "pnpm build && node scripts/release/gate-registry.mjs", + "quality:package-artifact": "pnpm build && node scripts/release/package-artifact-gate.mjs", "quality:docs-skills": "node scripts/release/docs-skills-gate.mjs", "quality:docs-links": "node scripts/release/docs-skills-gate.mjs --links-only", "quality:hosted-analysis": "node scripts/release/hosted-analysis-gate.mjs", @@ -191,14 +193,6 @@ "engines": { "node": ">=22.18.0" }, - "peerDependencies": { - "typebox": "*" - }, - "peerDependenciesMeta": { - "typebox": { - "optional": true - } - }, "dependencies": { "@sentry/node": "10.69.0", "@toon-format/toon": "^4.1.0", diff --git a/packages/pm-vcs/GAP_REPORT.md b/packages/pm-vcs/GAP_REPORT.md index c1dec57d3..d068841af 100644 --- a/packages/pm-vcs/GAP_REPORT.md +++ b/packages/pm-vcs/GAP_REPORT.md @@ -10,7 +10,7 @@ core into Git. | --- | --- | --- | | Domain entities | extension item types and fields | Complete: `Changeset` and `VcsRef` require no core change. | | Domain lifecycle | project profile statuses and workflows | Complete: draft, review, merge, and abandon are schema-owned. | -| Domain verbs | `registerCommand` | Complete: seven structured commands share normal CLI/contracts rendering. | +| Domain verbs | `registerCommand` | Complete: seven collision-free `vcs-exemplar` commands share normal CLI/contracts rendering; internal `vcs` spellings preserve local compatibility. | | Business rule | `beforeCommand` hook | Complete: merge requires an explicit reviewed affirmation. | | Current state | `PmClient` lifecycle/query methods | Complete: command handlers use the same mutation engine as CLI and MCP. | | Point-in-time state | `getItemAt` | Complete: any changeset history version or timestamp is reconstructed without file access. | diff --git a/packages/pm-vcs/README.md b/packages/pm-vcs/README.md index 8cb13008d..fc184bdeb 100644 --- a/packages/pm-vcs/README.md +++ b/packages/pm-vcs/README.md @@ -1,8 +1,8 @@ -# @unbrained/pm-vcs +# @unbrained/pm-vcs-sdk-exemplar -> Tracker: [pm-xtrd](../../.agents/pm/features/pm-xtrd.toon), acceptance story [pm-8ngt](../../.agents/pm/stories/pm-8ngt.toon), atomic SDK transactions [pm-4e12](../../.agents/pm/features/pm-4e12.toon), graph SDK [pm-ju83](../../.agents/pm/features/pm-ju83.toon). +> Tracker: namespace ownership [pm-6z0wzf](../../.agents/pm/issues/pm-6z0wzf.toon), SDK exemplar [pm-xtrd](../../.agents/pm/features/pm-xtrd.toon), acceptance story [pm-8ngt](../../.agents/pm/stories/pm-8ngt.toon), atomic SDK transactions [pm-4e12](../../.agents/pm/features/pm-4e12.toon), graph SDK [pm-ju83](../../.agents/pm/features/pm-ju83.toon). -`pm-vcs` is the first deliberately non-project-management package in the +`pm-vcs-sdk-exemplar` is the first deliberately non-project-management package in the first-party ecosystem. It proves that public pm SDK and extension contracts can model a small version-control domain without importing `src/core`, reading item files directly, or adding VCS policy to the core CLI. @@ -11,8 +11,9 @@ The exemplar provides: - `Changeset` and `VcsRef` custom item types; - `draft -> proposed -> merged|abandoned` domain lifecycle; -- `vcs ref-create`, `vcs create`, `vcs propose`, `vcs merge`, `vcs abandon`, - `vcs show`, and `vcs log` commands; +- collision-free `vcs-exemplar ref-create`, `create`, `propose`, `merge`, + `abandon`, `show`, and `log` commands, with internal `vcs` compatibility + spellings retained for existing local consumers; - a `beforeCommand` hook enforcing explicit reviewed-merge affirmation; - point-in-time changeset reconstruction through `getItemAt`; - a durable, optimistic, append-only `commits_to` relationship stream projected @@ -23,10 +24,10 @@ The exemplar provides: ## Install and stage the domain ```bash -pm install vcs --project +pm install vcs-exemplar --project pm profile apply vcs pm package doctor --project --isolated --detail deep --json -pm contracts --command "vcs merge" --flags-only --json +pm contracts --command "vcs-exemplar merge" --flags-only --json ``` The package registers live types and fields globally, so the manifest does not @@ -36,18 +37,18 @@ the `Changeset` transition graph idempotently. ## End-to-end changeset flow ```bash -pm vcs ref-create main --author demo -pm vcs create "Add durable projection" --ref --tree-hash sha256:abc --author demo -pm vcs propose --author demo -pm vcs show --at 1 -pm vcs merge --ref --reviewed --author demo -pm vcs log +pm vcs-exemplar ref-create main --author demo +pm vcs-exemplar create "Add durable projection" --ref --tree-hash sha256:abc --author demo +pm vcs-exemplar propose --author demo +pm vcs-exemplar show --at 1 +pm vcs-exemplar merge --ref --reviewed --author demo +pm vcs-exemplar log ``` -`vcs show --at` reconstructs immutable item history. `vcs log` independently +`vcs-exemplar show --at` reconstructs immutable item history. `vcs-exemplar log` independently projects the package-owned relationship JSONL stream, proving that current item state and graph event state are both rebuildable from public SDK contracts. -`vcs merge` publishes success only after its SDK transaction journal commits; +`vcs-exemplar merge` publishes success only after its SDK transaction journal commits; ordinary failures compensate in reverse order, and retrying the same merge id resumes any interrupted forward or compensation phase. diff --git a/packages/pm-vcs/extensions/vcs/index.ts b/packages/pm-vcs/extensions/vcs/index.ts index 8eacc1694..4e334970f 100644 --- a/packages/pm-vcs/extensions/vcs/index.ts +++ b/packages/pm-vcs/extensions/vcs/index.ts @@ -25,13 +25,19 @@ import type { /** Declarative package manifest consumed by the extension loader. */ export const manifest = { - name: "builtin-vcs-exemplar", + name: "builtin-vcs-sdk-exemplar", version: "0.1.0", entry: "./index.js", priority: 0, capabilities: ["commands", "schema", "hooks"], }; +/** Collision-free command root advertised by the bundled SDK exemplar. */ +export const VCS_COMMAND_NAMESPACE = "vcs-exemplar"; + +/** Compatibility command root retained for existing local exemplar consumers. */ +export const VCS_LEGACY_COMMAND_NAMESPACE = "vcs"; + /** Domain types contributed by the VCS exemplar. */ export const VCS_ITEM_TYPES = [ { @@ -636,16 +642,16 @@ const ID_ARGUMENT = [ /** Build every VCS domain command definition from one contract table. */ export function buildVcsCommands(): CommandDefinition[] { - return [ + const canonicalCommands: CommandDefinition[] = [ { - name: "vcs ref-create", + name: `${VCS_COMMAND_NAMESPACE} ref-create`, action: "vcs-ref-create", description: "Create a VCS ref through the public pm lifecycle SDK.", arguments: [{ name: "name", required: true, description: "Ref name." }], run: runRefCreate, }, { - name: "vcs create", + name: `${VCS_COMMAND_NAMESPACE} create`, action: "vcs-create", description: "Create a draft changeset.", arguments: [ @@ -669,14 +675,14 @@ export function buildVcsCommands(): CommandDefinition[] { run: runChangesetCreate, }, { - name: "vcs propose", + name: `${VCS_COMMAND_NAMESPACE} propose`, action: "vcs-propose", description: "Move a draft changeset into review.", arguments: ID_ARGUMENT, run: (context) => transitionChangeset(context, "proposed"), }, { - name: "vcs merge", + name: `${VCS_COMMAND_NAMESPACE} merge`, action: "vcs-merge", description: "Merge a reviewed changeset into a ref.", arguments: ID_ARGUMENT, @@ -697,14 +703,14 @@ export function buildVcsCommands(): CommandDefinition[] { run: runChangesetMerge, }, { - name: "vcs abandon", + name: `${VCS_COMMAND_NAMESPACE} abandon`, action: "vcs-abandon", description: "Retire a draft or proposed changeset.", arguments: ID_ARGUMENT, run: (context) => transitionChangeset(context, "abandoned"), }, { - name: "vcs show", + name: `${VCS_COMMAND_NAMESPACE} show`, action: "vcs-show", description: "Read current or point-in-time changeset state.", arguments: ID_ARGUMENT, @@ -714,17 +720,33 @@ export function buildVcsCommands(): CommandDefinition[] { run: runChangesetShow, }, { - name: "vcs log", + name: `${VCS_COMMAND_NAMESPACE} log`, action: "vcs-log", description: "Project the immutable merge relationship stream.", run: runVcsLog, }, ]; + return [ + ...canonicalCommands, + ...canonicalCommands.map((command) => ({ + ...command, + name: command.name.replace( + VCS_COMMAND_NAMESPACE, + VCS_LEGACY_COMMAND_NAMESPACE, + ), + description: `${command.description} Legacy compatibility spelling; prefer pm ${command.name}.`, + tier: "internal" as const, + })), + ]; } /** Hook-enforced merge rule: domain merges require an explicit review affirmation. */ export function enforceVcsMergePolicy(context: BeforeCommandHookContext): void { - if (context.command !== "vcs merge") return; + if ( + context.command !== `${VCS_COMMAND_NAMESPACE} merge` && + context.command !== `${VCS_LEGACY_COMMAND_NAMESPACE} merge` + ) + return; if (context.options?.reviewed !== true) throw new TypeError("vcs merge requires --reviewed"); } diff --git a/packages/pm-vcs/extensions/vcs/manifest.json b/packages/pm-vcs/extensions/vcs/manifest.json index 51813b883..e2b9e8dc6 100644 --- a/packages/pm-vcs/extensions/vcs/manifest.json +++ b/packages/pm-vcs/extensions/vcs/manifest.json @@ -1,5 +1,5 @@ { - "name": "builtin-vcs-exemplar", + "name": "builtin-vcs-sdk-exemplar", "version": "0.1.0", "entry": "./index.ts", "priority": 0, diff --git a/packages/pm-vcs/package.json b/packages/pm-vcs/package.json index e715fcbaa..acd4efe88 100644 --- a/packages/pm-vcs/package.json +++ b/packages/pm-vcs/package.json @@ -1,5 +1,5 @@ { - "name": "@unbrained/pm-vcs", + "name": "@unbrained/pm-vcs-sdk-exemplar", "version": "2026.8.3", "private": true, "type": "module", @@ -22,7 +22,7 @@ ], "pm": { "aliases": [ - "vcs" + "vcs-exemplar" ], "extensions": [ "extensions/vcs" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7002a8e82..5ed55753c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,9 +41,6 @@ importers: tar: specifier: 7.5.22 version: 7.5.22 - typebox: - specifier: '*' - version: 1.3.7 devDependencies: '@codspeed/vitest-plugin': specifier: ^5.7.1 @@ -1621,9 +1618,6 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - typebox@1.3.7: - resolution: {integrity: sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg==} - typescript-eslint@8.65.0: resolution: {integrity: sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3184,8 +3178,6 @@ snapshots: type-fest@4.41.0: {} - typebox@1.3.7: {} - typescript-eslint@8.65.0(eslint@10.8.0(jiti@2.7.0))(typescript@6.0.3): dependencies: '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0))(typescript@6.0.3) diff --git a/scripts/bundle-cli.mjs b/scripts/bundle-cli.mjs index 228a8e021..3196ae2eb 100644 --- a/scripts/bundle-cli.mjs +++ b/scripts/bundle-cli.mjs @@ -2,7 +2,6 @@ import { createHash } from "node:crypto"; import { - lstat, mkdir, readdir, readFile, @@ -46,7 +45,6 @@ const binPath = path.join(repoRoot, "dist", "cli.js"); const lockRetryMs = 250; const lockTimeoutMs = 120_000; const staleLockMs = 10 * 60_000; -const bundleStaleRetentionMs = 10 * 60_000; const bundleManifestPath = path.join(outputDir, "bundle-manifest.json"); export function sleep(ms) { @@ -151,17 +149,10 @@ export async function removeStaleBundleFiles(outputs) { ), ); const existingFiles = await collectFiles(outputDir); - const now = Date.now(); await Promise.all( existingFiles .filter((filePath) => !expectedFiles.has(filePath)) - .map(async (filePath) => { - const fileStats = await lstat(filePath).catch(() => null); - if (!fileStats || now - fileStats.mtimeMs < bundleStaleRetentionMs) { - return; - } - await unlink(filePath).catch(() => {}); - }), + .map((filePath) => unlink(filePath).catch(() => {})), ); } @@ -221,7 +212,9 @@ function bundleOptions(selectedEntryPoints, chunkNames) { export async function main() { // Do not delete the live bundle before rebuilding. Agents often run docs, // dogfood, and build gates concurrently in one checkout; removing this folder - // creates a transient broken `dist/cli.js` runtime. + // creates a transient broken `dist/cli.js` runtime. Once both new graphs are + // complete under the build lock, obsolete hashed chunks are safe to prune and + // must not leak into repeated-build package artifacts. const releaseBundleBuildLock = await acquireBundleBuildLock(); try { const primaryBuildResult = await build( diff --git a/scripts/release-version.mjs b/scripts/release-version.mjs index a81e37fc7..6746111bf 100644 --- a/scripts/release-version.mjs +++ b/scripts/release-version.mjs @@ -18,8 +18,8 @@ function usage() { node scripts/release-version.mjs next [--date ] Rules: - - Version format: YYYY.M.D or YYYY.M.D-N - - N is the release number for that day and must be >= 2 when present + - New production versions use YYYY.M.D exactly once per UTC day + - Historical YYYY.M.D-N tags remain valid for immutable recovery only - Month/day must be valid calendar values `); } @@ -163,7 +163,9 @@ function nextVersionForDate(packageName, dateKey) { if (releasesOnDate.length === 0) { return dateKey; } - return `${dateKey}-${releasesOnDate.length + 1}`; + fail( + `Release already exists for ${dateKey}; same-day ordinal releases are SemVer prereleases and cannot satisfy stable package peer ranges. Recover the immutable existing tag or wait for the next UTC day.`, + ); } function parseFlags(args) { @@ -226,12 +228,12 @@ function runCheck(flags) { ); } - const expectedNext = nextVersionForDate(pkg.name, expectedDate); - if (pkg.version !== expectedNext) { + if (parsedVersion.ordinal !== null) { fail( - `Version sequencing mismatch: package.json has ${pkg.version}, expected next release version ${expectedNext}.`, + `Version sequencing mismatch: ${pkg.version} is a historical ordinal; new releases must use the stable ${expectedDate} version.`, ); } + nextVersionForDate(pkg.name, expectedDate); } console.log(`Version policy check passed (${pkg.version}).`); diff --git a/scripts/release/package-artifact-budget.json b/scripts/release/package-artifact-budget.json new file mode 100644 index 000000000..6c09c709e --- /dev/null +++ b/scripts/release/package-artifact-budget.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "max_unpacked_bytes": 20000000, + "max_file_count": 1800, + "forbidden_suffixes": [".map"], + "required_paths": [ + "dist/cli.js", + "dist/cli-bundle/sdk.js", + "dist/sdk/index.d.ts", + "package.json" + ] +} diff --git a/scripts/release/package-artifact-gate.mjs b/scripts/release/package-artifact-gate.mjs new file mode 100644 index 000000000..58005a9b8 --- /dev/null +++ b/scripts/release/package-artifact-gate.mjs @@ -0,0 +1,78 @@ +#!/usr/bin/env node + +/** + * Fail-closed npm artifact composition and size gate. + * + * Tracker: pm-998juj. The gate inspects npm's own packlist projection, so its + * verdict covers the artifact users actually install instead of the build tree. + */ +import { execFileSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +/** Validate one npm pack report against the committed distribution budget. */ +export function validatePackageArtifact(report, budget) { + if (!Array.isArray(report) || report.length !== 1) { + throw new TypeError("npm pack must return exactly one package report"); + } + const artifact = report[0]; + if ( + typeof artifact !== "object" || + artifact === null || + !Array.isArray(artifact.files) || + typeof artifact.unpackedSize !== "number" + ) { + throw new TypeError("npm pack report is missing files or unpackedSize"); + } + const paths = artifact.files + .map((file) => + typeof file === "object" && file !== null && typeof file.path === "string" + ? file.path + : "", + ) + .filter(Boolean); + const violations = []; + if (artifact.unpackedSize > budget.max_unpacked_bytes) { + violations.push( + `unpacked_size:${artifact.unpackedSize}>${budget.max_unpacked_bytes}`, + ); + } + if (paths.length > budget.max_file_count) { + violations.push(`file_count:${paths.length}>${budget.max_file_count}`); + } + for (const suffix of budget.forbidden_suffixes) { + const matches = paths.filter((file) => file.endsWith(suffix)); + if (matches.length > 0) { + violations.push(`forbidden_suffix:${suffix}:${matches.length}`); + } + } + violations.push( + ...budget.required_paths + .filter((required) => !paths.includes(required)) + .map((required) => `required_path_missing:${required}`), + ); + if (violations.length > 0) { + throw new Error(`Package artifact gate failed:\n${violations.join("\n")}`); + } + return { + ok: true, + package: artifact.name, + version: artifact.version, + unpacked_size: artifact.unpackedSize, + file_count: paths.length, + forbidden_suffixes: budget.forbidden_suffixes, + }; +} + +const scriptRoot = path.dirname(fileURLToPath(import.meta.url)); +const budget = JSON.parse( + readFileSync(path.join(scriptRoot, "package-artifact-budget.json"), "utf8"), +); +const output = execFileSync( + process.platform === "win32" ? "npm.cmd" : "npm", + ["pack", "--dry-run", "--json", "--ignore-scripts"], + { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }, +); +const report = JSON.parse(output); +console.log(JSON.stringify(validatePackageArtifact(report, budget), null, 2)); diff --git a/src/core/extensions/extension-types.ts b/src/core/extensions/extension-types.ts index 605697bea..95ea09df5 100644 --- a/src/core/extensions/extension-types.ts +++ b/src/core/extensions/extension-types.ts @@ -296,6 +296,8 @@ export interface EffectiveExtension { name: string; /** Value that configures or reports source package for this contract. */ source_package?: string; + /** Install-source identities that can resolve this extension through package lifecycle commands. */ + source_aliases?: string[]; /** Value that configures or reports version for this contract. */ version: string; /** Value that configures or reports entry for this contract. */ @@ -1659,6 +1661,8 @@ export interface ExtensionCandidate { manifest: ExtensionManifest; /** Value that configures or reports source package for this contract. */ source_package?: string; + /** Install-source identities that can resolve this extension through package lifecycle commands. */ + source_aliases?: string[]; } /** Documents the extension layer scan result payload exchanged by command, SDK, and package integrations. */ diff --git a/src/core/extensions/loader.ts b/src/core/extensions/loader.ts index cd8109858..e0050d716 100644 --- a/src/core/extensions/loader.ts +++ b/src/core/extensions/loader.ts @@ -641,6 +641,9 @@ function summarizeCandidate(candidate: ExtensionCandidate): EffectiveExtension { if (candidate.source_package) { summary.source_package = candidate.source_package; } + if (candidate.source_aliases) { + summary.source_aliases = [...candidate.source_aliases]; + } return summary; } @@ -650,10 +653,15 @@ function normalizeManagedSourcePackage(value: unknown): string | undefined { : undefined; } +interface ManagedExtensionSourceIdentity { + package_name?: string; + aliases: string[]; +} + async function readManagedExtensionSourcePackages( extensionsRoot: string, -): Promise> { - const packages = new Map(); +): Promise> { + const packages = new Map(); try { const parsed = JSON.parse( await fs.readFile( @@ -661,36 +669,41 @@ async function readManagedExtensionSourcePackages( "utf8", ), ) as unknown; - if ( - typeof parsed !== "object" || - parsed === null || - !Array.isArray((parsed as { entries?: unknown }).entries) - ) { + const managedExtensions = asRecordLoose(parsed); + const entries = managedExtensions?.entries; + if (!Array.isArray(entries)) { return packages; } - for (const entry of (parsed as { entries: unknown[] }).entries) { + for (const entry of entries) { if (typeof entry !== "object" || entry === null) { continue; } const record = entry as { directory?: unknown; name?: unknown; - source?: { package?: unknown }; + source?: { input?: unknown; name?: unknown; package?: unknown }; }; const sourcePackage = normalizeManagedSourcePackage( record.source?.package, ); - if (!sourcePackage) { + const aliases = [record.source?.input, record.source?.name, sourcePackage] + .map((value) => normalizeManagedSourcePackage(value)) + .filter((value): value is string => value !== undefined); + if (aliases.length === 0) { continue; } + const identity: ManagedExtensionSourceIdentity = { + aliases: [...new Set(aliases)], + ...(sourcePackage ? { package_name: sourcePackage } : {}), + }; if ( typeof record.directory === "string" && record.directory.trim().length > 0 ) { - packages.set(`directory:${record.directory.trim()}`, sourcePackage); + packages.set(`directory:${record.directory.trim()}`, identity); } if (typeof record.name === "string" && record.name.trim().length > 0) { - packages.set(`name:${record.name.trim()}`, sourcePackage); + packages.set(`name:${record.name.trim()}`, identity); } } } catch { @@ -849,7 +862,7 @@ async function scanExtensionDirectory( directory: string, enabled: Set, disabled: Set, - managedSourcePackages: ReadonlyMap, + managedSourcePackages: ReadonlyMap, pmMaxVersionExceededMode: PmMaxVersionExceededMode, ): Promise { const extensionDir = path.join(extensionsRoot, directory); @@ -917,7 +930,7 @@ async function scanExtensionDirectory( entryExists && pmVersionCompatibility.allowed && pmMaxVersionCompatibility.allowed; - const sourcePackage = + const sourceIdentity = managedSourcePackages.get(`directory:${directory}`) ?? managedSourcePackages.get(`name:${manifest.name}`); @@ -943,7 +956,8 @@ async function scanExtensionDirectory( manifest_path: manifestPath, entry_path: entryPath, manifest, - source_package: sourcePackage, + source_package: sourceIdentity?.package_name, + source_aliases: sourceIdentity?.aliases, } : null, }; @@ -3604,7 +3618,14 @@ export const _testOnlyLoader = { parseComparableVersion, parseManifest, readCurrentPmCliVersion, - readManagedExtensionSourcePackages, + readManagedExtensionSourcePackages: async (extensionsRoot: string) => + new Map( + [...(await readManagedExtensionSourcePackages(extensionsRoot))] + .filter((entry): entry is [string, ManagedExtensionSourceIdentity & { package_name: string }] => + typeof entry[1].package_name === "string", + ) + .map(([key, identity]) => [key, identity.package_name]), + ), resolveExtensionImportHref, resolveCurrentPmCliVersion, resolveCommandDefinitionAction, diff --git a/src/sdk/extension/describe.ts b/src/sdk/extension/describe.ts index a2e937cf6..d6f34ad24 100644 --- a/src/sdk/extension/describe.ts +++ b/src/sdk/extension/describe.ts @@ -161,10 +161,10 @@ function buildExtensionCommandOwnership( * provided only the case-insensitively matching extensions are described and the * `union` is scoped to that resolved name set; otherwise every loaded extension contributes. * A target may name either the extension itself or its source npm package - * (`source_package`), so agents can reuse the `package_name` values surfaced by - * `pm extension list` / install discovery without a second lookup. An unmatched - * `target` yields an empty `extensions` array -- the caller decides whether that - * is a not-found error. + * (`source_package`) or any persisted install-source identity (`source_aliases`), + * so agents can reuse the exact catalog, local, GitHub, or npm spelling passed + * to install without a second lookup. An unmatched `target` yields an empty + * `extensions` array -- the caller decides whether that is a not-found error. */ export function buildExtensionDescribeResult( target: string | undefined, @@ -218,7 +218,11 @@ export function buildExtensionDescribeResult( normalizedTarget || (typeof entry.source_package === "string" && normalizeExtensionNameForMatch(entry.source_package) === - normalizedTarget), + normalizedTarget) || + (entry.source_aliases ?? []).some( + (alias) => + normalizeExtensionNameForMatch(alias) === normalizedTarget, + ), ) .map((entry) => normalizeExtensionNameForMatch(entry.name)) .concat(normalizedTarget), diff --git a/src/sdk/extension/scaffold.ts b/src/sdk/extension/scaffold.ts index 0ce7b7ff4..6c0302cc9 100644 --- a/src/sdk/extension/scaffold.ts +++ b/src/sdk/extension/scaffold.ts @@ -2798,6 +2798,7 @@ export function buildStarterExtensionScaffoldFiles( ...buildScaffoldActivationReadmeSection(capability, "package"), "", "## Compatibility Bounds", + `- \`peerDependencies["@unbrained/pm-cli"]\` uses the stable range \`>=${SCAFFOLD_PM_MIN_VERSION}\`. Keep a normal stable range instead of pinning a date ordinal: SemVer excludes prerelease ordinals such as \`2026.7.24-3\`, while daily stable releases continue to satisfy the range.`, "`manifest.json` cannot hold comments, so the version-compatibility fields are documented here:", `- \`manifest_version\` (integer): manifest schema generation. Leave at \`${SCAFFOLD_MANIFEST_VERSION}\` unless you adopt a newer manifest schema.`, `- \`pm_min_version\` (string): lowest pm CLI version that may load this package. Scaffolded as \`${SCAFFOLD_PM_MIN_VERSION}\`. The loader blocks the package on older CLIs.`, diff --git a/tests/integration/ci-workflow-contract.spec.ts b/tests/integration/ci-workflow-contract.spec.ts index 061ab85bc..7bfa773ff 100644 --- a/tests/integration/ci-workflow-contract.spec.ts +++ b/tests/integration/ci-workflow-contract.spec.ts @@ -153,7 +153,7 @@ describe("GitHub workflow contract", () => { "run: pnpm typecheck", "pnpm test:coverage --", "run: node scripts/release/compatibility-check.mjs --json", - "npm pack --dry-run", + "node scripts/release/package-artifact-gate.mjs", "pnpm smoke:npx", "pnpm dogfood:package-first", PINNED_ACTIONS.uploadArtifact, @@ -464,7 +464,7 @@ describe("GitHub workflow contract", () => { "SENTRY_AUTH_TOKEN is not configured", "pnpm sentry:inject", "pnpm sentry:upload", - "run: npm pack --dry-run", + "run: node scripts/release/package-artifact-gate.mjs", "run: pnpm smoke:npx", "run: pnpm dogfood:package-first", "fetch-depth: 0", diff --git a/tests/integration/release-automation-contract.spec.ts b/tests/integration/release-automation-contract.spec.ts index ed18cb5a1..b652704e3 100644 --- a/tests/integration/release-automation-contract.spec.ts +++ b/tests/integration/release-automation-contract.spec.ts @@ -183,9 +183,12 @@ describe("release automation contract", () => { expect(bundleScript).toContain("acquireBundleBuildLock"); expect(bundleScript).toContain(".cli-bundle-build.lock"); expect(bundleScript).toContain("rename(lockDir"); - expect(bundleScript).toContain("bundleStaleRetentionMs"); expect(bundleScript).toContain("if (!lockStats)"); - expect(bundleScript).toContain("await lstat(filePath)"); + expect(bundleScript).toContain("await removeStaleBundleFiles(outputs)"); + expect(bundleScript).toContain("await writeBundleManifest(outputs)"); + expect(bundleScript).toContain( + "must not leak into repeated-build package artifacts", + ); }); it("builds dist before the auto-release pipeline consumes dist/cli.js", async () => { diff --git a/tests/unit/extensions/extension-command.spec.ts b/tests/unit/extensions/extension-command.spec.ts index 9fd73f0f7..5717bafc5 100644 --- a/tests/unit/extensions/extension-command.spec.ts +++ b/tests/unit/extensions/extension-command.spec.ts @@ -3698,10 +3698,10 @@ describe("extension command runtime", () => { }, }, { - alias: "vcs", + alias: "vcs-exemplar", available: true, installed: false, - package_name: "@unbrained/pm-vcs", + package_name: "@unbrained/pm-vcs-sdk-exemplar", catalog: { display_name: "VCS SDK Exemplar", category: "sdk", @@ -4040,8 +4040,8 @@ describe("extension command runtime", () => { activated: true, }, { - alias: "vcs", - extension: { name: "builtin-vcs-exemplar" }, + alias: "vcs-exemplar", + extension: { name: "builtin-vcs-sdk-exemplar" }, activated: true, }, ], diff --git a/tests/unit/extensions/extension-describe.spec.ts b/tests/unit/extensions/extension-describe.spec.ts index 6713bb89c..6d7a233fc 100644 --- a/tests/unit/extensions/extension-describe.spec.ts +++ b/tests/unit/extensions/extension-describe.spec.ts @@ -376,7 +376,27 @@ describe("extension describe action", () => { }); await writeFile( path.join(context.pmPath, "extensions", ".managed-extensions.json"), - `${JSON.stringify({ entries: [{ name: "profile-ext", source: { package: "@example/pm-profile" } }] }, null, 2)}\n`, + `${JSON.stringify({ + version: 1, + updated_at: "2026-08-03T00:00:00.000Z", + entries: [{ + name: "profile-ext", + directory: "profile-ext", + scope: "project", + manifest_version: "0.1.0", + manifest_entry: "./index.js", + capabilities: [], + installed_at: "2026-08-03T00:00:00.000Z", + updated_at: "2026-08-03T00:00:00.000Z", + source: { + kind: "npm", + input: "@example/pm-profile", + location: "@example/pm-profile", + package: "@example/pm-profile", + version: "1.0.0", + }, + }], + }, null, 2)}\n`, "utf8", ); await expect( @@ -387,4 +407,53 @@ describe("extension describe action", () => { }); }); }); + + it("describes a package by its persisted install alias", async () => { + await withTempPmPath(async (context) => { + await writeTestExtension({ + root: path.join(context.pmPath, "extensions", "profile-ext"), + name: "profile-ext", + entrySource: + "export default { activate(api) { api.registerCommand({ name: 'profile inspect', run: () => ({ ok: true }) }); } };\n", + }); + await writeFile( + path.join(context.pmPath, "extensions", ".managed-extensions.json"), + `${JSON.stringify({ + version: 1, + updated_at: "2026-08-03T00:00:00.000Z", + entries: [{ + name: "profile-ext", + directory: "profile-ext", + scope: "project", + manifest_version: "0.1.0", + manifest_entry: "./index.js", + capabilities: ["commands"], + installed_at: "2026-08-03T00:00:00.000Z", + updated_at: "2026-08-03T00:00:00.000Z", + source: { + kind: "local", + input: "profile-starter", + location: "/tmp/profile-starter", + package: "@example/pm-profile", + }, + }], + }, null, 2)}\n`, + "utf8", + ); + + const result = await runExtension( + "profile-starter", + { describe: true, project: true, vocabulary: "package" }, + { path: context.pmPath }, + ); + const details = result.details as { + target: string; + total: number; + extensions: Array<{ name: string }>; + }; + expect(details.target).toBe("profile-starter"); + expect(details.total).toBe(1); + expect(details.extensions.map((entry) => entry.name)).toEqual(["profile-ext"]); + }); + }); }); diff --git a/tests/unit/extensions/extension-scaffold-define-guidance.spec.ts b/tests/unit/extensions/extension-scaffold-define-guidance.spec.ts index 5af2d6f2e..e693933cf 100644 --- a/tests/unit/extensions/extension-scaffold-define-guidance.spec.ts +++ b/tests/unit/extensions/extension-scaffold-define-guidance.spec.ts @@ -340,6 +340,10 @@ describe("extension scaffold define builder guidance", () => { expect(packageJson.peerDependencies?.["@unbrained/pm-cli"]).toBe(`>=${SCAFFOLD_PM_MIN_VERSION}`); expect(manifest.pm_min_version).toBe(SCAFFOLD_PM_MIN_VERSION); expect(scaffold["README.md"]).toContain(`Scaffolded as \`${SCAFFOLD_PM_MIN_VERSION}\``); + expect(scaffold["README.md"]).toContain( + `stable range \`>=${SCAFFOLD_PM_MIN_VERSION}\``, + ); + expect(scaffold["README.md"]).toContain("SemVer excludes prerelease ordinals"); expect(packageJson.scripts?.build).toBeUndefined(); expect(packageJson.scripts?.typecheck).toBe("tsc --noEmit"); expect(packageJson.scripts?.["test:runtime"]).toBe("node --test"); diff --git a/tests/unit/packages/vcs-extension.spec.ts b/tests/unit/packages/vcs-extension.spec.ts index 7bf2cd572..8ba733612 100644 --- a/tests/unit/packages/vcs-extension.spec.ts +++ b/tests/unit/packages/vcs-extension.spec.ts @@ -20,6 +20,8 @@ import { import vcsExtension, { VCS_ITEM_FIELDS, VCS_ITEM_TYPES, + VCS_COMMAND_NAMESPACE, + VCS_LEGACY_COMMAND_NAMESPACE, VCS_RELATIONSHIP_KIND, activate, buildVcsCommands, @@ -44,7 +46,7 @@ function emptyState(): ProfileCurrentState { } describe("pm-vcs beyond-PM SDK exemplar", () => { - it("registers schema, profile, seven domain commands, and the merge hook", async () => { + it("registers schema, profile, namespaced commands, legacy aliases, and the merge hook", async () => { const harness = await createExtensionTestHarness(vcsExtension, { capabilities: ["commands", "schema", "hooks"], }); @@ -53,6 +55,13 @@ describe("pm-vcs beyond-PM SDK exemplar", () => { expect(vcsExtension.activate).toBe(activate); expect(vcsExtension.deactivate).toBe(deactivate); expect(buildVcsCommands().map((command) => command.name)).toEqual([ + "vcs-exemplar ref-create", + "vcs-exemplar create", + "vcs-exemplar propose", + "vcs-exemplar merge", + "vcs-exemplar abandon", + "vcs-exemplar show", + "vcs-exemplar log", "vcs ref-create", "vcs create", "vcs propose", @@ -61,6 +70,13 @@ describe("pm-vcs beyond-PM SDK exemplar", () => { "vcs show", "vcs log", ]); + expect(VCS_COMMAND_NAMESPACE).toBe("vcs-exemplar"); + expect(VCS_LEGACY_COMMAND_NAMESPACE).toBe("vcs"); + expect( + buildVcsCommands() + .slice(7) + .every((command) => command.tier === "internal"), + ).toBe(true); for (const itemType of VCS_ITEM_TYPES) { expect( harness.assertItemType({ itemType: itemType.name }).itemType.name, @@ -117,6 +133,14 @@ describe("pm-vcs beyond-PM SDK exemplar", () => { }); it("enforces reviewed merges while leaving every other command untouched", () => { + expect(() => + enforceVcsMergePolicy({ + command: "vcs-exemplar merge", + args: ["change-1"], + options: {}, + pm_root: "/tmp/pm", + }), + ).toThrow(/--reviewed/); expect(() => enforceVcsMergePolicy({ command: "vcs merge", @@ -158,7 +182,7 @@ describe("pm-vcs beyond-PM SDK exemplar", () => { ).toBe(0); const ref = await context.runCliInProcess( - ["vcs", "ref-create", "main", "--json"], + ["vcs-exemplar", "ref-create", "main", "--json"], { expectJson: true }, ); expect(ref.code).toBe(0); @@ -166,7 +190,7 @@ describe("pm-vcs beyond-PM SDK exemplar", () => { const created = await context.runCliInProcess( [ - "vcs", + "vcs-exemplar", "create", "Durable projection", "--ref", @@ -181,7 +205,7 @@ describe("pm-vcs beyond-PM SDK exemplar", () => { const changesetId = (created.json as { id: string }).id; const missingReview = await context.runCliInProcess( - ["vcs", "merge", changesetId, "--ref", refId, "--json"], + ["vcs-exemplar", "merge", changesetId, "--ref", refId, "--json"], { expectJson: true }, ); expect(missingReview.code).not.toBe(0); diff --git a/tests/unit/scripts/bundle-cli.spec.ts b/tests/unit/scripts/bundle-cli.spec.ts index a6b82133a..9b511eb4b 100644 --- a/tests/unit/scripts/bundle-cli.spec.ts +++ b/tests/unit/scripts/bundle-cli.spec.ts @@ -488,7 +488,7 @@ describe("bundle-cli helpers", () => { await expect(mod.collectFiles("/x")).rejects.toThrow("perm"); }); - it("removeStaleBundleFiles keeps expected + recent files and unlinks old extras (swallows unlink error)", async () => { + it("removeStaleBundleFiles keeps expected files and unlinks every obsolete output", async () => { const unlink = vi.fn(async () => { throw new Error("unlink failed"); }); @@ -506,25 +506,7 @@ describe("bundle-cli helpers", () => { isFile: () => true, isSymbolicLink: () => false, }, - { - name: "recent.js", - isDirectory: () => false, - isFile: () => true, - isSymbolicLink: () => false, - }, - { - name: "nostat.js", - isDirectory: () => false, - isFile: () => true, - isSymbolicLink: () => false, - }, ]), - lstat: vi.fn(async (p: string) => { - const s = String(p); - if (s.endsWith("nostat.js")) throw new Error("no stat"); - if (s.endsWith("old.js")) return { mtimeMs: Date.now() - 11 * 60_000 }; - return { mtimeMs: Date.now() }; - }), unlink, }); const mod = await harness.importModuleStable(SCRIPT); diff --git a/tests/unit/scripts/release-version.spec.ts b/tests/unit/scripts/release-version.spec.ts index de75aeaaf..f42779bc0 100644 --- a/tests/unit/scripts/release-version.spec.ts +++ b/tests/unit/scripts/release-version.spec.ts @@ -49,14 +49,16 @@ describe("scripts/release-version: check/next success paths", () => { expect(result.execFileSync).not.toHaveBeenCalled(); }); - it("computes the next ordinal release for a date with published versions", async () => { + it("refuses to propose a same-day ordinal after a stable release exists", async () => { const result = await runReleaseVersionScenario({ args: ["next", "--date", "2026.6.14"], packageJson: { name: "pm-cli", version: "2026.6.14" }, execFileSyncImpl: () => JSON.stringify(["2026.6.14", "2026.6.14-2", "2026.6.13"]), }); - expect(result.failure).toBeNull(); - expect(result.logs.at(-1)).toBe("2026.6.14-3"); + expect(String(result.failure ?? "")).toContain("EXIT:1"); + expect(result.errors.join("\n")).toContain( + "same-day ordinal releases are SemVer prereleases", + ); }); it("returns the bare date key when npm returns a 404 for the package", async () => { @@ -92,13 +94,15 @@ describe("scripts/release-version: check/next success paths", () => { expect(result.logs.at(-1)).toBe(dateKey); }); - it("treats a single published string version as a one-element list", async () => { + it("refuses a date when npm returns one published string version", async () => { const result = await runReleaseVersionScenario({ args: ["next", "--date", "2026.6.14"], execFileSyncImpl: () => JSON.stringify("2026.6.14"), }); - expect(result.failure).toBeNull(); - expect(result.logs.at(-1)).toBe("2026.6.14-2"); + expect(String(result.failure ?? "")).toContain("EXIT:1"); + expect(result.errors.join("\n")).toContain( + "Release already exists for 2026.6.14", + ); }); it("treats a non-array, non-string npm payload as an empty version list", async () => { @@ -156,7 +160,20 @@ describe("scripts/release-version: failure paths", () => { execFileSyncImpl: () => JSON.stringify(["2026.6.14"]), }); expect(String(result.failure ?? "")).toContain("EXIT:1"); - expect(result.errors.join("\n")).toContain("Version sequencing mismatch"); + expect(result.errors.join("\n")).toContain( + "same-day ordinal releases are SemVer prereleases", + ); + }); + + it("rejects a historical ordinal as a new stable release target", async () => { + const result = await runReleaseVersionScenario({ + args: ["check", "--verify-next", "--date", "2026.6.14"], + packageJson: { name: "pm-cli", version: "2026.6.14-2" }, + }); + expect(String(result.failure ?? "")).toContain("EXIT:1"); + expect(result.errors.join("\n")).toContain( + "new releases must use the stable 2026.6.14 version", + ); }); it("fails on an unknown flag", async () => { diff --git a/tests/unit/scripts/release/package-artifact-gate.spec.ts b/tests/unit/scripts/release/package-artifact-gate.spec.ts new file mode 100644 index 000000000..893f80420 --- /dev/null +++ b/tests/unit/scripts/release/package-artifact-gate.spec.ts @@ -0,0 +1,110 @@ +import { describe, expect, it, vi } from "vitest"; +import { createScriptHarness } from "../../../helpers/scriptModule"; + +const harness = createScriptHarness(); +const budget = { + version: 1, + max_unpacked_bytes: 100, + max_file_count: 4, + forbidden_suffixes: [".map"], + required_paths: ["dist/cli.js", "package.json"], +}; + +async function run(report: unknown, configuredBudget: unknown = budget) { + const execFileSync = vi.fn(() => JSON.stringify(report)); + const readFileSync = vi.fn(() => JSON.stringify(configuredBudget)); + vi.doMock("node:child_process", () => ({ execFileSync })); + vi.doMock("node:fs", () => ({ readFileSync })); + const log = vi.spyOn(console, "log").mockImplementation(() => undefined); + let failure: unknown = null; + try { + await harness.importModule( + "scripts/release/package-artifact-gate.mjs", + "packageArtifactGate", + ); + } catch (error) { + failure = error; + } + return { execFileSync, failure, log, readFileSync }; +} + +describe("package artifact gate", () => { + it("accepts the exact npm pack projection and prints a bounded receipt", async () => { + const result = await run([ + { + name: "@unbrained/pm-cli", + version: "2026.8.3", + unpackedSize: 90, + files: [ + { path: "dist/cli.js" }, + { path: "package.json" }, + { path: "README.md" }, + null, + ], + }, + ]); + expect(result.failure).toBeNull(); + expect(result.execFileSync).toHaveBeenCalledWith( + process.platform === "win32" ? "npm.cmd" : "npm", + ["pack", "--dry-run", "--json", "--ignore-scripts"], + { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }, + ); + expect(result.log.mock.calls.flat().join(" ")).toContain('"ok": true'); + expect(result.readFileSync).toHaveBeenCalled(); + }); + + it("reports every composition and budget violation together", async () => { + const result = await run([ + { + unpackedSize: 101, + files: [ + { path: "dist/cli.js.map" }, + { path: "a" }, + { path: "b" }, + { path: "c" }, + { path: "d" }, + ], + }, + ]); + expect(String(result.failure)).toContain("unpacked_size:101>100"); + expect(String(result.failure)).toContain("file_count:5>4"); + expect(String(result.failure)).toContain("forbidden_suffix:.map:1"); + expect(String(result.failure)).toContain("required_path_missing:dist/cli.js"); + expect(String(result.failure)).toContain("required_path_missing:package.json"); + }); + + it("uses the npm command shim on Windows", async () => { + const originalPlatform = Object.getOwnPropertyDescriptor(process, "platform"); + Object.defineProperty(process, "platform", { + value: "win32", + configurable: true, + }); + try { + const result = await run([ + { + unpackedSize: 2, + files: [{ path: "dist/cli.js" }, { path: "package.json" }], + }, + ]); + expect(result.failure).toBeNull(); + expect(result.execFileSync.mock.calls[0]?.[0]).toBe("npm.cmd"); + } finally { + if (originalPlatform) { + Object.defineProperty(process, "platform", originalPlatform); + } + } + }); + + it.each([ + [[]], + [[{ unpackedSize: 1 }]], + [[null]], + [[{ unpackedSize: "1", files: [] }]], + ])( + "rejects malformed npm pack report %#", + async (report) => { + const result = await run(report); + expect(String(result.failure)).toMatch(/exactly one|missing files/); + }, + ); +});