diff --git a/.agents/pm/features/pm-github-c093.toon b/.agents/pm/features/pm-github-c093.toon index d847dcc4..9d452324 100644 --- a/.agents/pm/features/pm-github-c093.toon +++ b/.agents/pm/features/pm-github-c093.toon @@ -6,9 +6,9 @@ status: in_progress priority: 2 tags[4]: changelog-unreleased,fidelity,github,import created_at: "2026-10-16T22:29:39.865Z" -updated_at: "2026-10-17T13:40:47.560Z" +updated_at: "2026-10-18T22:04:28.505Z" author: codex-agent -comments[35]{created_at,author,text}: +comments[40]{created_at,author,text}: "2026-10-16T22:30:04.918Z",codex-agent,"Read all twelve unresolved Sourcery threads and the changed tracker/changelog files in the six consumer sync PRs. Scope: fix import only; preserve append-only history and leave unrelated closeout work untouched. The pinned SDK exposes completedAt but reserves created_at, updated_at and closed_at; source timestamp metadata plus an explicit SDK-gap receipt is required unless a supported import path proves otherwise. No upstream SDK issue will be filed under the queue rules." "2026-10-16T22:35:10.689Z",codex-agent,"Found public SDK import primitives beyond high-level create/update: item locks, canonical document serialization, before/after history entries and appendHistoryEntry. Implementing an idempotent finalization event with real native dates and source metadata, without modifying any historical record. Existing provider owners receive provenance links only; their content, native lifecycle, release and export identity remain authoritative. Local Git calendar tag dates select the first release at or after source closure; later closures remain pending. GraphQL ClosedEvent closer provides actual closing PR attribution where REST commit_id is null." "2026-10-16T23:09:24.995Z",codex-agent,"SDK candidate: bulk compensation captures native updated_at and passes it to restore as a history timestamp. Backdating that field disconnects the rollback version from its event. Preserve source creation/closure/completion natively for momentum and cycle time, and retain the exact source update date in github_updated_at while native updated_at stays the SDK mutation clock. Lifecycle finalization now runs at the SDK committing transition before the journal commits, with real compensation acceptance and a post-recovery idempotent check. No historical entries are rewritten." @@ -44,6 +44,11 @@ comments[35]{created_at,author,text}: "2026-10-17T12:18:26.459Z",codex-agent,"Focused branch repair proof passes 3/3 under c8: refused cancellation, refused provider linking, and identity edge cases with undefined github_url. V8 receipts show execution of the previously uncovered locator fallback and the refused-link throw at index.ts:3470. Test compilation and lint pass. No production logic changed after the four behavioral-revert controls; only provider-fixture identity and an absent-value case were corrected. Starting a clean full npm release:check with CI identity, then the independent Bun release:check at unchanged policy." "2026-10-17T13:12:31.216Z",codex-agent,"Clean CI-identity npm run release:check PASSED on installed Node 26: 797/797 tests, zero failures/skips/cancellations/TODOs. Exact all-source coverage across 14 authored modules: 10438/10438 lines and statements, 273/273 functions, 3157/3157 branches. Type checks, docstrings, lint, zero duplication, privacy, production audit, package dry-run, changelog and publish attestation all passed. Starting the independent literal bun run release:check sequentially with fresh HOME and disabled global/system Git identity; policy, SDK pins and package lock remain unchanged." "2026-10-17T13:40:46.635Z",codex-agent,"Round 1 implementation and local verification complete. Both literal CI-identity release gates PASSED: npm run release:check and bun run release:check each 797/797 tests, zero failures/skips/cancellations/TODOs, exact 100/100/100/100 across 14 authored modules (10438/10438 lines/statements, 273/273 functions, 3157/3157 branches). Audit found zero vulnerabilities; docstrings, lint, duplication, privacy, packing, changelog and attestation pass. Four function-only behavioral reverts produced the expected assertion failures. README partial-write and empty-plan qualifications are verified with real trackers. Marker startup probe is bounded separately while retaining its 10-second work deadline and a forced-spin control. Existing pm-github-sah1 remains open for its original acceptance-watchdog case. Releasing the coding claim for orchestrator verification; next actions are commit/push, replies to the five original review threads, and bounded CI monitoring. No items will be closed." + "2026-10-18T18:19:03.447Z",codex-agent,"Read-only real-public-data verification will use main build and dry-run gated plans in scratch clones. Caller blockers: https://github.com/unbraind/pm-beads/pull/145 https://github.com/unbraind/pm-brief/pull/154 https://github.com/unbraind/pm-context/pull/147 https://github.com/unbraind/pm-csv/pull/163 https://github.com/unbraind/pm-linear/pull/150 https://github.com/unbraind/pm-slack-standup/pull/127. Evidence will compare source dates, release placement and pm-brief momentum without editing consumer checkouts." + "2026-10-18T18:28:36.151Z",codex-agent,"Main dc86e83 built without importer source changes. Live public dry-run gated atomic plans completed for pm-csv (3 issues), pm-brief (2), and pm-context (5; 2 new open plus 3 existing terminal). All 8 previously terminal imports match source created_at, closed_at, github_state and github_updated_at; durable tracker fingerprints are unchanged. Projected completed_at follows the existing adapter source closure assignment; no importer apply ran. Real pm-changelog stdin rendering includes every projected historical item under its explicit containing release and none under Unreleased. Real pm-brief summarizeMomentum reports GitHub lifetimes of 1.2 to 7.0 days instead of the old zero-day imports (or distorted older owners). No import defect found; no import-fix PR is needed." + "2026-10-18T19:03:42.812Z",codex-agent,"Additional real-consumer proof at a normal seven-day window (observation 2026-10-18T19:00:00Z): the eight baseline terminal records produce closedCount=8 and median cycle=0 days. Projected main fields produce closedCount=1 and median cycle=2.3 days; only pm-context issue 136 remains, with GitHub closed_at=2026-10-13T17:54:36Z. All seven older imports leave current throughput. The actual pm-brief summarizeMomentum export ran on both sets; importer apply remains unused. Updated docs/daily-release-refresh.md with this bounded result." + "2026-10-18T19:05:50.551Z",codex-agent,"Present-window proof is now verified from certified COMPLETE SDK records for the scratch caller heads, preserving the native updated_at fallback required by legacy terminal rows. The first scratch attempt used only selected table columns and correctly failed its baseline-count assertion because updated_at was absent from that projection. The complete records pass: recent closures 8 to 1, median cycle 0 to 2.3 days, only pm-context issue 136 remains. This is a verification-harness correction, not a pm-github or pm-brief defect; no importer apply ran and no historical event was rewritten." + "2026-10-18T22:03:48.244Z",codex-agent,"Real-public-data proof is complete for pm-csv issues 72, 134 and 86; pm-brief issues 135 and 84; and pm-context issues 136, 81 and canceled 53. Main gated atomic dry runs account for every fetched issue and preserve all durable tracker fingerprints. Planned created_at, closed_at, github_state and github_updated_at match GitHub. completed_at is explicitly projected from the existing persistence assignment because the dry-run schema omits it; the linked real-SDK pm-brief-135 fidelity test passed 1/1. Actual pm-changelog rendering includes every projected row in a historical release; six prior Unreleased entries become zero. Actual pm-brief momentum over these eight records at the documented seven-day observation changes 8 recent closures to 1 and median cycle 0 to 2.3 days. Full package npm and Bun release checks each passed 897/897 tests and exact 100/100/100/100. No importer defect remains and no import apply or caller edit occurred. Evidence: docs/daily-release-refresh.md; PR https://github.com/unbraind/pm-github/pull/149. Release/adoption remains with the orchestrator and pm-github-aiok." files[13]{path,scope}: import-fidelity.ts,project index.ts,project @@ -58,9 +63,31 @@ files[13]{path,scope}: test/import-gate.test.ts,project test/import-lock.test.ts,project test/import-selection.test.ts,project -tests[2]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref}}: - node --test test/import-fidelity.test.ts,project,2400,codex-agent,"2026-10-16T23:09:21.738Z",local_mutation,feat/import-fidelity - "node --test --test-name-pattern=\"closure evidence accepts forward skew\" test/import-fidelity.test.ts",project,2400,codex-agent,"2026-10-17T10:34:46.689Z",local_mutation,feat/import-fidelity -docs[1]{path,scope}: +tests[3]: + - command: node --test test/import-fidelity.test.ts + scope: project + timeout_seconds: 2400 + provenance: + author: codex-agent + created_at: "2026-10-16T23:09:21.738Z" + source_kind: local_mutation + source_ref: feat/import-fidelity + - command: "node --test --test-name-pattern=\"closure evidence accepts forward skew\" test/import-fidelity.test.ts" + scope: project + timeout_seconds: 2400 + provenance: + author: codex-agent + created_at: "2026-10-17T10:34:46.689Z" + source_kind: local_mutation + source_ref: feat/import-fidelity + - command: node --test --test-name-pattern='pm-brief-135' test/import-fidelity.test.ts + scope: project + provenance: + author: codex-agent + created_at: "2026-10-18T20:33:13.416Z" + source_kind: local_mutation + source_ref: fix/daily-release-refreshes-stale-pr +docs[2]{path,scope}: + docs/daily-release-refresh.md,project README.md,project body: "" diff --git a/.agents/pm/history/pm-github-c093.jsonl b/.agents/pm/history/pm-github-c093.jsonl index 4330645d..fb5ac117 100644 --- a/.agents/pm/history/pm-github-c093.jsonl +++ b/.agents/pm/history/pm-github-c093.jsonl @@ -49,3 +49,12 @@ {"hash_algorithm":"sha256","ts":"2026-10-17T13:12:31.216Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"043799c84ec1b103f8c35f0e","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/33","value":{"created_at":"2026-10-17T13:12:31.216Z","author":"codex-agent","text":"Clean CI-identity npm run release:check PASSED on installed Node 26: 797/797 tests, zero failures/skips/cancellations/TODOs. Exact all-source coverage across 14 authored modules: 10438/10438 lines and statements, 273/273 functions, 3157/3157 branches. Type checks, docstrings, lint, zero duplication, privacy, production audit, package dry-run, changelog and publish attestation all passed. Starting the independent literal bun run release:check sequentially with fresh HOME and disabled global/system Git identity; policy, SDK pins and package lock remain unchanged."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-17T13:12:31.216Z"}],"before_hash":"eda66d60618d714f8bc540625a1e17949764590b8058bcf4058fa5e169a7b503","after_hash":"15d3771447836a04a8d8d93aa07103d64ef82555944ad4d94eda34693d63a34b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d7ffa4ecbcc242ef81fa861f9e9def70e993fb9fa4f326249266bb910cea4bff"} {"hash_algorithm":"sha256","ts":"2026-10-17T13:40:46.635Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"043799c84ec1b103f8c35f0e","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/34","value":{"created_at":"2026-10-17T13:40:46.635Z","author":"codex-agent","text":"Round 1 implementation and local verification complete. Both literal CI-identity release gates PASSED: npm run release:check and bun run release:check each 797/797 tests, zero failures/skips/cancellations/TODOs, exact 100/100/100/100 across 14 authored modules (10438/10438 lines/statements, 273/273 functions, 3157/3157 branches). Audit found zero vulnerabilities; docstrings, lint, duplication, privacy, packing, changelog and attestation pass. Four function-only behavioral reverts produced the expected assertion failures. README partial-write and empty-plan qualifications are verified with real trackers. Marker startup probe is bounded separately while retaining its 10-second work deadline and a forced-spin control. Existing pm-github-sah1 remains open for its original acceptance-watchdog case. Releasing the coding claim for orchestrator verification; next actions are commit/push, replies to the five original review threads, and bounded CI monitoring. No items will be closed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-17T13:40:46.635Z"}],"before_hash":"15d3771447836a04a8d8d93aa07103d64ef82555944ad4d94eda34693d63a34b","after_hash":"8752acecb505866e371a3e567e7c4375cfa45ea1290de8f620209e2b89f43a96","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"a4636433cd6c133621a7791c6fff8c19ae1a52bb5188255b3e376bbf9c6949f5"} {"hash_algorithm":"sha256","ts":"2026-10-17T13:40:47.560Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"043799c84ec1b103f8c35f0e","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-17T13:40:47.560Z"}],"before_hash":"8752acecb505866e371a3e567e7c4375cfa45ea1290de8f620209e2b89f43a96","after_hash":"43ab1cf609be9527eb33197c9943ff1aa96cdd5df31993ed6ace87854ec18ff5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c6cc15ecd82ea75538882b5f650496b3dafafbd2c5a30bf5fc26107b2c9982a3"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:18:52.826Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:18:52.826Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"43ab1cf609be9527eb33197c9943ff1aa96cdd5df31993ed6ace87854ec18ff5","after_hash":"ccf913de56ca9f01b100a0ee8a012f6ed68b13245e2bc7e869e955117debcfa8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7496d943913d1b94e3a28ff3afdafbceb8e5e009422b3a7decf3635165a0906d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:19:03.447Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/35","value":{"created_at":"2026-10-18T18:19:03.447Z","author":"codex-agent","text":"Read-only real-public-data verification will use main build and dry-run gated plans in scratch clones. Caller blockers: https://github.com/unbraind/pm-beads/pull/145 https://github.com/unbraind/pm-brief/pull/154 https://github.com/unbraind/pm-context/pull/147 https://github.com/unbraind/pm-csv/pull/163 https://github.com/unbraind/pm-linear/pull/150 https://github.com/unbraind/pm-slack-standup/pull/127. Evidence will compare source dates, release placement and pm-brief momentum without editing consumer checkouts."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:19:03.447Z"}],"before_hash":"ccf913de56ca9f01b100a0ee8a012f6ed68b13245e2bc7e869e955117debcfa8","after_hash":"a248e86243a0ebd975cf3bcb98113dae05fee44c46cd9da1598c32f18e7e9850","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"6a5624ec341a812f9f975169e5a3d5fc540af618dbc33fe911e4fe8ab800c967"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:28:36.151Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/36","value":{"created_at":"2026-10-18T18:28:36.151Z","author":"codex-agent","text":"Main dc86e83 built without importer source changes. Live public dry-run gated atomic plans completed for pm-csv (3 issues), pm-brief (2), and pm-context (5; 2 new open plus 3 existing terminal). All 8 previously terminal imports match source created_at, closed_at, github_state and github_updated_at; durable tracker fingerprints are unchanged. Projected completed_at follows the existing adapter source closure assignment; no importer apply ran. Real pm-changelog stdin rendering includes every projected historical item under its explicit containing release and none under Unreleased. Real pm-brief summarizeMomentum reports GitHub lifetimes of 1.2 to 7.0 days instead of the old zero-day imports (or distorted older owners). No import defect found; no import-fix PR is needed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:28:36.151Z"}],"before_hash":"a248e86243a0ebd975cf3bcb98113dae05fee44c46cd9da1598c32f18e7e9850","after_hash":"8285da5cbd858b07e58aad96e2fd8c33ee6a42bde54da3d900d104a3fff6cc32","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"2ca46efc180655b236dd30a7a63724a069dbdfeaddb3cedf27332ab55336bec8"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:29:20.384Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/0/path","value":"docs/daily-release-refresh.md"},{"op":"add","path":"/metadata/docs/1","value":{"path":"README.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:29:20.384Z"}],"before_hash":"8285da5cbd858b07e58aad96e2fd8c33ee6a42bde54da3d900d104a3fff6cc32","after_hash":"12984bb7416ac210dfcb792e8baa55b1b30fa0d32ec6706c8d9f10b612ad24ca","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"7fac4370a11d171307b09f46c654c7693870bac42e42dd80636d77dc4f8493f9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T19:03:42.812Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/37","value":{"created_at":"2026-10-18T19:03:42.812Z","author":"codex-agent","text":"Additional real-consumer proof at a normal seven-day window (observation 2026-10-18T19:00:00Z): the eight baseline terminal records produce closedCount=8 and median cycle=0 days. Projected main fields produce closedCount=1 and median cycle=2.3 days; only pm-context issue 136 remains, with GitHub closed_at=2026-10-13T17:54:36Z. All seven older imports leave current throughput. The actual pm-brief summarizeMomentum export ran on both sets; importer apply remains unused. Updated docs/daily-release-refresh.md with this bounded result."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T19:03:42.812Z"}],"before_hash":"12984bb7416ac210dfcb792e8baa55b1b30fa0d32ec6706c8d9f10b612ad24ca","after_hash":"a19a77974353c4d7e0d89eb47b789495a4c0036e90f77cee2e0a77b63ad9c8f8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e1cac4fa8f24f01c0206d8cffad98def176e2ad30ef0b045d4ab1ed58a7e2fc8"} +{"hash_algorithm":"sha256","ts":"2026-10-18T19:05:50.551Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/38","value":{"created_at":"2026-10-18T19:05:50.551Z","author":"codex-agent","text":"Present-window proof is now verified from certified COMPLETE SDK records for the scratch caller heads, preserving the native updated_at fallback required by legacy terminal rows. The first scratch attempt used only selected table columns and correctly failed its baseline-count assertion because updated_at was absent from that projection. The complete records pass: recent closures 8 to 1, median cycle 0 to 2.3 days, only pm-context issue 136 remains. This is a verification-harness correction, not a pm-github or pm-brief defect; no importer apply ran and no historical event was rewritten."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T19:05:50.551Z"}],"before_hash":"a19a77974353c4d7e0d89eb47b789495a4c0036e90f77cee2e0a77b63ad9c8f8","after_hash":"9fe15b89a9d906467b9d5f2d9e3be77efbdf91c0fc47f1188728c88903b593d0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"efc6828e55b567991e3793bf22910ce33b52c248144b3977ac009bf9f89ba579"} +{"hash_algorithm":"sha256","ts":"2026-10-18T20:33:13.736Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/2","value":{"command":"node --test --test-name-pattern='pm-brief-135' test/import-fidelity.test.ts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-18T20:33:13.416Z","source_kind":"local_mutation","source_ref":"fix/daily-release-refreshes-stale-pr"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T20:33:13.736Z"}],"before_hash":"9fe15b89a9d906467b9d5f2d9e3be77efbdf91c0fc47f1188728c88903b593d0","after_hash":"589a0a69af3b221680aa82c5362c241a795f2614deb9a316396edda566a4300b","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"a66b26fb11219ea92b96a4bcbc3affe0599354308d25140b9c4f046295e45e09"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:03:48.247Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/39","value":{"created_at":"2026-10-18T22:03:48.244Z","author":"codex-agent","text":"Real-public-data proof is complete for pm-csv issues 72, 134 and 86; pm-brief issues 135 and 84; and pm-context issues 136, 81 and canceled 53. Main gated atomic dry runs account for every fetched issue and preserve all durable tracker fingerprints. Planned created_at, closed_at, github_state and github_updated_at match GitHub. completed_at is explicitly projected from the existing persistence assignment because the dry-run schema omits it; the linked real-SDK pm-brief-135 fidelity test passed 1/1. Actual pm-changelog rendering includes every projected row in a historical release; six prior Unreleased entries become zero. Actual pm-brief momentum over these eight records at the documented seven-day observation changes 8 recent closures to 1 and median cycle 0 to 2.3 days. Full package npm and Bun release checks each passed 897/897 tests and exact 100/100/100/100. No importer defect remains and no import apply or caller edit occurred. Evidence: docs/daily-release-refresh.md; PR https://github.com/unbraind/pm-github/pull/149. Release/adoption remains with the orchestrator and pm-github-aiok."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:03:48.247Z"}],"before_hash":"589a0a69af3b221680aa82c5362c241a795f2614deb9a316396edda566a4300b","after_hash":"5c89abc43c4c4976e425043feb296eea6c0e5945d357dcdd879910f80208769a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"21ecfac705601f63fb105a74a8d1cef7b8166d21905cda35c35774d4b68c454e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:04:28.505Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:04:28.505Z"}],"before_hash":"5c89abc43c4c4976e425043feb296eea6c0e5945d357dcdd879910f80208769a","after_hash":"0fd58257a56704475ae4b6ab459baf4f4a3b07ea2149b9e222af2ecadef1c7e8","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"6698a9f74b7c506ca2881f85f5653fc4141f93727d769586a230986c4248f1cb"} diff --git a/.agents/pm/history/pm-github-l1ot.jsonl b/.agents/pm/history/pm-github-l1ot.jsonl index fd910068..4079ee74 100644 --- a/.agents/pm/history/pm-github-l1ot.jsonl +++ b/.agents/pm/history/pm-github-l1ot.jsonl @@ -1,2 +1,24 @@ {"hash_algorithm":"sha256","ts":"2026-10-15T09:25:36.259Z","author":"claude-hub","author_source":"asserted","agent_harness":"claude-code","agent_model":"claude-opus-5-5","agent_model_source":"probe","agent_instance":"0400d60929071b1beaa422c1","agent_provenance":{"model":{"value":"claude-opus-5-5","source":"probe"},"effort":{"value":"xhigh","source":"environment"},"role":{"value":"implementer","source":"argv"},"topic":null,"version":{"value":"2.1.300","source":"probe"}},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-l1ot"},{"op":"add","path":"/metadata/title","value":"The daily release regenerates the changelog with a different status filter than release:check, so an open item delivered since the last tag fails the release"},{"op":"add","path":"/metadata/description","value":"On 2026-10-15 the scheduled pm-github release (run 38705391245) failed in Run release checks with 'Changelog is out of date'. The release step 'Generate changelog and release notes' runs npx pm-changelog in replace mode with its default closed-only status filter, then npm run release:check runs changelog:check through scripts/generate-changelog.ts, which passes closed plus every status present in the tracker. pm-github-wrmt (delivered by PR 122) was still in_progress, so it appeared only in the check's output and the release aborted after bumping in the runner (nothing was published). The release workflow and the package scripts must generate the changelog through one code path (the repo's changelog:full script), so a release cannot fail on a disagreement between two generators of the same file."},{"op":"add","path":"/metadata/type","value":"Issue"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":["changelog","release"]},{"op":"add","path":"/metadata/created_at","value":"2026-10-15T09:25:36.259Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-15T09:25:36.259Z"},{"op":"add","path":"/metadata/author","value":"claude-hub"},{"op":"add","path":"/metadata/acceptance_criteria","value":"release.yml generates CHANGELOG.md and the release notes through the package's own changelog scripts with the same status filter as changelog:check; a test fails if the two disagree; a release run with an in_progress item delivered since the last tag either succeeds or fails before any bump with a clear reason"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"4893666f20619a1aec9c36e63192f424dc722126aa2ab719bd27f450df629136","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"claude_session_file","rule_version":"v1"},"version":{"status":"resolved","resolver":"claude_session_file","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"83936020b2f64b50ccbc46b83862dbe2d776bda868257e725086d32eda46e1e8"} {"hash_algorithm":"sha256","ts":"2026-10-15T10:59:09.456Z","author":"claude-hub","author_source":"asserted","agent_harness":"claude-code","agent_model":"claude-fable-5-1","agent_model_source":"probe","agent_instance":"288a1bcb65e947ca3afe5490","agent_provenance":{"model":{"value":"claude-fable-5-1","source":"probe"},"effort":{"value":"high","source":"environment"},"role":{"value":"implementer","source":"argv"},"topic":null,"version":{"value":"2.1.300","source":"probe"}},"op":"update","patch":[{"op":"replace","path":"/metadata/acceptance_criteria","value":"release.yml generates CHANGELOG.md and the release notes through the package's own changelog scripts with the same status filter as changelog:check; a test fails if the two disagree; a release run with an in_progress item tagged changelog-unreleased and delivered since the last tag either succeeds or fails before any bump with a clear reason"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-15T10:59:09.456Z"},{"op":"replace","path":"/metadata/description","value":"On 2026-10-15 the scheduled pm-github release (run 38705391245) failed in Run release checks with 'Changelog is out of date'. The release step 'Generate changelog and release notes' runs npx pm-changelog in replace mode with its default closed-only status filter, then npm run release:check runs changelog:check through scripts/generate-changelog.ts, which retains closed items and non-closed items tagged changelog-unreleased, then passes closed plus the statuses of those retained items. pm-github-wrmt (delivered by PR 122) was still in_progress and had the changelog-unreleased tag, so it appeared only in the check's output and the release aborted after bumping in the runner (nothing was published). The release workflow and the package scripts must generate the changelog through one code path (the repo's changelog:full script), so a release cannot fail on a disagreement between two generators of the same file."},{"op":"replace","path":"/metadata/title","value":"The daily release regenerates the changelog with a different status filter than release:check, so an open changelog-unreleased item delivered since the last tag fails the release"}],"before_hash":"4893666f20619a1aec9c36e63192f424dc722126aa2ab719bd27f450df629136","after_hash":"8c5e53ac241315dc9a1e0966dc657addaae0acfefc57378b32d5221ec1e5e383","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"claude_session_file","rule_version":"v1"},"version":{"status":"resolved","resolver":"claude_session_file","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"7960c9e95fadb1406ae59b63b6fb9b5e2c1cd0d35dde09c5857e35a1b1bf58f9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:18:44.974Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:18:44.974Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"8c5e53ac241315dc9a1e0966dc657addaae0acfefc57378b32d5221ec1e5e383","after_hash":"6be47f0ad862456a282aa85e2f515a7affd903e70014cc2e1334683fde2cc4a9","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4480e51e5a5983b4bf9639e0ed889ba016bcc2fd31fe8ae60852509e20b471c9"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:18:48.628Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:18:48.628Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"6be47f0ad862456a282aa85e2f515a7affd903e70014cc2e1334683fde2cc4a9","after_hash":"062d9d69e13dbbec7a7978d72b91ce59a9a27c691b169a5d36a0fd914268e3d6","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"293679935d4e56473e6a6ebea7c3cb08f5153a1e332d472895a749daf2042d59"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:19:00.875Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:19:00.875Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-18T18:19:00.873Z","author":"codex-agent","text":"Reproduced the release generator split: release.yml uses pm-changelog closed-only output while changelog:check includes tagged pending work. The next run fails before refreshing the protected release PR. Plan: one canonical generator, rebuild from freshly fetched main, refresh or supersede stale PRs, and enforce one release per calendar day with pure decision regressions. Related: https://github.com/unbraind/pm-github/pull/144 and https://github.com/unbraind/pm-ado/issues/33"}]}],"before_hash":"062d9d69e13dbbec7a7978d72b91ce59a9a27c691b169a5d36a0fd914268e3d6","after_hash":"4f5a307868932555a0af1a27e0fdfabbf8457368708511945067a60ea54c9979","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d826f9797b3e42951fe9b7e5e0bf07836530b7c80e2c6b389d100a7739f944cd"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:20:41.085Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:20:41.085Z"},{"op":"replace","path":"/metadata/tags/1","value":"changelog-unreleased"},{"op":"add","path":"/metadata/tags/2","value":"release"}],"before_hash":"4f5a307868932555a0af1a27e0fdfabbf8457368708511945067a60ea54c9979","after_hash":"52d3979af7c5f7073941e08b42ba93c6db11fd9b303ea10f440052de8d098c80","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"69d5780a5e32c9e342a84917be1655d6d2f1835a05fd7dc0c12f9ac5f409800d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:20:45.969Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:20:45.969Z"},{"op":"add","path":"/metadata/files","value":[{"path":".github/workflows/release.yml","scope":"project"},{"path":"scripts/daily-release-plan.ts","scope":"project"},{"path":"test/daily-release-plan.test.ts","scope":"project"}]}],"before_hash":"52d3979af7c5f7073941e08b42ba93c6db11fd9b303ea10f440052de8d098c80","after_hash":"8c694e3621c8008f3ff0f0916299d46861b8a62b5af298cb3768f6661ebd156f","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"646ee3d2e4319507beab55d841d80e6c8ad50093336c141ece5ba98b6c4f861b"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:20:50.727Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:20:50.727Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node --test test/daily-release-plan.test.ts test/release-workflow.test.ts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-18T18:20:50.608Z","source_kind":"local_mutation","source_ref":"fix/daily-release-refreshes-stale-pr"}}]}],"before_hash":"8c694e3621c8008f3ff0f0916299d46861b8a62b5af298cb3768f6661ebd156f","after_hash":"14b66fceb96225b9b5e329f4f65588cc4947bc44629e691d33775f0ceae4b477","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"3864a64cc6bc9c3f7b1e12f3f7a87553dab7e4ff1215bf3acf9240b91577cee4"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:22:11.208Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/1","value":{"created_at":"2026-10-18T18:22:11.207Z","author":"codex-agent","text":"Behavioral function-only revert proof: keeping the same decision function and tests, restored the old unconditional same-day eligibility and today-only branch selection. node --test test/daily-release-plan.test.ts failed 2/4 assertions: the old PR branch was abandoned and a second same-day release was allowed. Restored implementation: focused release suites passed 13/13 and the linked PM command passed. The release generator now invokes changelog:full, changelog:check and release:notes; lease-protected refresh updates the reused PR title/version to today."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:22:11.208Z"}],"before_hash":"14b66fceb96225b9b5e329f4f65588cc4947bc44629e691d33775f0ceae4b477","after_hash":"d37f55f40cabb30052615a7f6728750ef3d4cbaef8382aa677c6aff86a16cf0c","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d137e91b92d65a6f85a97f4c49ee07dd8ee778a0e5f56c8f7cadf424de8cbad4"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:29:34.750Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:29:34.750Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/daily-release-refresh.md","scope":"project"}]}],"before_hash":"d37f55f40cabb30052615a7f6728750ef3d4cbaef8382aa677c6aff86a16cf0c","after_hash":"5816a8ee0bfaffaa0038f8dc8d9220ecb5720eb454745a82c9baaf019cf7eafd","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"eda1159068ec256356ea6b6a11eca8e34d57a0ca1d87e628b5cb4fc233967848"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:32:32.900Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/2","value":{"created_at":"2026-10-18T18:32:32.900Z","author":"codex-agent","text":"Consumer context: https://github.com/unbraind/pm-beads/pull/145 https://github.com/unbraind/pm-brief/pull/154 https://github.com/unbraind/pm-context/pull/147 https://github.com/unbraind/pm-csv/pull/163 https://github.com/unbraind/pm-linear/pull/150 https://github.com/unbraind/pm-slack-standup/pull/127. Separate attribution fix: https://github.com/unbraind/pm-ado/issues/33. The proof report contains all 8 real imported terminal rows, exact before/main lifecycle fields, explicit completed_at projection limits, historical release placement and momentum. Six baseline entries are under Unreleased; all 8 projected rows render under historical releases when terminal statuses are selected."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:32:32.900Z"}],"before_hash":"5816a8ee0bfaffaa0038f8dc8d9220ecb5720eb454745a82c9baaf019cf7eafd","after_hash":"87b5f34ee5b3c38fc3654b77410f7fa2e34567e9ecc2346c35a414093c62eec0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"6f27859fa3771d93e2efe1f9867ffa36fbb6cbab2bc7c53175b243c603584f57"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:34:34.711Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/3","value":{"created_at":"2026-10-18T18:34:34.710Z","author":"codex-agent","text":"Verified the installed gh read boundary against the real repository: number/headRefName selects existing release PR 144. Removed an unnecessary baseRefOid query field that this gh version does not expose. The pure decision uses existing PR identity, current main SHA, last release and today; it intentionally rebuilds even if the existing PR is already based on current main. Focused release tests pass 13/13 after this compatibility adjustment."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:34:34.711Z"}],"before_hash":"87b5f34ee5b3c38fc3654b77410f7fa2e34567e9ecc2346c35a414093c62eec0","after_hash":"20fae5b27385d4ef9bcca8afcda0440fbddf347223fa98316fabfb35e2d74594","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"94809b69378897c00cdf822a8934a9e17b29ad0a55c27d770068a76e8303762d"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:48:05.868Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/4","value":{"created_at":"2026-10-18T18:48:05.868Z","author":"codex-agent","text":"PR https://github.com/unbraind/pm-github/pull/149 is open at e544b02a2bd266c9f7f07de28eec272ea11e7676. A fresh --no-local clone passed strict health with required merge drivers in an isolated home. Current-head function-only revert copies fail exactly 2/4 decision tests; positive suites pass 13/13. Independent decision coverage is 22/22 lines and statements, 12/12 branches and 1/1 functions. Full npm/Bun gates and Node 22/26 CI remain in progress; no merge, release dispatch, tag or publish occurred."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:48:05.868Z"}],"before_hash":"20fae5b27385d4ef9bcca8afcda0440fbddf347223fa98316fabfb35e2d74594","after_hash":"5201c16a25b3ad96ecbe4f0431def20e07f2e6b641e0678fbf184cfd64f630f5","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"4d591e0bffaaa3ac6cb291eae816a66a7f6bc1659dd130b15b7fb7997f0b5275"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:57:13.394Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/5","value":{"created_at":"2026-10-18T18:57:13.394Z","author":"codex-agent","text":"CI Node 26 measured exact 100/100/100/100 across all 15 authored modules, but 1 of 897 tests failed: the pinned pm-ops attestation auditor interpreted the new Node heredoc body as shell publish paths. Replaced that heredoc with a single-quoted node -e expression; the canonical auditor now recognizes exactly one publish invocation with provenance. No auditor code, dependency pin, threshold or exclusion was changed. This is a package-owned compatibility workaround for the pinned shell model; full gates are restarting."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:57:13.394Z"}],"before_hash":"5201c16a25b3ad96ecbe4f0431def20e07f2e6b641e0678fbf184cfd64f630f5","after_hash":"b71924a9316c0b133ee8b7a743c9c5f8670577bc12c59d8b5025b7d12af7f27d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"026baab09626afe6671ba63efda24fd42fe905a51ed9f2ed67ceb01b38e6c7b6"} +{"hash_algorithm":"sha256","ts":"2026-10-18T19:11:03.790Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"node --test test/daily-release-plan.test.ts test/release-workflow.test.ts test/verify-release-publish-attestation.test.ts","scope":"project","provenance":{"author":"codex-agent","created_at":"2026-10-18T19:11:03.374Z","source_kind":"local_mutation","source_ref":"fix/daily-release-refreshes-stale-pr"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T19:11:03.790Z"}],"before_hash":"b71924a9316c0b133ee8b7a743c9c5f8670577bc12c59d8b5025b7d12af7f27d","after_hash":"c0e1a3775c88a58bbe59aed84703dd4b2d506ea2c5e2a2f53274f529f3e2c653","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"93cebba2181f8e17813a80a31dd20c3a1e3eb2a43180d8336888f3e738ebee6e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T21:12:31.150Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/6","value":{"created_at":"2026-10-18T21:12:31.150Z","author":"codex-agent","text":"Code-head CI is green at 12601d6d325d6e6ad1264c0729ff70bb18c90feb: Node 22 and 26 passed, each with 897/897 tests and exact 100/100/100/100 coverage over 15 authored modules. CodeQL and Semgrep passed. Full local npm and Bun release checks are still running through workflow acceptance; no local completion is claimed yet. Sourcery is quota-limited, CodeRabbit skipped review, and Greptile reports an ended trial, so reviewer approval remains missing. CI: https://github.com/unbraind/pm-github/actions/runs/39156572837."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T21:12:31.150Z"}],"before_hash":"c0e1a3775c88a58bbe59aed84703dd4b2d506ea2c5e2a2f53274f529f3e2c653","after_hash":"a86c272e6e376460b91551a3f29c9724c5af614b62e1c3f7cc046e1efb41f83d","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"3a2621a594d3861c1514fbcb5a37951a891a880be51c95d1254fefadd63453d4"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:03:27.935Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/7","value":{"created_at":"2026-10-18T22:03:27.935Z","author":"codex-agent","text":"Full local npm run release:check and bun run release:check both exited 0 at code head 12601d6d325d6e6ad1264c0729ff70bb18c90feb. Each ran 897/897 tests with zero failures, skips or cancellations and measured exact 100/100/100/100 over all 15 authored modules at unchanged thresholds and dependency pins. Typecheck, build, docstrings, lint, duplication, privacy, production audit, pack dry run, changelog check and publication-attestation checks passed. The linked current decision/workflow/auditor suite also passed 21/21. Function-only revert failed the stale-PR and same-day regressions. Final receipt changes contain tracker records and documentation; changelog regeneration and final-head CI follow before handoff. No merge, release dispatch, tag or publication was performed."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:03:27.935Z"}],"before_hash":"a86c272e6e376460b91551a3f29c9724c5af614b62e1c3f7cc046e1efb41f83d","after_hash":"227410138b6a56169dc33593005bfc4515ebcba880bdc98df79d6303b01d5454","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"b42f888aadf82dbf9081322bb53d3891fa84ac6c869c47ee88f30e55dba6b40e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:04:18.419Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:04:18.419Z"}],"before_hash":"227410138b6a56169dc33593005bfc4515ebcba880bdc98df79d6303b01d5454","after_hash":"e68bf993ba3e5f64655f1bdc00ecb5c3fdef1cf506398d38c5c975acbbff3e32","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"a6fd3b3fd0b6af5b0fd43e655a0a9414c6f2e72bbbc57a8654aacc9700280d9c"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:51:50.082Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"claim","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:51:50.082Z"},{"op":"add","path":"/metadata/assignee","value":"codex-agent"},{"op":"add","path":"/metadata/claim_principal","value":"codex-agent"}],"before_hash":"e68bf993ba3e5f64655f1bdc00ecb5c3fdef1cf506398d38c5c975acbbff3e32","after_hash":"68b8778c8b6bcd5c17ad370e29f5bb82c52390b1ea431d5110e07137766a8d1a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"d437784711d469b1b567ca26fcc751d488e95adc4a52e98d5ee722734a731957"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:51:56.036Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/8","value":{"created_at":"2026-10-18T22:51:56.035Z","author":"codex-agent","text":"Review round 1: PR149 threads PRRT_kwDOTbN4pM6tu6Ys and PRRT_kwDOTbN4pM6tu6Y7 remain unresolved. Trace confirms untrusted release-prefix PRs flow to force-push and by-head PR editing. Restrict the pure planner to same-repository PRs authored by the workflow identity with date-shaped branches, carry the selected PR number to editing, and refuse fresh-branch collisions. Add independent filter regressions and function-only revert proofs. Link completed receipts in report and tracker; new review gates remain pending. PR150 has no review threads; its completed source and validation remain unchanged. No review-thread replies or resolutions will be made."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:51:56.036Z"}],"before_hash":"68b8778c8b6bcd5c17ad370e29f5bb82c52390b1ea431d5110e07137766a8d1a","after_hash":"79841fb3fcb73af5457af85ecdf153340b5c643dd1248fd89dc45aaa0edc7cb1","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"cefb82040296419b26772d8c7ac21d0b0126bb65287ffb74f047433d4432a84e"} +{"hash_algorithm":"sha256","ts":"2026-10-18T22:53:06.496Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/9","value":{"created_at":"2026-10-18T22:53:06.496Z","author":"codex-agent","text":"Review security regression proof: reverting only the same-repository predicate makes the cross-repository test fail with ERR_ASSERTION; reverting only exact workflow-author equality makes the foreign-author test fail; reverting only the date-branch predicate makes the non-date branch test fail. Each isolated run exits 1, with tests and remaining implementation retained. Correct implementation passes the 27-test decision/workflow/publication suite, including legitimate stale PR reuse, unpadded dates, GitHub lookup failure propagation and existing-ref collision refusal before push or cleanup. Report now links immutable completed local receipts and final-head CI for the prior heads: https://github.com/unbraind/pm-github/blob/3de8cde015db5979d6c0ebc9a749bbccd5656d7d/.agents/pm/history/pm-github-l1ot.jsonl and https://github.com/unbraind/pm-github/actions/runs/39170908685 . Review-round full gates remain pending."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T22:53:06.496Z"}],"before_hash":"79841fb3fcb73af5457af85ecdf153340b5c643dd1248fd89dc45aaa0edc7cb1","after_hash":"209f6918543c1ce885950b52ca9ca55fac335c856ffa0b76be339762d7b2e3b4","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"697a398532f73dd9a4b862eb269b2de5a3049ba557e2731dbe8f65eaa5f09ece"} +{"hash_algorithm":"sha256","ts":"2026-10-18T23:32:50.519Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/10","value":{"created_at":"2026-10-18T23:32:50.519Z","author":"codex-agent","text":"Review code-head CI is green at febd1215f941369be9e2de2e69dcfc0fc84f25be: Node22 and Node26, CodeQL and Semgrep passed within 40 minutes with 60-second polling. Node26 logs confirm 903/903 Node tests, exact 100/100/100/100 over 15 authored modules, and 903 native Bun tests across 41 files. CI receipt: https://github.com/unbraind/pm-github/actions/runs/39174854832 . Both explicit local release checks are still running, so their completion is not claimed. Review threads have not been replied to or resolved."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T23:32:50.519Z"}],"before_hash":"209f6918543c1ce885950b52ca9ca55fac335c856ffa0b76be339762d7b2e3b4","after_hash":"75c6b572fc2d9a6f183ad208a9c10f95e3a6ee63ebf0b85497c2ca5ff2299d27","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"0fa706e0a395f1df03ae3279c5cd29f7f08b80be54fd573139f584bcb142592b"} +{"hash_algorithm":"sha256","ts":"2026-10-19T00:15:30.141Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"add","path":"/metadata/comments/11","value":{"created_at":"2026-10-19T00:15:30.141Z","author":"codex-agent","text":"Review round 1 full local gates completed: npm run release:check and bun run release:check both exited 0 at code head febd1215f941369be9e2de2e69dcfc0fc84f25be. Each passed 903/903 tests, zero failures/skips/cancellations, exact 100/100/100/100 over 15 authored modules at unchanged thresholds and pins. Lines/statements 10471/10471; functions 275/275; branches npm 3177/3177 and Bun invocation 3175/3175. Typecheck, build, docstrings, lint, duplication, privacy, production audit, pack dry run, changelog check and publication attestation passed. Focused suite 27/27; each of the three planner safety predicates independently reverted causes its regression to fail. Legitimate stale bot PR reuse, single-day cap, GitHub read failure propagation and ref collision refusal remain covered. docs/daily-release-refresh.md links prior completed receipts and the current review receipt, distinguishing historical pending comments from completion. Code-head CI: https://github.com/unbraind/pm-github/actions/runs/39174854832 . Receipt-only head CI and independent fresh-clone strict health follow in the PR. No review-thread replies/resolutions or release actions occurred."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-19T00:15:30.141Z"}],"before_hash":"75c6b572fc2d9a6f183ad208a9c10f95e3a6ee63ebf0b85497c2ca5ff2299d27","after_hash":"a9d7651b6a226160e067f3d128b2b3b7e0044834722ef16839e828ab7d6cdb9a","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"ecc5bdf24b4b11818335acfa339f57a52aaad1a23e525cad143308edf2505a3f"} +{"hash_algorithm":"sha256","ts":"2026-10-19T00:15:34.559Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"release","patch":[{"op":"remove","path":"/metadata/claim_principal"},{"op":"remove","path":"/metadata/assignee"},{"op":"replace","path":"/metadata/updated_at","value":"2026-10-19T00:15:34.559Z"}],"before_hash":"a9d7651b6a226160e067f3d128b2b3b7e0044834722ef16839e828ab7d6cdb9a","after_hash":"273cfdf9c1c85cf55bb28e4f45550605918f6095b5593e777483c1cbc6fdab1e","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"c4c7e9ab81e1f35ccba06bff852c69074fd83539935a5c59c98b37f2f60ea258"} diff --git a/.agents/pm/history/pm-github-sagl.jsonl b/.agents/pm/history/pm-github-sagl.jsonl new file mode 100644 index 00000000..a0f24a95 --- /dev/null +++ b/.agents/pm/history/pm-github-sagl.jsonl @@ -0,0 +1,3 @@ +{"hash_algorithm":"sha256","ts":"2026-10-18T18:32:44.499Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-sagl"},{"op":"add","path":"/metadata/title","value":"Audit copied fleet release workflows for canonical generation and one daily publication"},{"op":"add","path":"/metadata/description","value":"Read-only inventory found 25 sibling workflows with the same numeric-suffix decision block. No shared release template exists in pm-ops. Use the sibling inventory in docs/daily-release-refresh.md to plan package-owned follow-up work without modifying other repositories in the current task."},{"op":"add","path":"/metadata/type","value":"Task"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":[]},{"op":"add","path":"/metadata/created_at","value":"2026-10-18T18:32:44.499Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-10-18T18:32:44.499Z"},{"op":"add","path":"/metadata/author","value":"codex-agent"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"23bec3bcd7f2942dc14cc4043cd0c21fa2f7e66a8a1f1d1e71ea678486a16e92","item_hash_version":3,"message":"","context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"b7986d02b1b3498de2d67f2e4d44aec8bc0f7b8b492514ff10133b5e447ceede"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:34:24.577Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:34:24.577Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/daily-release-refresh.md","scope":"project"}]}],"before_hash":"23bec3bcd7f2942dc14cc4043cd0c21fa2f7e66a8a1f1d1e71ea678486a16e92","after_hash":"3de444fe01e06f0697cbb202ea6efc7cce878903a04ff0ce2fa12f3025858269","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"maintenance","record_hash_version":1,"record_hash":"754955ca6100249170a1175a6ff204cb18edb50025e7bc8912d47137994d1966"} +{"hash_algorithm":"sha256","ts":"2026-10-18T18:48:31.996Z","author":"codex-agent","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"e4446d2a1278b42fdf0b9f7f","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-10-18T18:48:31.996Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-10-18T18:48:31.995Z","author":"codex-agent","text":"Shared-block follow-up only; the current code change is limited to pm-github PR https://github.com/unbraind/pm-github/pull/149. The report names every copied sibling workflow; no pm-ops release template was found and no sibling repository was edited."}]}],"before_hash":"3de444fe01e06f0697cbb202ea6efc7cce878903a04ff0ce2fa12f3025858269","after_hash":"c33fec9226b33533190d8208c064f0bf2193567e4e256a00394bbd3be14176c0","item_hash_version":3,"context":{"agent_provenance_outcomes":{"model":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"effort":{"status":"resolved","resolver":"codex_session_file","rule_version":"v1"},"version":{"status":"unavailable","reason":"harness_unavailable","resolver":"ai_agent_version","rule_version":"v1"}}},"event_class":"substantive","record_hash_version":1,"record_hash":"e1438142971be65089549dfcf4e7634147b06f6c8d69bec4edb133a40a864e66"} diff --git a/.agents/pm/issues/pm-github-l1ot.toon b/.agents/pm/issues/pm-github-l1ot.toon index 883c7e0c..ca30cb37 100644 --- a/.agents/pm/issues/pm-github-l1ot.toon +++ b/.agents/pm/issues/pm-github-l1ot.toon @@ -2,11 +2,33 @@ id: pm-github-l1ot title: "The daily release regenerates the changelog with a different status filter than release:check, so an open changelog-unreleased item delivered since the last tag fails the release" description: "On 2026-10-15 the scheduled pm-github release (run 38705391245) failed in Run release checks with 'Changelog is out of date'. The release step 'Generate changelog and release notes' runs npx pm-changelog in replace mode with its default closed-only status filter, then npm run release:check runs changelog:check through scripts/generate-changelog.ts, which retains closed items and non-closed items tagged changelog-unreleased, then passes closed plus the statuses of those retained items. pm-github-wrmt (delivered by PR 122) was still in_progress and had the changelog-unreleased tag, so it appeared only in the check's output and the release aborted after bumping in the runner (nothing was published). The release workflow and the package scripts must generate the changelog through one code path (the repo's changelog:full script), so a release cannot fail on a disagreement between two generators of the same file." type: Issue -status: open +status: in_progress priority: 1 -tags[2]: changelog,release +tags[3]: changelog,changelog-unreleased,release created_at: "2026-10-15T09:25:36.259Z" -updated_at: "2026-10-15T10:59:09.456Z" +updated_at: "2026-10-19T00:15:34.559Z" author: claude-hub acceptance_criteria: "release.yml generates CHANGELOG.md and the release notes through the package's own changelog scripts with the same status filter as changelog:check; a test fails if the two disagree; a release run with an in_progress item tagged changelog-unreleased and delivered since the last tag either succeeds or fails before any bump with a clear reason" +comments[12]{created_at,author,text}: + "2026-10-18T18:19:00.873Z",codex-agent,"Reproduced the release generator split: release.yml uses pm-changelog closed-only output while changelog:check includes tagged pending work. The next run fails before refreshing the protected release PR. Plan: one canonical generator, rebuild from freshly fetched main, refresh or supersede stale PRs, and enforce one release per calendar day with pure decision regressions. Related: https://github.com/unbraind/pm-github/pull/144 and https://github.com/unbraind/pm-ado/issues/33" + "2026-10-18T18:22:11.207Z",codex-agent,"Behavioral function-only revert proof: keeping the same decision function and tests, restored the old unconditional same-day eligibility and today-only branch selection. node --test test/daily-release-plan.test.ts failed 2/4 assertions: the old PR branch was abandoned and a second same-day release was allowed. Restored implementation: focused release suites passed 13/13 and the linked PM command passed. The release generator now invokes changelog:full, changelog:check and release:notes; lease-protected refresh updates the reused PR title/version to today." + "2026-10-18T18:32:32.900Z",codex-agent,"Consumer context: https://github.com/unbraind/pm-beads/pull/145 https://github.com/unbraind/pm-brief/pull/154 https://github.com/unbraind/pm-context/pull/147 https://github.com/unbraind/pm-csv/pull/163 https://github.com/unbraind/pm-linear/pull/150 https://github.com/unbraind/pm-slack-standup/pull/127. Separate attribution fix: https://github.com/unbraind/pm-ado/issues/33. The proof report contains all 8 real imported terminal rows, exact before/main lifecycle fields, explicit completed_at projection limits, historical release placement and momentum. Six baseline entries are under Unreleased; all 8 projected rows render under historical releases when terminal statuses are selected." + "2026-10-18T18:34:34.710Z",codex-agent,"Verified the installed gh read boundary against the real repository: number/headRefName selects existing release PR 144. Removed an unnecessary baseRefOid query field that this gh version does not expose. The pure decision uses existing PR identity, current main SHA, last release and today; it intentionally rebuilds even if the existing PR is already based on current main. Focused release tests pass 13/13 after this compatibility adjustment." + "2026-10-18T18:48:05.868Z",codex-agent,"PR https://github.com/unbraind/pm-github/pull/149 is open at e544b02a2bd266c9f7f07de28eec272ea11e7676. A fresh --no-local clone passed strict health with required merge drivers in an isolated home. Current-head function-only revert copies fail exactly 2/4 decision tests; positive suites pass 13/13. Independent decision coverage is 22/22 lines and statements, 12/12 branches and 1/1 functions. Full npm/Bun gates and Node 22/26 CI remain in progress; no merge, release dispatch, tag or publish occurred." + "2026-10-18T18:57:13.394Z",codex-agent,"CI Node 26 measured exact 100/100/100/100 across all 15 authored modules, but 1 of 897 tests failed: the pinned pm-ops attestation auditor interpreted the new Node heredoc body as shell publish paths. Replaced that heredoc with a single-quoted node -e expression; the canonical auditor now recognizes exactly one publish invocation with provenance. No auditor code, dependency pin, threshold or exclusion was changed. This is a package-owned compatibility workaround for the pinned shell model; full gates are restarting." + "2026-10-18T21:12:31.150Z",codex-agent,"Code-head CI is green at 12601d6d325d6e6ad1264c0729ff70bb18c90feb: Node 22 and 26 passed, each with 897/897 tests and exact 100/100/100/100 coverage over 15 authored modules. CodeQL and Semgrep passed. Full local npm and Bun release checks are still running through workflow acceptance; no local completion is claimed yet. Sourcery is quota-limited, CodeRabbit skipped review, and Greptile reports an ended trial, so reviewer approval remains missing. CI: https://github.com/unbraind/pm-github/actions/runs/39156572837." + "2026-10-18T22:03:27.935Z",codex-agent,"Full local npm run release:check and bun run release:check both exited 0 at code head 12601d6d325d6e6ad1264c0729ff70bb18c90feb. Each ran 897/897 tests with zero failures, skips or cancellations and measured exact 100/100/100/100 over all 15 authored modules at unchanged thresholds and dependency pins. Typecheck, build, docstrings, lint, duplication, privacy, production audit, pack dry run, changelog check and publication-attestation checks passed. The linked current decision/workflow/auditor suite also passed 21/21. Function-only revert failed the stale-PR and same-day regressions. Final receipt changes contain tracker records and documentation; changelog regeneration and final-head CI follow before handoff. No merge, release dispatch, tag or publication was performed." + "2026-10-18T22:51:56.035Z",codex-agent,"Review round 1: PR149 threads PRRT_kwDOTbN4pM6tu6Ys and PRRT_kwDOTbN4pM6tu6Y7 remain unresolved. Trace confirms untrusted release-prefix PRs flow to force-push and by-head PR editing. Restrict the pure planner to same-repository PRs authored by the workflow identity with date-shaped branches, carry the selected PR number to editing, and refuse fresh-branch collisions. Add independent filter regressions and function-only revert proofs. Link completed receipts in report and tracker; new review gates remain pending. PR150 has no review threads; its completed source and validation remain unchanged. No review-thread replies or resolutions will be made." + "2026-10-18T22:53:06.496Z",codex-agent,"Review security regression proof: reverting only the same-repository predicate makes the cross-repository test fail with ERR_ASSERTION; reverting only exact workflow-author equality makes the foreign-author test fail; reverting only the date-branch predicate makes the non-date branch test fail. Each isolated run exits 1, with tests and remaining implementation retained. Correct implementation passes the 27-test decision/workflow/publication suite, including legitimate stale PR reuse, unpadded dates, GitHub lookup failure propagation and existing-ref collision refusal before push or cleanup. Report now links immutable completed local receipts and final-head CI for the prior heads: https://github.com/unbraind/pm-github/blob/3de8cde015db5979d6c0ebc9a749bbccd5656d7d/.agents/pm/history/pm-github-l1ot.jsonl and https://github.com/unbraind/pm-github/actions/runs/39170908685 . Review-round full gates remain pending." + "2026-10-18T23:32:50.519Z",codex-agent,"Review code-head CI is green at febd1215f941369be9e2de2e69dcfc0fc84f25be: Node22 and Node26, CodeQL and Semgrep passed within 40 minutes with 60-second polling. Node26 logs confirm 903/903 Node tests, exact 100/100/100/100 over 15 authored modules, and 903 native Bun tests across 41 files. CI receipt: https://github.com/unbraind/pm-github/actions/runs/39174854832 . Both explicit local release checks are still running, so their completion is not claimed. Review threads have not been replied to or resolved." + "2026-10-19T00:15:30.141Z",codex-agent,"Review round 1 full local gates completed: npm run release:check and bun run release:check both exited 0 at code head febd1215f941369be9e2de2e69dcfc0fc84f25be. Each passed 903/903 tests, zero failures/skips/cancellations, exact 100/100/100/100 over 15 authored modules at unchanged thresholds and pins. Lines/statements 10471/10471; functions 275/275; branches npm 3177/3177 and Bun invocation 3175/3175. Typecheck, build, docstrings, lint, duplication, privacy, production audit, pack dry run, changelog check and publication attestation passed. Focused suite 27/27; each of the three planner safety predicates independently reverted causes its regression to fail. Legitimate stale bot PR reuse, single-day cap, GitHub read failure propagation and ref collision refusal remain covered. docs/daily-release-refresh.md links prior completed receipts and the current review receipt, distinguishing historical pending comments from completion. Code-head CI: https://github.com/unbraind/pm-github/actions/runs/39174854832 . Receipt-only head CI and independent fresh-clone strict health follow in the PR. No review-thread replies/resolutions or release actions occurred." +files[3]{path,scope}: + .github/workflows/release.yml,project + scripts/daily-release-plan.ts,project + test/daily-release-plan.test.ts,project +tests[2]{command,scope,provenance{author,created_at,source_kind,source_ref}}: + node --test test/daily-release-plan.test.ts test/release-workflow.test.ts,project,codex-agent,"2026-10-18T18:20:50.608Z",local_mutation,fix/daily-release-refreshes-stale-pr + node --test test/daily-release-plan.test.ts test/release-workflow.test.ts test/verify-release-publish-attestation.test.ts,project,codex-agent,"2026-10-18T19:11:03.374Z",local_mutation,fix/daily-release-refreshes-stale-pr +docs[1]{path,scope}: + docs/daily-release-refresh.md,project body: "" diff --git a/.agents/pm/tasks/pm-github-sagl.toon b/.agents/pm/tasks/pm-github-sagl.toon new file mode 100644 index 00000000..0eaa97af --- /dev/null +++ b/.agents/pm/tasks/pm-github-sagl.toon @@ -0,0 +1,15 @@ +id: pm-github-sagl +title: Audit copied fleet release workflows for canonical generation and one daily publication +description: Read-only inventory found 25 sibling workflows with the same numeric-suffix decision block. No shared release template exists in pm-ops. Use the sibling inventory in docs/daily-release-refresh.md to plan package-owned follow-up work without modifying other repositories in the current task. +type: Task +status: open +priority: 2 +tags: [] +created_at: "2026-10-18T18:32:44.499Z" +updated_at: "2026-10-18T18:48:31.996Z" +author: codex-agent +comments[1]{created_at,author,text}: + "2026-10-18T18:48:31.995Z",codex-agent,"Shared-block follow-up only; the current code change is limited to pm-github PR https://github.com/unbraind/pm-github/pull/149. The report names every copied sibling workflow; no pm-ops release template was found and no sibling repository was edited." +docs[1]{path,scope}: + docs/daily-release-refresh.md,project +body: "" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c045eba..70f98bff 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,13 @@ jobs: fetch-depth: 0 fetch-tags: true + - name: Refresh release base + shell: bash + run: | + set -euo pipefail + git fetch origin main --force + git checkout --detach origin/main + - name: Setup Node.js uses: actions/setup-node@v7 with: @@ -74,54 +81,34 @@ jobs: - name: Decide release id: decide + env: + GH_TOKEN: ${{ github.token }} shell: bash run: | set -euo pipefail git fetch --force --tags - latest_tag="$(git tag --sort=-creatordate | head -n 1 || true)" - if [[ -n "$latest_tag" ]] && git diff --quiet "$latest_tag"..HEAD -- .; then - echo "should_release=false" >> "$GITHUB_OUTPUT" - echo "latest_tag=$latest_tag" >> "$GITHUB_OUTPUT" - echo "No changes since $latest_tag; skipping release." >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi - - release_date="$(TZ="$RELEASE_TIMEZONE" date +%Y.%m.%d)" - base_tag="v${release_date}" - max_suffix=-1 - while IFS= read -r existing_tag; do - if [[ "$existing_tag" == "$base_tag" ]]; then - (( max_suffix < 0 )) && max_suffix=0 - continue - fi - if [[ "$existing_tag" == "$base_tag-"* ]]; then - suffix="${existing_tag#"$base_tag-"}" - if [[ "$suffix" =~ ^[0-9]+$ ]] && (( suffix > max_suffix )); then - max_suffix="$suffix" - fi - fi - done < <(git tag -l "${base_tag}*") - - if (( max_suffix >= 0 )); then - tag="${base_tag}-$((max_suffix + 1))" - else - tag="$base_tag" + latest_tag="$(git tag --sort=-version:refname | head -n 1 || true)" + export RELEASE_TODAY="$(TZ="$RELEASE_TIMEZONE" date +%Y.%m.%d)" + export RELEASE_MAIN_SHA="$(git rev-parse HEAD)" + export RELEASE_LAST_TAG="$latest_tag" + export RELEASE_LAST_SHA="" + if [[ -n "$latest_tag" ]]; then + export RELEASE_LAST_SHA="$(git rev-list -n 1 "$latest_tag")" fi - - version_core="${tag#v}" - year="${version_core%%.*}" - version_tail="${version_core#*.}" - month="${version_tail%%.*}" - day_and_suffix="${version_tail#*.}" - day="${day_and_suffix%%-*}" - suffix="${day_and_suffix#"$day"}" - npm_version="$((10#$year)).$((10#$month)).$((10#$day))${suffix}" - - echo "should_release=true" >> "$GITHUB_OUTPUT" - echo "latest_tag=$latest_tag" >> "$GITHUB_OUTPUT" - echo "tag=$tag" >> "$GITHUB_OUTPUT" - echo "npm_version=$npm_version" >> "$GITHUB_OUTPUT" - echo "base_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + RELEASE_EXISTING_PRS="$(gh pr list --repo "$GITHUB_REPOSITORY" --base main --state open \ + --json number,headRefName,isCrossRepository,author)" + export RELEASE_EXISTING_PRS + node --input-type=module -e ' + import { decideDailyRelease } from "./scripts/daily-release-plan.ts"; + const e = process.env; + const plan = decideDailyRelease({ + existingPrs: JSON.parse(e.RELEASE_EXISTING_PRS), + mainSha: e.RELEASE_MAIN_SHA, today: e.RELEASE_TODAY, + lastRelease: e.RELEASE_LAST_TAG ? { tag: e.RELEASE_LAST_TAG, sha: e.RELEASE_LAST_SHA } : null, + }); + for (const [key, value] of Object.entries(plan)) console.log(key + "=" + value); + console.log("latest_tag=" + e.RELEASE_LAST_TAG); + ' >> "$GITHUB_OUTPUT" # Refuse non-main release runs BEFORE publishing. `github.ref` is the # authoritative workflow trigger ref: schedule -> refs/heads/main; @@ -262,9 +249,9 @@ jobs: shell: bash run: | set -euo pipefail - npx pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded --github-step-summary - npx pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded --check - npx pm-changelog --pm-root .agents/pm --stdout --since-previous-tag --until-release-tag --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded > RELEASE_NOTES.md + npm run changelog:full -- --github-step-summary + npm run changelog:check + npm run --silent release:notes > RELEASE_NOTES.md - name: Run release checks if: steps.decide.outputs.should_release == 'true' @@ -299,6 +286,8 @@ jobs: RELEASE_BASE_SHA: ${{ steps.decide.outputs.base_sha }} RELEASE_TAG: ${{ steps.decide.outputs.tag }} NPM_VERSION: ${{ steps.decide.outputs.npm_version }} + RELEASE_BRANCH: ${{ steps.decide.outputs.release_branch }} + RELEASE_PR_NUMBER: ${{ steps.decide.outputs.pr_number }} run: | set -euo pipefail git fetch origin main --force @@ -308,12 +297,19 @@ jobs: exit 1 fi - release_branch="release/${RELEASE_TAG#v}" + release_branch="$RELEASE_BRANCH" + pr_number="$RELEASE_PR_NUMBER" + remote_branch_sha="$(git ls-remote --heads origin "refs/heads/${release_branch}" | cut -f1)" + if [[ -z "$pr_number" && -n "$remote_branch_sha" ]]; then + echo "::error::Refusing to overwrite a release branch without a verified workflow PR." + exit 1 + fi release_commit="$(git rev-parse HEAD)" if [[ "$release_commit" == "$current_main_sha" ]]; then echo "Release metadata is already present on main; resuming the publish/tag transaction." - if git ls-remote --exit-code --heads origin "refs/heads/${release_branch}" > /dev/null 2>&1; then - git push origin --delete "$release_branch" + if [[ -n "$remote_branch_sha" ]]; then + git push --force-with-lease="refs/heads/${release_branch}:${remote_branch_sha}" \ + origin ":refs/heads/${release_branch}" fi { echo "merged_sha=$current_main_sha" @@ -322,22 +318,9 @@ jobs: exit 0 fi - remote_branch_sha="$(git ls-remote --heads origin "refs/heads/${release_branch}" | cut -f1)" - if [[ -n "$remote_branch_sha" ]]; then - git push \ - --force-with-lease="refs/heads/${release_branch}:${remote_branch_sha}" \ - origin "HEAD:refs/heads/${release_branch}" - else - git push origin "HEAD:refs/heads/${release_branch}" - fi - - pr_number="$(gh pr list \ - --repo "$GITHUB_REPOSITORY" \ - --base main \ - --head "$release_branch" \ - --state open \ - --json number \ - --jq '.[0].number // empty')" + git push \ + --force-with-lease="refs/heads/${release_branch}:${remote_branch_sha}" \ + origin "HEAD:refs/heads/${release_branch}" if [[ -z "$pr_number" ]]; then pr_url="$(gh pr create \ --repo "$GITHUB_REPOSITORY" \ @@ -346,6 +329,10 @@ jobs: --title "Release pm-github ${RELEASE_TAG}" \ --body "Automated daily release metadata for \`${RELEASE_TAG}\`. The release gate passed before this PR was created; npm publication and tagging remain blocked until this protected PR is merged.")" pr_number="${pr_url##*/}" + else + gh pr edit "$pr_number" --repo "$GITHUB_REPOSITORY" \ + --title "Release pm-github ${RELEASE_TAG}" \ + --body "Automated daily release metadata for \`${RELEASE_TAG}\`, rebuilt from current main. The release gate passed before refresh; publication and tagging wait for the protected PR." fi owner="${GITHUB_REPOSITORY%/*}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e0dc4bf..851129f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixed +- The daily release regenerates the changelog with a different status filter than release:check, so an open changelog-unreleased item delivered since the last tag fails the release ([pm-github-l1ot](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-l1ot.toon)) - Release timeout must report current workflow approval state ([pm-github-b145](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-b145.toon)) - Preserve legacy GitHub ownership across copied provider examples ([pm-github-b143](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-b143.toon)) - Reject malformed effective-rule discriminators before closeout ([pm-github-b141](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-b141.toon)) diff --git a/docs/daily-release-refresh.md b/docs/daily-release-refresh.md new file mode 100644 index 00000000..440d00f7 --- /dev/null +++ b/docs/daily-release-refresh.md @@ -0,0 +1,137 @@ +# Daily release refresh and public import evidence + +Unchanged importer source: main `dc86e83be87f915dabef831e720edcf3cdc562e8`. Public API observation: 2026-10-18. + +## Release root cause + +The release job generates closed-only history by invoking pm-changelog directly. Its changelog:check invokes scripts/generate-changelog.ts, which also includes unfinished items tagged changelog-unreleased. After main gains such tracker changes, a later run fails release:check before reaching the existing lease-protected branch push. Date-derived branch selection also abandons an older open PR on the next day; numeric suffixes permit multiple same-day publications. + +The job now fetches current main before preparation and uses the canonical changelog scripts. A pure decision over existing PR, main SHA, last release and today selects the existing release branch for rebuilding, updates its title/version to today and refuses a second version after today has a release tag. A concurrent main update still refuses publication; a subsequent run rebuilds it. + +## Public-data method + +Temporary clones contain the real caller sync PR heads. The unchanged main build runs runImport with state=all, gate=true, atomic=true and dry-run=true against the live API. Certified complete SDK reads and durable tracker fingerprints prove zero durable tracker writes. pm-context also accounts for two new open issues. + +Each historical plan row is projected into real pm-changelog stdin rendering and the actual pm-brief summarizeMomentum export. The renderer must include the item under its explicit containing release and omit it from Unreleased. No importer apply ran. The dry-run schema omits completed_at: below it is explicitly projected from the existing persistImportFidelity assignment, which writes both terminal fields from github_closed_at. Existing real-tracker import-fidelity regressions exercise those durable assignments. + +Baseline Unreleased membership comes from the actual caller PR CHANGELOG.md. All projected GitHub states equal closed; the canceled item retains local status canceled. Momentum observes each source closure plus one second with a 3650-day window, to inspect its historical lifetime; baseline momentum is observed on 2026-10-18. This is not a production now-window throughput claim. + +| Repository | Caller PR head | +| --- | --- | +| unbraind/pm-csv | `fea199155e101b250e34d3fcb5eebda0544b0c42` | +| unbraind/pm-brief | `25495e6b35572d1d7c9218eb91ace4ed5925c9dd` | +| unbraind/pm-context | `7d9ed21dedcf104ab921bc34dc11fd9019738dd6` | + +## Before versus main plan + +| Repo / issue | Field | Caller sync PR | Main plan / projection | +| --- | --- | --- | --- | +| unbraind/pm-csv#72 | created_at | `2026-08-20T19:28:52.262Z` | `2026-08-20T19:42:05Z` | +| unbraind/pm-csv#72 | closed_at | `2026-10-18T07:17:46.393Z` | `2026-08-27T04:12:45Z` | +| unbraind/pm-csv#72 | completed_at | `2026-08-27T04:12:45.000Z` | `2026-08-27T04:12:45Z` | +| unbraind/pm-csv#72 | github_state | `open` | `closed` | +| unbraind/pm-csv#72 | github_updated_at | `2026-08-20T19:42:05Z` | `2026-10-14T11:34:13Z` | +| unbraind/pm-csv#72 | release | `absent` | `v2026.08.28` | +| unbraind/pm-csv#134 | created_at | `2026-10-18T07:17:46.545Z` | `2026-09-23T08:54:00Z` | +| unbraind/pm-csv#134 | closed_at | `2026-10-18T07:17:46.631Z` | `2026-09-25T07:52:12Z` | +| unbraind/pm-csv#134 | completed_at | `2026-09-25T07:52:12.000Z` | `2026-09-25T07:52:12Z` | +| unbraind/pm-csv#134 | github_state | `absent` | `closed` | +| unbraind/pm-csv#134 | github_updated_at | `absent` | `2026-09-25T07:52:12Z` | +| unbraind/pm-csv#134 | release | `absent` | `v2026.09.26` | +| unbraind/pm-csv#86 | created_at | `2026-10-18T07:17:46.426Z` | `2026-08-27T14:29:39Z` | +| unbraind/pm-csv#86 | closed_at | `2026-10-18T07:17:46.520Z` | `2026-09-01T04:51:41Z` | +| unbraind/pm-csv#86 | completed_at | `2026-09-01T04:51:41.000Z` | `2026-09-01T04:51:41Z` | +| unbraind/pm-csv#86 | github_state | `absent` | `closed` | +| unbraind/pm-csv#86 | github_updated_at | `absent` | `2026-09-01T04:51:41Z` | +| unbraind/pm-csv#86 | release | `absent` | `v2026.09.01` | +| unbraind/pm-brief#135 | created_at | `2026-10-18T08:08:52.780Z` | `2026-10-05T05:06:12Z` | +| unbraind/pm-brief#135 | closed_at | `2026-10-18T08:08:52.862Z` | `2026-10-07T12:19:04Z` | +| unbraind/pm-brief#135 | completed_at | `2026-10-07T12:19:04.000Z` | `2026-10-07T12:19:04Z` | +| unbraind/pm-brief#135 | github_state | `absent` | `closed` | +| unbraind/pm-brief#135 | github_updated_at | `absent` | `2026-10-09T09:17:10Z` | +| unbraind/pm-brief#135 | release | `absent` | `v2026.10.08` | +| unbraind/pm-brief#84 | created_at | `2026-10-18T08:08:52.630Z` | `2026-08-25T04:12:33Z` | +| unbraind/pm-brief#84 | closed_at | `2026-10-18T08:08:52.752Z` | `2026-09-01T04:51:37Z` | +| unbraind/pm-brief#84 | completed_at | `2026-09-01T04:51:37.000Z` | `2026-09-01T04:51:37Z` | +| unbraind/pm-brief#84 | github_state | `absent` | `closed` | +| unbraind/pm-brief#84 | github_updated_at | `absent` | `2026-09-01T04:51:37Z` | +| unbraind/pm-brief#84 | release | `absent` | `v2026.09.01` | +| unbraind/pm-context#136 | created_at | `2026-10-12T12:44:54.969Z` | `2026-10-11T10:07:01Z` | +| unbraind/pm-context#136 | closed_at | `2026-10-13T22:21:15.749Z` | `2026-10-13T17:54:36Z` | +| unbraind/pm-context#136 | completed_at | `2026-10-13T22:21:15.749Z` | `2026-10-13T17:54:36Z` | +| unbraind/pm-context#136 | github_state | `absent` | `closed` | +| unbraind/pm-context#136 | github_updated_at | `absent` | `2026-10-14T12:32:31Z` | +| unbraind/pm-context#136 | release | `absent` | `v2026.10.14` | +| unbraind/pm-context#81 | created_at | `2026-10-16T05:55:33.608Z` | `2026-08-27T14:24:37Z` | +| unbraind/pm-context#81 | closed_at | `2026-10-16T05:55:33.687Z` | `2026-09-01T04:51:39Z` | +| unbraind/pm-context#81 | completed_at | `2026-09-01T04:51:39.000Z` | `2026-09-01T04:51:39Z` | +| unbraind/pm-context#81 | github_state | `absent` | `closed` | +| unbraind/pm-context#81 | github_updated_at | `absent` | `2026-09-01T04:51:39Z` | +| unbraind/pm-context#81 | release | `absent` | `v2026.09.06` | +| unbraind/pm-context#53 | created_at | `2026-10-16T05:55:33.525Z` | `2026-08-07T16:55:49Z` | +| unbraind/pm-context#53 | closed_at | `absent` | `2026-08-08T22:24:46Z` | +| unbraind/pm-context#53 | completed_at | `absent` | `2026-08-08T22:24:46Z` | +| unbraind/pm-context#53 | github_state | `absent` | `closed` | +| unbraind/pm-context#53 | github_updated_at | `absent` | `2026-10-14T11:34:09Z` | +| unbraind/pm-context#53 | release | `absent` | `v2026.08.09` | + +| Repo / issue | Unreleased before → main | Momentum cycle days before → main | +| --- | --- | --- | +| unbraind/pm-csv#72 | yes → no | 58.5 → 6.4 | +| unbraind/pm-csv#134 | yes → no | 0 → 2 | +| unbraind/pm-csv#86 | yes → no | 0 → 4.6 | +| unbraind/pm-brief#135 | yes → no | 0 → 2.3 | +| unbraind/pm-brief#84 | yes → no | 0 → 7 | +| unbraind/pm-context#136 | no → no | 1.4 → 2.3 | +| unbraind/pm-context#81 | yes → no | 0 → 4.6 | +| unbraind/pm-context#53 | no → no | 0 → 1.2 | + +## Present-window momentum + +The same real pm-brief export was also run at 2026-10-18T19:00:00Z with its normal seven-day window over all eight baseline/projected terminal records. This calculation uses certified complete SDK records, retaining native updated_at for legacy terminal records without closed_at; the selected columns in the comparison table are not its input. The baseline counts all 8 as recent closures and has a 0-day median. Main counts only the genuinely recent pm-context issue 136, using its GitHub closure on 2026-10-13T17:54:36Z and a 2.3-day cycle. The seven older imports leave the recent-throughput window. The importer remains dry-run only. + +## Caller adoption + +https://github.com/unbraind/pm-beads/pull/145, https://github.com/unbraind/pm-brief/pull/154, https://github.com/unbraind/pm-context/pull/147, https://github.com/unbraind/pm-csv/pull/163, https://github.com/unbraind/pm-linear/pull/150, https://github.com/unbraind/pm-slack-standup/pull/127. Publication alone does not update their pins; adoption remains tracked in pm-github-aiok. + +## Copied workflow exposure + +The same numeric-suffix block exists in the following 25 sibling workflows. pm-ops has the copied workflow too, but its only tracked executable template is prepare-merge-driver.ts; no shared release workflow template was found. This patch changes pm-github only. + +- pm-ado +- pm-beads +- pm-brief +- pm-changelog +- pm-context +- pm-csv +- pm-gantt-chart +- pm-graph +- pm-jev +- pm-jira +- pm-linear +- pm-lint +- pm-ops +- pm-presets +- pm-review +- pm-rl +- pm-rust +- pm-slack +- pm-slack-standup +- pm-starter +- pm-swarm +- pm-todos +- pm-ts-starter +- pm-vcs +- pm-web + +## Validation + +Function-only behavioral revert restores today-only branch selection and same-day eligibility, retaining the tests. The stale-PR and once-per-day regressions fail (2 failures). At the pre-review code head 12601d6d325d6e6ad1264c0729ff70bb18c90feb, the release decision, workflow and publication-auditor suites passed 21/21. + +Both npm run release:check and bun run release:check exited 0 at code head 12601d6d325d6e6ad1264c0729ff70bb18c90feb. Each ran 897/897 tests with zero failures, cancellations or skips. Both measured exact 100/100/100/100 over all 15 authored modules, at unchanged thresholds and pins: 10466/10466 lines and statements, 275/275 functions, and 3171/3171 (npm) or 3172/3172 (Bun invocation) branches. All remaining release-check stages passed. The completed local results were recorded at 2026-10-18T22:03:27Z in the [append-only tracker receipt](https://github.com/unbraind/pm-github/blob/3de8cde015db5979d6c0ebc9a749bbccd5656d7d/.agents/pm/history/pm-github-l1ot.jsonl); earlier pending comments describe earlier runs. The subsequent documentation/tracker head 3de8cde015db5979d6c0ebc9a749bbccd5656d7d passed [Node 22/26 CI](https://github.com/unbraind/pm-github/actions/runs/39170908685) and fresh-clone strict health. These receipts certify those heads; review-round changes require new gates. + +Review round 1 restricts reusable PRs to the same repository, the exact GITHUB_TOKEN workflow author (`app/github-actions` in gh JSON), and date-shaped release branches. The pure planner selects the PR number used for editing. New branches use an empty force-with-lease expectation and refuse existing refs without a verified workflow PR, including before cleanup. Cross-repository, foreign-author and non-date candidates each plan a fresh PR; mixed candidates still find a legitimate stale workflow PR. Each safety predicate was reverted independently while retaining the tests and other implementation: cross-repository, foreign-author and non-date regressions each fail with ERR_ASSERTION (exit 1). The restored decision/workflow/publication suite passes 27/27. + +At review code head febd1215f941369be9e2de2e69dcfc0fc84f25be, both npm run release:check and bun run release:check exited 0. Each passed 903/903 tests with zero failures, cancellations or skips and exact 100/100/100/100 across 15 authored modules. Both measured 10471/10471 lines and statements and 275/275 functions; branches were 3177/3177 (npm) and 3175/3175 (Bun invocation). All release-check stages passed with unchanged thresholds and dependency pins. The [review-round tracker receipt](../.agents/pm/history/pm-github-l1ot.jsonl) records these completed local results; earlier pending comments describe earlier runs. [Code-head CI](https://github.com/unbraind/pm-github/actions/runs/39174854832) passed Node 22/26, each with 903 Node tests, 903 native Bun tests across 41 files and exact authored-source coverage, plus CodeQL and Semgrep. Receipt-head CI and fresh-clone health are recorded in the PR after that head is pushed. + +GitHub documents that GITHUB_TOKEN-created pull-request runs may require approval; existing bounded approval diagnostics remain: https://docs.github.com/en/actions/concepts/security/github_token. Refresh correctness does not certify GitHub approval or npm publisher policy. diff --git a/scripts/daily-release-plan.ts b/scripts/daily-release-plan.ts new file mode 100644 index 00000000..1aab4496 --- /dev/null +++ b/scripts/daily-release-plan.ts @@ -0,0 +1,27 @@ +/** Facts needed to rebuild a protected release PR without a second daily publication. */ +export interface DailyReleaseInput { + existingPrs: { number: number; headRefName: string; isCrossRepository: boolean; author: { login: string } }[]; + mainSha: string; + lastRelease: { tag: string; sha: string } | null; + today: string; +} + +/** Rebuild from current main on every eligible run, reusing even yesterday's open PR. */ +export function decideDailyRelease(input: DailyReleaseInput) { + // gh represents the GITHUB_TOKEN author as app/github-actions. + const existingPr = input.existingPrs.find(pr => pr.isCrossRepository === false + && pr.author.login === "app/github-actions" + && /^release\/\d{4}\.\d{1,2}\.\d{1,2}$/.test(pr.headRefName)); + const version = input.today.split(".").map(Number).join("."); + const releasedVersion = input.lastRelease?.tag.replace(/^v/, "").split("-")[0]?.split(".").map(Number).join("."); + const shouldRelease = releasedVersion !== version && input.lastRelease?.sha !== input.mainSha; + return { + should_release: shouldRelease, + action: !shouldRelease ? "skip" : existingPr ? "refresh" : "create", + tag: `v${input.today}`, + npm_version: version, + base_sha: input.mainSha, + release_branch: existingPr?.headRefName ?? `release/${input.today}`, + pr_number: existingPr?.number ?? "", + }; +} diff --git a/test/daily-release-plan.test.ts b/test/daily-release-plan.test.ts new file mode 100644 index 00000000..10e12734 --- /dev/null +++ b/test/daily-release-plan.test.ts @@ -0,0 +1,107 @@ +/** Daily release policy is independent of GitHub and the wall clock. */ +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { readFileSync } from "node:fs"; +import test from "node:test"; +import { decideDailyRelease, type DailyReleaseInput } from "../scripts/daily-release-plan.ts"; + +const input: DailyReleaseInput = { existingPrs: [], mainSha: "new-main", lastRelease: null, today: "2026.10.18" }; +const workflowPr = { number: 144, headRefName: "release/2026.10.17", isCrossRepository: false, + author: { login: "app/github-actions" } }; + +test("first release uses today's stable npm version and current main", () => { + assert.deepEqual(decideDailyRelease(input), { should_release: true, action: "create", tag: "v2026.10.18", + npm_version: "2026.10.18", base_sha: "new-main", release_branch: "release/2026.10.18", pr_number: "" }); + assert.equal(decideDailyRelease({ ...input, today: "2026.01.02" }).npm_version, "2026.1.2"); +}); + +test("an existing stale PR is rebuilt from current main and today's date", () => { + const plan = decideDailyRelease({ ...input, existingPrs: [workflowPr], + lastRelease: { tag: "v2026.10.16", sha: "released-main" } }); + assert.equal(plan.action, "refresh"); + assert.equal(plan.should_release, true); + assert.equal(plan.base_sha, "new-main"); + assert.equal(plan.release_branch, "release/2026.10.17"); + assert.equal(plan.tag, "v2026.10.18"); + assert.equal(plan.pr_number, 144); +}); + +test("a cross-repository release PR is ignored and a fresh PR is planned", () => { + const plan = decideDailyRelease({ ...input, existingPrs: [{ ...workflowPr, isCrossRepository: true }] }); + assert.equal(plan.action, "create"); + assert.equal(plan.pr_number, ""); + assert.equal(plan.release_branch, "release/2026.10.18"); +}); + +test("a foreign author's release PR is ignored and a fresh PR is planned", () => { + const plan = decideDailyRelease({ ...input, existingPrs: [{ ...workflowPr, author: { login: "app/other-bot" } }] }); + assert.equal(plan.action, "create"); + assert.equal(plan.pr_number, ""); + assert.equal(plan.release_branch, "release/2026.10.18"); +}); + +test("a non-date release branch is ignored and a fresh PR is planned", () => { + for (const headRefName of ["release/v2-notes", "release/2026.10.17-notes", "release/2026.100.17", "release/2026.10.17\n"]) { + const plan = decideDailyRelease({ ...input, existingPrs: [{ ...workflowPr, headRefName }] }); + assert.equal(plan.action, "create", headRefName); + assert.equal(plan.pr_number, ""); + assert.equal(plan.release_branch, "release/2026.10.18"); + } +}); + +test("selection skips untrusted candidates and accepts the workflow's unpadded date branches", () => { + const plan = decideDailyRelease({ ...input, existingPrs: [ + { ...workflowPr, isCrossRepository: true }, + { ...workflowPr, number: 155, headRefName: "release/2026.1.2" }, + ] }); + assert.equal(plan.action, "refresh"); + assert.equal(plan.pr_number, 155); + assert.equal(plan.release_branch, "release/2026.1.2"); +}); + +test("an unchanged release or a publication already dated today skips, even after new main changes", () => { + for (const tag of ["v2026.10.18", "v2026.10.18-1", "v2026.010.018"]) { + assert.equal(decideDailyRelease({ ...input, lastRelease: { tag, sha: "earlier-main" } }).should_release, false); + } + assert.equal(decideDailyRelease({ ...input, lastRelease: { tag: "v2026.10.17", sha: input.mainSha } }).action, "skip"); +}); + +test("workflow rebuilds before preparation and runs the canonical generator before checks and leased PR refresh", () => { + const workflow = readFileSync(new URL("../.github/workflows/release.yml", import.meta.url), "utf8"); + assert.match(workflow, /import \{ decideDailyRelease \} from "\.\/scripts\/daily-release-plan\.ts"/); + assert.ok(workflow.indexOf("git checkout --detach origin/main") < workflow.indexOf("- name: Install dependencies")); + const generation = workflow.slice(workflow.indexOf("- name: Generate changelog"), workflow.indexOf("- name: Run release checks")); + assert.match(generation, /npm run changelog:full/); + assert.match(generation, /npm run changelog:check/); + assert.match(generation, /npm run --silent release:notes/); + assert.doesNotMatch(generation, /npx pm-changelog/); + assert.match(workflow, /release_branch="\$RELEASE_BRANCH"/); + assert.match(workflow, /--force-with-lease=/); + assert.match(workflow, /gh pr edit "\$pr_number"/); + assert.match(workflow, /pr_number="\$RELEASE_PR_NUMBER"/); + assert.match(workflow, /RELEASE_PR_NUMBER: \$\{\{ steps.decide.outputs.pr_number \}\}/); + assert.equal(workflow.match(/gh pr list/g)?.length, 1); + assert.match(workflow, /--json number,headRefName,isCrossRepository,author/); + assert.doesNotMatch(workflow, /export RELEASE_EXISTING_PRS=/); + assert.ok(workflow.indexOf("Refusing to overwrite a release branch") < workflow.indexOf('origin ":refs/heads/${release_branch}"')); +}); + +test("a failed GitHub candidate lookup aborts instead of exporting an empty success", () => { + const workflow = readFileSync(new URL("../.github/workflows/release.yml", import.meta.url), "utf8"); + const lookup = workflow.slice(workflow.indexOf(' RELEASE_EXISTING_PRS="$('), workflow.indexOf(" node --input-type=module -e '")); + const result = spawnSync("bash", ["-c", `set -eu; gh() { return 47; }; ${lookup}\nprintf continued`], + { encoding: "utf8", env: { ...process.env, GITHUB_REPOSITORY: "example/package" } }); + assert.equal(result.status, 47); + assert.equal(result.stdout, ""); +}); + +test("the push and cleanup boundary refuses an existing ref without a selected workflow PR", () => { + const workflow = readFileSync(new URL("../.github/workflows/release.yml", import.meta.url), "utf8"); + const guard = workflow.slice(workflow.indexOf(' release_branch="$RELEASE_BRANCH"'), workflow.indexOf(' release_commit="$(git rev-parse HEAD)"')); + for (const [prNumber, ref, status] of [["", "existing-sha", 1], ["144", "existing-sha", 0], ["", "", 0]] as const) { + const result = spawnSync("bash", ["-c", `set -eu; git() { printf '%s' "$TEST_REF"; }; ${guard}`], + { encoding: "utf8", env: { ...process.env, RELEASE_BRANCH: "release/2026.10.18", RELEASE_PR_NUMBER: prNumber, TEST_REF: ref } }); + assert.equal(result.status, status, result.stderr); + if (status === 1) assert.match(result.stdout, /Refusing to overwrite/); + } +});