From 0f58f1096c33a9fa3d0e9482d64c7a01fc23a16d Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 14 Nov 2026 10:21:03 +0100 Subject: [PATCH 1/4] Fix reusable workflow extension version selection --- .../pm-github-workflow-own-release.jsonl | 16 ++ .../pm-github-workflow-own-release.toon | 29 ++ .github/workflows/pm-github-closeout.yml | 62 ++--- .github/workflows/pm-github-sync.yml | 62 ++--- CHANGELOG.md | 6 + README.md | 45 ++-- docs/scheduled-workflow-watch-1106.md | 9 +- docs/workflow-version-callers.md | 120 +++++++++ test/self-versioned-workflows.test.ts | 253 ++++++++++-------- 9 files changed, 389 insertions(+), 213 deletions(-) create mode 100644 .agents/pm/history/pm-github-workflow-own-release.jsonl create mode 100644 .agents/pm/issues/pm-github-workflow-own-release.toon create mode 100644 docs/workflow-version-callers.md diff --git a/.agents/pm/history/pm-github-workflow-own-release.jsonl b/.agents/pm/history/pm-github-workflow-own-release.jsonl new file mode 100644 index 00000000..0ee355d2 --- /dev/null +++ b/.agents/pm/history/pm-github-workflow-own-release.jsonl @@ -0,0 +1,16 @@ +{"hash_algorithm":"sha256","ts":"2026-11-14T09:04:23.981Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-workflow-own-release"},{"op":"add","path":"/metadata/title","value":"Default reusable workflows to their own package release; warn on deliberate version holds"},{"op":"add","path":"/metadata/description","value":"Fix #238: derive the default extension from package.json at job.workflow_sha, preserve validated explicit holds with a two-version warning, and preflight registry existence before tracker writes. Migration: callers must drop pm-github-version so Dependabot workflow updates also select the extension version, including the curated identity fix in 2026.11.14."},{"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-unreleased","gh:unbraind/pm-github#238","workflows"]},{"op":"add","path":"/metadata/created_at","value":"2026-11-14T09:04:23.981Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-11-14T09:04:23.981Z"},{"op":"add","path":"/metadata/author","value":"codex-github238-1114"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"fabf67c24a935e3fa26ac84937bbeb1746b0087d059d0d725075a5eddbc42cd6","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":"3d4d2d592c277fc50cb3f20e1b5056d137f1dabbd2a065fee241ec47a6d0d6fd"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:04:25.917Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:04:25.917Z"},{"op":"add","path":"/metadata/assignee","value":"codex-github238-1114"},{"op":"add","path":"/metadata/claim_principal","value":"codex-github238-1114"}],"before_hash":"fabf67c24a935e3fa26ac84937bbeb1746b0087d059d0d725075a5eddbc42cd6","after_hash":"bbf4203068fa68329280fef765f16dcdf0c1cb286cfd0bb1e944f4d82ba11b1a","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":"f942cba05807f514834fc161185c309f68d3515fa6d1f2f585ecf3bd3ec2a4ce"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:04:27.949Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:04:27.949Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"bbf4203068fa68329280fef765f16dcdf0c1cb286cfd0bb1e944f4d82ba11b1a","after_hash":"ab2114da2f668c07de8a5a172e33b37532cb392c000eec173f8fbe2d63432260","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":"a30c7571b00fcca265d469b055cda1cd5bf6103b743396669337864a1ba93f2a"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:04:30.564Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:04:30.564Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-11-14T09:04:30.564Z","author":"codex-github238-1114","text":"Plan: replace tag enumeration with a public package.json fetch at the reusable job workflow SHA, normalize exact numeric versions, honor explicit holds and warn with both versions, then check the selected exact registry release before any tracker write. Execute extracted workflow bash with real scratch pm trackers, cover the issue regression cases and behavioral reverts, document caller migration, and inventory public fleet callers through the contents API without changing them. Targeted gates follow the task brief; CI runs the full gate."}]}],"before_hash":"ab2114da2f668c07de8a5a172e33b37532cb392c000eec173f8fbe2d63432260","after_hash":"f892f4b445fba25aa07fb574182c684edba59c9424564fa808c7ac73e26320d7","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":"b08f04dcad31f9637e255c354fef7f156acd0eacbc570ad6bb280d1faaf692bc"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:09:29.562Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:09:29.562Z"},{"op":"add","path":"/metadata/files","value":[{"path":".github/workflows/pm-github-closeout.yml","scope":"project"},{"path":".github/workflows/pm-github-sync.yml","scope":"project"},{"path":"test/self-versioned-workflows.test.ts","scope":"project"}]}],"before_hash":"f892f4b445fba25aa07fb574182c684edba59c9424564fa808c7ac73e26320d7","after_hash":"b4746bc49e3bbaf9a5f41abf3ae00038fd89a52d5002b7ff4dcbe005aa8d6374","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":"f5f401533cce78328c71b065846b740b89ff6e00ef4ca741f9671c7c12eb4e8d"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:09:31.723Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:09:31.723Z"},{"op":"add","path":"/metadata/docs","value":[{"path":"docs/workflow-version-callers.md","scope":"project"},{"path":"README.md","scope":"project"}]}],"before_hash":"b4746bc49e3bbaf9a5f41abf3ae00038fd89a52d5002b7ff4dcbe005aa8d6374","after_hash":"814a2cc155d7d51f3d001dc3100ba748e513a6d2e7a4dcafdec2d58baf7416bc","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":"ffbfd3ac9779001164a2c8fae2c1106f222f1269828ec6ef85a444f979f6a8f1"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:09:34.287Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:09:34.287Z"},{"op":"add","path":"/metadata/tests","value":[{"command":"node --test --test-concurrency=2 test/self-versioned-workflows.test.ts","scope":"project","provenance":{"author":"codex-github238-1114","created_at":"2026-11-14T09:09:34.220Z","source_kind":"local_mutation","source_ref":"fix/workflow-installs-own-release"}}]}],"before_hash":"814a2cc155d7d51f3d001dc3100ba748e513a6d2e7a4dcafdec2d58baf7416bc","after_hash":"6f8d3a185e8753f5dd3c4946d4c9742f6a8f4bdf1dff358db3a097da8137c8ae","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":"7d2bf10898c98f5f2799dba1047c2a3ea9f6ac003de8246e70a4138bb7220683"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:12:12.957Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:12:12.957Z","author":"codex-github238-1114","text":"Design verified against GitHub Actions job context documentation: job.workflow_sha identifies the reusable job commit for both tag and SHA pins. Both workflows fetch their own package.json at that SHA, validate and normalize its version, honor explicit exact holds, and warn with both versions on a mismatch. Exact public registry metadata is checked before checkout/setup or tracker writes. Live transport smoke: omitted input resolved 2026.11.14; explicit 2026.10.16 remained 2026.10.16 with both versions in the warning; 2099.1.1 returned a refusal with no exported install version. Migration is in the item description and README: callers should drop pm-github-version."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:12:12.957Z"}],"before_hash":"6f8d3a185e8753f5dd3c4946d4c9742f6a8f4bdf1dff358db3a097da8137c8ae","after_hash":"fb1de0ce4480ccd7ed1bb41b6ab24fba2af107d243eef85a4384926019bf806f","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":"e9b089c4f3d7dfe281a05c467f0c1e4f980ba903e0f146f78112ed23b955bf56"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:12:15.098Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:12:15.097Z","author":"codex-github238-1114","text":"Behavioral revert proofs ran in disposable copies, leaving the fixed checkout untouched. Reverting only default selection: 4/4 selected tests fail. Ignoring explicit holds: 2/2 fail. Removing the two-version warning: 2/2 fail. Removing registry preflight: 2/2 fail, including a real tracker mutation sentinel. Restoring the entire origin/main resolver: all 8 selected issue regressions fail (omitted, padded default, older hold, unavailable version across both workflows). Each refusal case snapshots every real tracker byte including native history; successes perform a real pinned-pm local fixture extension installation. Baseline focused run: 58/58; additional malformed metadata cases are in the linked final run."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:12:15.098Z"}],"before_hash":"fb1de0ce4480ccd7ed1bb41b6ab24fba2af107d243eef85a4384926019bf806f","after_hash":"a2344fcdd4246b52f3f5f1044e082a0f3c2bf59fff2b42238a79f66809b75069","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":"694aa1e470828cf7e7d8803f664b02b679e78e6cc71feb6bf9d94836593cff5b"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:15:57.371Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:15:57.370Z","author":"codex-github238-1114","text":"Caller inventory complete: 217 workflow files read via public contents API across 37 canonical fleet repository names, zero unavailable reads; 51 calls in 28 repositories still provide pm-github-version. docs/workflow-version-callers.md records every caller file, exact reusable workflow pin, pin comment, input version, and contents blob SHA. No callers changed. Existing caller-adoption follow-up pm-github-samq can carry the later migration sweep. Focused workflow-order checks passed 2/2; typecheck, build:test and lint passed; privacy audited 9288 Git objects without findings; docstrings checked 33 files and 315 declarations. actionlint is unavailable. No authored TypeScript/JavaScript source modules changed (34 inventoried); full CI retains unchanged 100/100/100/100 coverage thresholds. The first linked run reached its default 120-second deadline; retry uses 300 seconds. A request to disable linked pm context in the source workspace was correctly refused, so the retry retains schema isolation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:15:57.371Z"}],"before_hash":"a2344fcdd4246b52f3f5f1044e082a0f3c2bf59fff2b42238a79f66809b75069","after_hash":"8aedf096869c7d3b26026954c210d0dda89179e048a5829972119744d77f3c3d","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":"e4df209281dc5a84b9108f296080856bfc0a3ccbde7f4d50fd5e776ffc27ea61"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:15:59.218Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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/files/2/path","value":"docs/scheduled-workflow-watch-1106.md"},{"op":"add","path":"/metadata/files/3","value":{"path":"test/self-versioned-workflows.test.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:15:59.218Z"}],"before_hash":"8aedf096869c7d3b26026954c210d0dda89179e048a5829972119744d77f3c3d","after_hash":"09995fce4ddbf90fc380dd8be9d6ac0b45163f325d2b3e75f27791f30595abd6","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":"a0cf0b7ece1baeb6be098c8011db313d375febed74c440399b5953ac01dadc66"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:19:21.792Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","agent_provenance":{"model":{"value":"gpt-6.1-sol","source":"probe"},"effort":{"value":"high","source":"probe"},"role":null,"topic":null},"op":"tests_update","patch":[{"op":"add","path":"/metadata/tests/0/timeout_seconds","value":600},{"op":"add","path":"/metadata/tests/0/updated_by","value":"codex-github238-1114"},{"op":"add","path":"/metadata/tests/0/updated_at","value":"2026-11-14T09:19:21.734Z"},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:19:21.792Z"},{"op":"add","path":"/metadata/pm_format_version","value":2}],"before_hash":"09995fce4ddbf90fc380dd8be9d6ac0b45163f325d2b3e75f27791f30595abd6","after_hash":"cb94477df4a7a10a860f83225df537f1cb1631fed4b61384ffb089710452eec3","item_hash_version":3,"context":{"linked_test_update":{"index":1,"fields":["timeout_seconds"]},"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":"7ea5c6094712adbca3c564244708068faff745eaf1ceb8e96fb058c6f5dd57df"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:19:26.407Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:19:26.367Z","author":"codex-github238-1114","text":"Final linked focused run passed 64/64 tests, zero failures/skips/cancellations, in 286.7 seconds using pm test --run --progress --timeout 300. This passing run followed the final disposable revert proofs (default 4 failures, hold 2, warning 2, existence 2, full old resolver 8). Linked-test timeout is now 600 seconds for slower shared execution; the first 120-second deadline was execution overhead, not an assertion failure. Additional workflow-order tests passed 2/2. npm run typecheck, npm run build:test, npm run lint, npm run privacy, npm run docstring and git diff --check passed; both changed workflows parse as YAML. actionlint was not installed. Full npm/Bun release and all-source coverage gates remain CI responsibilities under the targeted task brief. Remaining rollout work is caller pin adoption and removal of the 51 explicit holds; raw manifest/registry transport failure deliberately stops before writes. No pm SDK defect was observed; linked execution requires an explicit timeout for this real-installer test file."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:19:26.407Z"}],"before_hash":"cb94477df4a7a10a860f83225df537f1cb1631fed4b61384ffb089710452eec3","after_hash":"e421bfa3f5ccb8fef25d54d05b52b8e0ef862073c474a36404ac1cc52d237b0f","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":"97171dff35e29310b38ec98b333d8dc7a3e35ed46a043a6e03244a2c865b8e7e"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:19:32.474Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:19:32.474Z"}],"before_hash":"e421bfa3f5ccb8fef25d54d05b52b8e0ef862073c474a36404ac1cc52d237b0f","after_hash":"0486c6c40cfacafbb198eced14214d3842d613d8016de89b5d11233af040c664","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":"d54b6a3d7f087ce70c040483f72474e15502c7ed3f17d7f6e46cf2400eb26662"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:20:39.544Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:20:39.544Z"},{"op":"replace","path":"/metadata/title","value":"Default reusable workflows to their own release (migration: drop pm-github-version); warn on explicit holds"}],"before_hash":"0486c6c40cfacafbb198eced14214d3842d613d8016de89b5d11233af040c664","after_hash":"ae83130effab24743f525319578108b52f0df38a9e258be55f2a5124c0336dad","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":"8c63900e0c1c2d9b43e1691da95f63230e9fc033e2c6555726e1d33106f9cfb2"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:20:42.014Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:20:41.960Z","author":"codex-github238-1114","text":"Changelog generator renders item titles, so the migration instruction is also in this item title and is visible in release notes. Supplemental read-only strict health found one pre-existing local gate failure: pinned host pm-cli 2026.11.6 versus installed global pm-github host requirement 2026.11.13; tracker settings/directories/values/locks/integrity passed and seven older in-progress items are advisory. No dependency pin or global extension was changed. This environment condition is already recorded by the reference-identity work; clean CI owns the full gate. Changelog generation and check are rerun after this final tracker write."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:20:42.014Z"}],"before_hash":"ae83130effab24743f525319578108b52f0df38a9e258be55f2a5124c0336dad","after_hash":"de042ffa97f9e5a4d420449dc0a21d6a9e023fb0c3ef19dd3a9fd4f0c0a5bf54","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":"1f293b1e93f7804ef5d59584ff7427990172d1954338f8cd9d61124aa55a221c"} diff --git a/.agents/pm/issues/pm-github-workflow-own-release.toon b/.agents/pm/issues/pm-github-workflow-own-release.toon new file mode 100644 index 00000000..4f01f375 --- /dev/null +++ b/.agents/pm/issues/pm-github-workflow-own-release.toon @@ -0,0 +1,29 @@ +id: pm-github-workflow-own-release +title: "Default reusable workflows to their own release (migration: drop pm-github-version); warn on explicit holds" +description: "Fix #238: derive the default extension from package.json at job.workflow_sha, preserve validated explicit holds with a two-version warning, and preflight registry existence before tracker writes. Migration: callers must drop pm-github-version so Dependabot workflow updates also select the extension version, including the curated identity fix in 2026.11.14." +type: Issue +pm_format_version: 2 +status: in_progress +priority: 1 +tags[3]: changelog-unreleased,"gh:unbraind/pm-github#238",workflows +created_at: "2026-11-14T09:04:23.981Z" +updated_at: "2026-11-14T09:20:42.014Z" +author: codex-github238-1114 +comments[6]{created_at,author,text}: + "2026-11-14T09:04:30.564Z",codex-github238-1114,"Plan: replace tag enumeration with a public package.json fetch at the reusable job workflow SHA, normalize exact numeric versions, honor explicit holds and warn with both versions, then check the selected exact registry release before any tracker write. Execute extracted workflow bash with real scratch pm trackers, cover the issue regression cases and behavioral reverts, document caller migration, and inventory public fleet callers through the contents API without changing them. Targeted gates follow the task brief; CI runs the full gate." + "2026-11-14T09:12:12.957Z",codex-github238-1114,"Design verified against GitHub Actions job context documentation: job.workflow_sha identifies the reusable job commit for both tag and SHA pins. Both workflows fetch their own package.json at that SHA, validate and normalize its version, honor explicit exact holds, and warn with both versions on a mismatch. Exact public registry metadata is checked before checkout/setup or tracker writes. Live transport smoke: omitted input resolved 2026.11.14; explicit 2026.10.16 remained 2026.10.16 with both versions in the warning; 2099.1.1 returned a refusal with no exported install version. Migration is in the item description and README: callers should drop pm-github-version." + "2026-11-14T09:12:15.097Z",codex-github238-1114,"Behavioral revert proofs ran in disposable copies, leaving the fixed checkout untouched. Reverting only default selection: 4/4 selected tests fail. Ignoring explicit holds: 2/2 fail. Removing the two-version warning: 2/2 fail. Removing registry preflight: 2/2 fail, including a real tracker mutation sentinel. Restoring the entire origin/main resolver: all 8 selected issue regressions fail (omitted, padded default, older hold, unavailable version across both workflows). Each refusal case snapshots every real tracker byte including native history; successes perform a real pinned-pm local fixture extension installation. Baseline focused run: 58/58; additional malformed metadata cases are in the linked final run." + "2026-11-14T09:15:57.370Z",codex-github238-1114,"Caller inventory complete: 217 workflow files read via public contents API across 37 canonical fleet repository names, zero unavailable reads; 51 calls in 28 repositories still provide pm-github-version. docs/workflow-version-callers.md records every caller file, exact reusable workflow pin, pin comment, input version, and contents blob SHA. No callers changed. Existing caller-adoption follow-up pm-github-samq can carry the later migration sweep. Focused workflow-order checks passed 2/2; typecheck, build:test and lint passed; privacy audited 9288 Git objects without findings; docstrings checked 33 files and 315 declarations. actionlint is unavailable. No authored TypeScript/JavaScript source modules changed (34 inventoried); full CI retains unchanged 100/100/100/100 coverage thresholds. The first linked run reached its default 120-second deadline; retry uses 300 seconds. A request to disable linked pm context in the source workspace was correctly refused, so the retry retains schema isolation." + "2026-11-14T09:19:26.367Z",codex-github238-1114,"Final linked focused run passed 64/64 tests, zero failures/skips/cancellations, in 286.7 seconds using pm test --run --progress --timeout 300. This passing run followed the final disposable revert proofs (default 4 failures, hold 2, warning 2, existence 2, full old resolver 8). Linked-test timeout is now 600 seconds for slower shared execution; the first 120-second deadline was execution overhead, not an assertion failure. Additional workflow-order tests passed 2/2. npm run typecheck, npm run build:test, npm run lint, npm run privacy, npm run docstring and git diff --check passed; both changed workflows parse as YAML. actionlint was not installed. Full npm/Bun release and all-source coverage gates remain CI responsibilities under the targeted task brief. Remaining rollout work is caller pin adoption and removal of the 51 explicit holds; raw manifest/registry transport failure deliberately stops before writes. No pm SDK defect was observed; linked execution requires an explicit timeout for this real-installer test file." + "2026-11-14T09:20:41.960Z",codex-github238-1114,"Changelog generator renders item titles, so the migration instruction is also in this item title and is visible in release notes. Supplemental read-only strict health found one pre-existing local gate failure: pinned host pm-cli 2026.11.6 versus installed global pm-github host requirement 2026.11.13; tracker settings/directories/values/locks/integrity passed and seven older in-progress items are advisory. No dependency pin or global extension was changed. This environment condition is already recorded by the reference-identity work; clean CI owns the full gate. Changelog generation and check are rerun after this final tracker write." +files[4]{path,scope}: + .github/workflows/pm-github-closeout.yml,project + .github/workflows/pm-github-sync.yml,project + docs/scheduled-workflow-watch-1106.md,project + test/self-versioned-workflows.test.ts,project +tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref},updated_by,updated_at}: + node --test --test-concurrency=2 test/self-versioned-workflows.test.ts,project,600,codex-github238-1114,"2026-11-14T09:09:34.220Z",local_mutation,fix/workflow-installs-own-release,codex-github238-1114,"2026-11-14T09:19:21.734Z" +docs[2]{path,scope}: + docs/workflow-version-callers.md,project + README.md,project +body: "" diff --git a/.github/workflows/pm-github-closeout.yml b/.github/workflows/pm-github-closeout.yml index 04c8dd73..01688567 100644 --- a/.github/workflows/pm-github-closeout.yml +++ b/.github/workflows/pm-github-closeout.yml @@ -12,7 +12,7 @@ on: required: false default: ${{ github.repository }} pm-github-version: - description: "Deprecated: fallback only for a non-release commit; pin a release SHA instead" + description: "Deprecated exact extension hold; omit to follow the workflow release (differing holds warn)" type: string required: false default: "" @@ -132,20 +132,13 @@ jobs: run: | set -euo pipefail [[ "${WORKFLOW_SHA}" =~ ^[a-f0-9]{40}$ ]] || { echo "::error::Cannot identify the reusable workflow commit from job.workflow_sha."; exit 1; } - # No checkout, authentication, API pagination, or local tags involved. - remote_tags="$(git ls-remote --tags https://github.com/unbraind/pm-github 'refs/tags/v*')" || { echo "::error::Cannot read pm-github release tags; refusing an unverified install."; exit 1; } - declare -A tag_commits=() peeled_commits=() - while read -r sha ref; do - [[ "${sha}" =~ ^[a-f0-9]{40}$ ]] || continue - # Validate the whole tag before using it as an associative-array key. - # declare evaluates subscripts, so arbitrary remote refs are not operands. - grep -zEq '^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?(\^\{\})?$' < <(printf '%s\0' "${ref}") || continue - if [[ "${ref}" == *'^{}' ]]; then - declare "peeled_commits[${ref%'^{}'}]=${sha}" - elif [[ "${ref}" == refs/tags/v* ]]; then - declare "tag_commits[${ref}]=${sha}" - fi - done <<< "${remote_tags}" + # job.workflow_sha belongs to this reusable job, even for a tag pin. + # Fetch our manifest at that immutable commit; the caller checkout and + # release-tag spelling are never version authorities. + manifest="$(curl --fail --silent --show-error --location --retry 2 --max-time 60 \ + "https://raw.githubusercontent.com/unbraind/pm-github/${WORKFLOW_SHA}/package.json")" || { echo "::error::Cannot read pm-github package.json at the reusable workflow commit."; exit 1; } + workflow_version="$(jq -ser 'select(length == 1) | .[0] | select(.name == "pm-github") | .version | select(type == "string" and (contains("\n") | not) and (contains("\r") | not))' <<< "${manifest}" 2>/dev/null)" || { echo "::error::Invalid pm-github workflow package metadata."; exit 1; } + grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${workflow_version}") || { echo "::error::Workflow package version must be an exact numeric version: N.N.N or N.N.N-N."; exit 1; } # Release tags keep zero-padded date components (v2026.11.02) while the # daily release plan publishes npm versions without padding (2026.11.2), # so strip the padding from every component before comparing or installing. @@ -166,39 +159,20 @@ jobs: done printf '%s' "${normalized}${suffix:+-${suffix}}" } - PM_GITHUB_VERSION="" - for ref in "${!tag_commits[@]}"; do - # Annotated tags must match their peeled commit, never the tag object. - [[ "${peeled_commits[$ref]-${tag_commits[$ref]}}" == "${WORKFLOW_SHA}" ]] || continue - candidate="${ref#refs/tags/v}" - grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${candidate}") || continue - candidate="$(normalize_pm_github_version "${candidate}")" - if [[ -n "${PM_GITHUB_VERSION}" && "${PM_GITHUB_VERSION}" != "${candidate}" ]]; then - echo "::error::Multiple release versions tag this workflow commit; refusing an ambiguous install." - exit 1 - fi - PM_GITHUB_VERSION="${candidate}" - done - if [[ -z "${PM_GITHUB_VERSION}" ]]; then - if [[ -z "${REQUESTED_PM_GITHUB_VERSION}" ]]; then - echo "::error::No release tag matches this reusable workflow commit. Pin a release SHA (a commit tagged vN.N.N or vN.N.N-N)." - exit 1 - fi - echo "::warning::pm-github-version is deprecated; no release tag matches this workflow commit, so using the legacy input as a normalized version. Pin a release SHA instead." + workflow_version="$(normalize_pm_github_version "${workflow_version}")" + PM_GITHUB_VERSION="${workflow_version}" + if [[ -n "${REQUESTED_PM_GITHUB_VERSION}" ]]; then grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${REQUESTED_PM_GITHUB_VERSION}") || { echo "::error::pm-github-version must be an exact numeric version: N.N.N or N.N.N-N."; exit 1; } PM_GITHUB_VERSION="$(normalize_pm_github_version "${REQUESTED_PM_GITHUB_VERSION}")" - elif [[ -n "${REQUESTED_PM_GITHUB_VERSION}" ]]; then - requested="${REQUESTED_PM_GITHUB_VERSION}" - # An unparseable legacy input stays raw: it can never equal a validated - # tag version, so it only warns, and the arithmetic never sees it. - if grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${requested}"); then - requested="$(normalize_pm_github_version "${requested}")" - fi - if [[ "${requested}" != "${PM_GITHUB_VERSION}" ]]; then - echo "::warning::pm-github-version is deprecated and differs from the workflow release tag; using the tag version." + if [[ "${PM_GITHUB_VERSION}" != "${workflow_version}" ]]; then + echo "::warning::pm-github-version is deprecated: workflow ${workflow_version} installs extension ${PM_GITHUB_VERSION} as an explicit hold. Drop pm-github-version to follow the workflow release." fi fi - grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${PM_GITHUB_VERSION}") || { echo "::error::pm-github-version must be an exact numeric version: N.N.N or N.N.N-N."; exit 1; } + # Resolve existence before setup, extension installation, or tracker writes. + # Public registry reads require no npm configuration or credentials. + package="$(curl --fail --silent --show-error --location --retry 2 --max-time 60 \ + "https://registry.npmjs.org/pm-github/${PM_GITHUB_VERSION}")" || { echo "::error::Selected pm-github extension ${PM_GITHUB_VERSION} is unavailable; refusing tracker writes."; exit 1; } + jq -se --arg version "${PM_GITHUB_VERSION}" 'length == 1 and .[0].name == "pm-github" and .[0].version == $version' <<< "${package}" >/dev/null 2>&1 || { echo "::error::Registry metadata does not identify the selected pm-github version; refusing tracker writes."; exit 1; } printf 'PM_GITHUB_VERSION=%s\n' "${PM_GITHUB_VERSION}" >> "${GITHUB_ENV}" - name: Validate closeout inputs diff --git a/.github/workflows/pm-github-sync.yml b/.github/workflows/pm-github-sync.yml index 58f5ec16..292fd642 100644 --- a/.github/workflows/pm-github-sync.yml +++ b/.github/workflows/pm-github-sync.yml @@ -29,7 +29,7 @@ on: required: false default: false pm-github-version: - description: "Deprecated: fallback only for a non-release commit; pin a release SHA instead" + description: "Deprecated exact extension hold; omit to follow the workflow release (differing holds warn)" type: string required: false default: "" @@ -132,20 +132,13 @@ jobs: run: | set -euo pipefail [[ "${WORKFLOW_SHA}" =~ ^[a-f0-9]{40}$ ]] || { echo "::error::Cannot identify the reusable workflow commit from job.workflow_sha."; exit 1; } - # No checkout, authentication, API pagination, or local tags involved. - remote_tags="$(git ls-remote --tags https://github.com/unbraind/pm-github 'refs/tags/v*')" || { echo "::error::Cannot read pm-github release tags; refusing an unverified install."; exit 1; } - declare -A tag_commits=() peeled_commits=() - while read -r sha ref; do - [[ "${sha}" =~ ^[a-f0-9]{40}$ ]] || continue - # Validate the whole tag before using it as an associative-array key. - # declare evaluates subscripts, so arbitrary remote refs are not operands. - grep -zEq '^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?(\^\{\})?$' < <(printf '%s\0' "${ref}") || continue - if [[ "${ref}" == *'^{}' ]]; then - declare "peeled_commits[${ref%'^{}'}]=${sha}" - elif [[ "${ref}" == refs/tags/v* ]]; then - declare "tag_commits[${ref}]=${sha}" - fi - done <<< "${remote_tags}" + # job.workflow_sha belongs to this reusable job, even for a tag pin. + # Fetch our manifest at that immutable commit; the caller checkout and + # release-tag spelling are never version authorities. + manifest="$(curl --fail --silent --show-error --location --retry 2 --max-time 60 \ + "https://raw.githubusercontent.com/unbraind/pm-github/${WORKFLOW_SHA}/package.json")" || { echo "::error::Cannot read pm-github package.json at the reusable workflow commit."; exit 1; } + workflow_version="$(jq -ser 'select(length == 1) | .[0] | select(.name == "pm-github") | .version | select(type == "string" and (contains("\n") | not) and (contains("\r") | not))' <<< "${manifest}" 2>/dev/null)" || { echo "::error::Invalid pm-github workflow package metadata."; exit 1; } + grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${workflow_version}") || { echo "::error::Workflow package version must be an exact numeric version: N.N.N or N.N.N-N."; exit 1; } # Release tags keep zero-padded date components (v2026.11.02) while the # daily release plan publishes npm versions without padding (2026.11.2), # so strip the padding from every component before comparing or installing. @@ -166,39 +159,20 @@ jobs: done printf '%s' "${normalized}${suffix:+-${suffix}}" } - PM_GITHUB_VERSION="" - for ref in "${!tag_commits[@]}"; do - # Annotated tags must match their peeled commit, never the tag object. - [[ "${peeled_commits[$ref]-${tag_commits[$ref]}}" == "${WORKFLOW_SHA}" ]] || continue - candidate="${ref#refs/tags/v}" - grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${candidate}") || continue - candidate="$(normalize_pm_github_version "${candidate}")" - if [[ -n "${PM_GITHUB_VERSION}" && "${PM_GITHUB_VERSION}" != "${candidate}" ]]; then - echo "::error::Multiple release versions tag this workflow commit; refusing an ambiguous install." - exit 1 - fi - PM_GITHUB_VERSION="${candidate}" - done - if [[ -z "${PM_GITHUB_VERSION}" ]]; then - if [[ -z "${REQUESTED_PM_GITHUB_VERSION}" ]]; then - echo "::error::No release tag matches this reusable workflow commit. Pin a release SHA (a commit tagged vN.N.N or vN.N.N-N)." - exit 1 - fi - echo "::warning::pm-github-version is deprecated; no release tag matches this workflow commit, so using the legacy input as a normalized version. Pin a release SHA instead." + workflow_version="$(normalize_pm_github_version "${workflow_version}")" + PM_GITHUB_VERSION="${workflow_version}" + if [[ -n "${REQUESTED_PM_GITHUB_VERSION}" ]]; then grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${REQUESTED_PM_GITHUB_VERSION}") || { echo "::error::pm-github-version must be an exact numeric version: N.N.N or N.N.N-N."; exit 1; } PM_GITHUB_VERSION="$(normalize_pm_github_version "${REQUESTED_PM_GITHUB_VERSION}")" - elif [[ -n "${REQUESTED_PM_GITHUB_VERSION}" ]]; then - requested="${REQUESTED_PM_GITHUB_VERSION}" - # An unparseable legacy input stays raw: it can never equal a validated - # tag version, so it only warns, and the arithmetic never sees it. - if grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${requested}"); then - requested="$(normalize_pm_github_version "${requested}")" - fi - if [[ "${requested}" != "${PM_GITHUB_VERSION}" ]]; then - echo "::warning::pm-github-version is deprecated and differs from the workflow release tag; using the tag version." + if [[ "${PM_GITHUB_VERSION}" != "${workflow_version}" ]]; then + echo "::warning::pm-github-version is deprecated: workflow ${workflow_version} installs extension ${PM_GITHUB_VERSION} as an explicit hold. Drop pm-github-version to follow the workflow release." fi fi - grep -zEq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$' < <(printf '%s\0' "${PM_GITHUB_VERSION}") || { echo "::error::pm-github-version must be an exact numeric version: N.N.N or N.N.N-N."; exit 1; } + # Resolve existence before setup, extension installation, or tracker writes. + # Public registry reads require no npm configuration or credentials. + package="$(curl --fail --silent --show-error --location --retry 2 --max-time 60 \ + "https://registry.npmjs.org/pm-github/${PM_GITHUB_VERSION}")" || { echo "::error::Selected pm-github extension ${PM_GITHUB_VERSION} is unavailable; refusing tracker writes."; exit 1; } + jq -se --arg version "${PM_GITHUB_VERSION}" 'length == 1 and .[0].name == "pm-github" and .[0].version == $version' <<< "${package}" >/dev/null 2>&1 || { echo "::error::Registry metadata does not identify the selected pm-github version; refusing tracker writes."; exit 1; } printf 'PM_GITHUB_VERSION=%s\n' "${PM_GITHUB_VERSION}" >> "${GITHUB_ENV}" - name: Validate sync inputs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6733108f..0cc67411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixed + +- Default reusable workflows to their own release (migration: drop pm-github-version); warn on explicit holds ([pm-github-workflow-own-release](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-workflow-own-release.toon)) + ## 2026.11.14 - 2026-11-14 ### Fixed diff --git a/README.md b/README.md index c04385c5..c650b781 100644 --- a/README.md +++ b/README.md @@ -984,22 +984,35 @@ workflow. `github.job_workflow_sha` is not a documented context property; never used to discover the reusable workflow's version. These workflow identity context properties are not available on GitHub Enterprise Server. -The resolver uses public `git ls-remote --tags https://github.com/unbraind/pm-github -'refs/tags/v*'`. It matches lightweight tags directly and annotated tags by their -peeled `^{}` commit (never the tag object), strips `v`, and requires an exact -numeric version `N.N.N` or `N.N.N-N`. It reads all matching refs in one request, -without API pagination or new credentials. Lookup errors and multiple release -versions on one commit fail closed. Release version discovery needs no GitHub App, and no release-time workflow -stamping is required. The release workflow keeps its existing token behavior. - -Pin **release commit SHAs**, with their matching tag in a same-line comment -(for example `uses: unbraind/pm-github/.github/workflows/pm-github-sync.yml@<40-character-release-sha> # v2026.10.16`). -New callers omit `pm-github-version`. If no release tag matches the workflow -commit, the job fails with instructions to pin a release SHA. For compatibility, -a nonempty deprecated input provides an exact-version fallback with a warning -only when no tag matches. If a tag matches and the input differs, the job warns -and uses the tag version. Untrusted input is passed through `env:`, never inserted -into shell source or warning text. No `latest`, range, or floating install tag is used. +The resolver fetches public `package.json` from +`https://raw.githubusercontent.com/unbraind/pm-github//package.json`. +It validates the package name and exact numeric version `N.N.N` or `N.N.N-N`, +then strips leading zeros from date components as the daily release plan does +(for example `v2026.11.04` publishes `2026.11.4`). The SHA is resolved by GitHub +for both SHA and tag pins; no ref string parsing, local tags, mutable branch, +or caller package metadata participates. Missing or invalid workflow metadata +fails closed even with an explicit input. Release version discovery needs no +GitHub App, and no release-time workflow stamping is required. The release +workflow keeps its existing token behavior. + +**Migration:** remove `pm-github-version` from existing callers. Pin the workflow +release SHA and keep its same-line release tag comment for Dependabot. With the +input omitted, a workflow pin update also updates the installed extension, +including the curated import identity fix released in `2026.11.14`. +An explicit exact version remains a deliberate hold: a differing value is +honored and emits `::warning::` naming both the workflow and extension versions. +Both values are validated and normalized before comparison or diagnostic output. +No `latest`, range, or floating install tag is accepted. + +Before checkout/setup can write any tracker data, the resolver verifies the +selected extension using the public exact-version npm registry endpoint +`https://registry.npmjs.org/pm-github/` and checks its name and version. +A missing release, network error, or invalid response stops the job before +tracker writes. Installation still verifies the installed version independently. +An untagged development commit uses its own manifest version and therefore +requires that exact version to be published; an explicit published hold may +be used for development. See [the caller inventory](docs/workflow-version-callers.md) +for the follow-up migration sweep; this change does not edit callers. GitHub documents [reusable-workflow updates](https://docs.github.com/en/code-security/how-tos/secure-your-supply-chain/secure-your-dependencies/auto-update-actions) and [SHA pins and same-line version comments](https://docs.github.com/en/code-security/reference/supply-chain-security/supported-ecosystems-and-repositories#github-actions). diff --git a/docs/scheduled-workflow-watch-1106.md b/docs/scheduled-workflow-watch-1106.md index 0bc934a3..8eea56bf 100644 --- a/docs/scheduled-workflow-watch-1106.md +++ b/docs/scheduled-workflow-watch-1106.md @@ -21,9 +21,12 @@ about a later default branch or rerun. No caller repository was modified. | Planned source content fails privacy scan | Sync: pm-jev. | [job](https://github.com/unbraind/pm-jev/actions/runs/42207291810/job/127857017395), annotation: item `pm-jev-admission-teardown`, field `body`, rule `absolute-host-path`. | Caller-owned source remediation or reviewed content-addressed allowlist. Latest package removes one historical finding but retains another; no matched values are published here. | | Closeout hides the command's actual stderr | Closeout: pm-brief, pm-changelog, pm-context, pm-csv, pm-gantt-chart, pm-jira, pm-linear, pm-rl, pm-slack, pm-slack-standup, pm-vcs. | [pm-slack job](https://github.com/unbraind/pm-slack/actions/runs/42210316609/job/127867049216), [pm-context job](https://github.com/unbraind/pm-context/actions/runs/42210348997/job/127867158497). Both expose only the generic token/validation message. A pm-slack read-only local replay reveals `Unverifiable GitHub pagination.` | These pins precede numeric repository pagination and actionable diagnostic fixes. Adopt 2026.11.4 or later. All eleven callers currently return a numeric next-page URL on the first 100-PR REST page, which their pinned guard rejects. Historical hidden stderr is unavailable; later required-check or close-validation refusals remain independently actionable. This PR also handles plain host stderr and redacts candidate diagnostics before the existing final privacy scan. | -The deprecated `pm-github-version` input does **not** override a release-tagged -workflow SHA. Removing a stale input removes a warning; it does not repair any -of the failures above. No ambiguity error was observed in the sampled install +At the time of this watch, the deprecated `pm-github-version` input did **not** +override a release-tagged workflow SHA. Issue #238 subsequently changes this +contract: an explicit hold is honored with a two-version warning; callers should +remove the input to follow the workflow manifest version. For the historical +runs above, removing a stale input only removed a warning; it did not repair +those failures. No ambiguity error was observed in the sampled install failures: the failure occurred after installation in the exact-version verifier. ## Disposable public-data replays diff --git a/docs/workflow-version-callers.md b/docs/workflow-version-callers.md new file mode 100644 index 00000000..5d476086 --- /dev/null +++ b/docs/workflow-version-callers.md @@ -0,0 +1,120 @@ +# Fleet workflow extension holds + +Public default-branch contents API scan completed: 2026-11-14 09:14 UTC. +Scanned 37 canonical fleet repository names and read 217 workflow files through `gh api repos/unbraind//contents/.github/workflows/`. Private repositories are excluded. No caller was edited. + +Migration: remove `pm-github-version` in a follow-up sweep after adopting the release containing #238. Keep the Dependabot-maintained workflow SHA and release comment. Explicit holds continue to install the requested version and warn when it differs from the workflow release. + +| Caller | Workflow file | Reusable workflow | Current pin | Pin comment | Input version | +| --- | --- | --- | --- | --- | --- | +| [pm-ado](https://github.com/unbraind/pm-ado) | [pm-github-closeout.yml](https://github.com/unbraind/pm-ado/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-ado](https://github.com/unbraind/pm-ado) | [pm-github-sync.yml](https://github.com/unbraind/pm-ado/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-beads](https://github.com/unbraind/pm-beads) | [pm-github-closeout.yml](https://github.com/unbraind/pm-beads/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-beads](https://github.com/unbraind/pm-beads) | [pm-github-sync.yml](https://github.com/unbraind/pm-beads/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-brief](https://github.com/unbraind/pm-brief) | [pm-github-closeout.yml](https://github.com/unbraind/pm-brief/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-brief](https://github.com/unbraind/pm-brief) | [pm-github-sync.yml](https://github.com/unbraind/pm-brief/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-changelog](https://github.com/unbraind/pm-changelog) | [pm-github-closeout.yml](https://github.com/unbraind/pm-changelog/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-changelog](https://github.com/unbraind/pm-changelog) | [pm-github-sync.yml](https://github.com/unbraind/pm-changelog/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-context](https://github.com/unbraind/pm-context) | [pm-github-closeout.yml](https://github.com/unbraind/pm-context/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-context](https://github.com/unbraind/pm-context) | [pm-github-sync.yml](https://github.com/unbraind/pm-context/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-csv](https://github.com/unbraind/pm-csv) | [pm-github-closeout.yml](https://github.com/unbraind/pm-csv/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-csv](https://github.com/unbraind/pm-csv) | [pm-github-sync.yml](https://github.com/unbraind/pm-csv/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-evidence](https://github.com/unbraind/pm-evidence) | [pm-github-sync.yml](https://github.com/unbraind/pm-evidence/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `a935d7b9cefde7c5099e552914653217e1024c3f` | pm-github 2026.11.02 | `2026.10.19` | +| [pm-gantt-chart](https://github.com/unbraind/pm-gantt-chart) | [pm-github-closeout.yml](https://github.com/unbraind/pm-gantt-chart/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-gantt-chart](https://github.com/unbraind/pm-gantt-chart) | [pm-github-sync.yml](https://github.com/unbraind/pm-gantt-chart/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-http](https://github.com/unbraind/pm-http) | [pm-github-sync.yml](https://github.com/unbraind/pm-http/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.28` | +| [pm-hypothesis](https://github.com/unbraind/pm-hypothesis) | [pm-github-sync.yml](https://github.com/unbraind/pm-hypothesis/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.24` | +| [pm-jev](https://github.com/unbraind/pm-jev) | [pm-github-closeout.yml](https://github.com/unbraind/pm-jev/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-jev](https://github.com/unbraind/pm-jev) | [pm-github-sync.yml](https://github.com/unbraind/pm-jev/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-jira](https://github.com/unbraind/pm-jira) | [pm-github-closeout.yml](https://github.com/unbraind/pm-jira/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-jira](https://github.com/unbraind/pm-jira) | [pm-github-sync.yml](https://github.com/unbraind/pm-jira/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-linear](https://github.com/unbraind/pm-linear) | [pm-github-closeout.yml](https://github.com/unbraind/pm-linear/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-linear](https://github.com/unbraind/pm-linear) | [pm-github-sync.yml](https://github.com/unbraind/pm-linear/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-lint](https://github.com/unbraind/pm-lint) | [pm-github-closeout.yml](https://github.com/unbraind/pm-lint/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-lint](https://github.com/unbraind/pm-lint) | [pm-github-sync.yml](https://github.com/unbraind/pm-lint/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-memory](https://github.com/unbraind/pm-memory) | [pm-github-sync.yml](https://github.com/unbraind/pm-memory/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.19` | +| [pm-ops](https://github.com/unbraind/pm-ops) | [pm-github-closeout.yml](https://github.com/unbraind/pm-ops/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-ops](https://github.com/unbraind/pm-ops) | [pm-github-sync.yml](https://github.com/unbraind/pm-ops/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-presets](https://github.com/unbraind/pm-presets) | [pm-github-closeout.yml](https://github.com/unbraind/pm-presets/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-presets](https://github.com/unbraind/pm-presets) | [pm-github-sync.yml](https://github.com/unbraind/pm-presets/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-review](https://github.com/unbraind/pm-review) | [pm-github-closeout.yml](https://github.com/unbraind/pm-review/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-review](https://github.com/unbraind/pm-review) | [pm-github-sync.yml](https://github.com/unbraind/pm-review/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-rl](https://github.com/unbraind/pm-rl) | [pm-github-closeout.yml](https://github.com/unbraind/pm-rl/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-rl](https://github.com/unbraind/pm-rl) | [pm-github-sync.yml](https://github.com/unbraind/pm-rl/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-rlm](https://github.com/unbraind/pm-rlm) | [pm-github-sync.yml](https://github.com/unbraind/pm-rlm/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-rust](https://github.com/unbraind/pm-rust) | [pm-github-closeout.yml](https://github.com/unbraind/pm-rust/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-rust](https://github.com/unbraind/pm-rust) | [pm-github-sync.yml](https://github.com/unbraind/pm-rust/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-slack](https://github.com/unbraind/pm-slack) | [pm-github-closeout.yml](https://github.com/unbraind/pm-slack/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-slack](https://github.com/unbraind/pm-slack) | [pm-github-sync.yml](https://github.com/unbraind/pm-slack/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-slack-standup](https://github.com/unbraind/pm-slack-standup) | [pm-github-closeout.yml](https://github.com/unbraind/pm-slack-standup/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | v2026.11.04 | `2026.10.16` | +| [pm-slack-standup](https://github.com/unbraind/pm-slack-standup) | [pm-github-sync.yml](https://github.com/unbraind/pm-slack-standup/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | v2026.11.04 | `2026.10.16` | +| [pm-starter](https://github.com/unbraind/pm-starter) | [pm-github-closeout.yml](https://github.com/unbraind/pm-starter/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-starter](https://github.com/unbraind/pm-starter) | [pm-github-sync.yml](https://github.com/unbraind/pm-starter/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-swarm](https://github.com/unbraind/pm-swarm) | [pm-github-closeout.yml](https://github.com/unbraind/pm-swarm/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-swarm](https://github.com/unbraind/pm-swarm) | [pm-github-sync.yml](https://github.com/unbraind/pm-swarm/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-todos](https://github.com/unbraind/pm-todos) | [pm-github-closeout.yml](https://github.com/unbraind/pm-todos/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-todos](https://github.com/unbraind/pm-todos) | [pm-github-sync.yml](https://github.com/unbraind/pm-todos/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-ts-starter](https://github.com/unbraind/pm-ts-starter) | [pm-github-closeout.yml](https://github.com/unbraind/pm-ts-starter/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-ts-starter](https://github.com/unbraind/pm-ts-starter) | [pm-github-sync.yml](https://github.com/unbraind/pm-ts-starter/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-vcs](https://github.com/unbraind/pm-vcs) | [pm-github-closeout.yml](https://github.com/unbraind/pm-vcs/blob/main/.github/workflows/pm-github-closeout.yml) | `pm-github-closeout.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | +| [pm-vcs](https://github.com/unbraind/pm-vcs) | [pm-github-sync.yml](https://github.com/unbraind/pm-vcs/blob/main/.github/workflows/pm-github-sync.yml) | `pm-github-sync.yml` | `eb89c6a19ecf6301cd074f3dfb36c7da36135f90` | pm-github 2026.11.04 | `2026.10.16` | + +51 calls across 28 repositories still supply the input. + +## Content receipts + +Git blob SHAs of the workflow files above; the inventory describes this snapshot only. + +| Caller / file | Contents blob SHA | +| --- | --- | +| pm-ado / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-ado / pm-github-sync.yml | `491d597b05a5de56fc60828aae573bd46b572e5b` | +| pm-beads / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-beads / pm-github-sync.yml | `200ddcdece64ebc7ddbc2cf869ef78387d00c9ef` | +| pm-brief / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-brief / pm-github-sync.yml | `da793ddc78eb4f192aaa1374d178d0a42f47c111` | +| pm-changelog / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-changelog / pm-github-sync.yml | `451a8c80209acd9e0cf4fd22cb14a334be1ca951` | +| pm-context / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-context / pm-github-sync.yml | `491d597b05a5de56fc60828aae573bd46b572e5b` | +| pm-csv / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-csv / pm-github-sync.yml | `200ddcdece64ebc7ddbc2cf869ef78387d00c9ef` | +| pm-evidence / pm-github-sync.yml | `798ea9d0279de35f93b1b4912dc23dbf2b6d9bfe` | +| pm-gantt-chart / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-gantt-chart / pm-github-sync.yml | `491d597b05a5de56fc60828aae573bd46b572e5b` | +| pm-http / pm-github-sync.yml | `6bcbb4a19a9563fbc4c7dad4a752d5dca555920c` | +| pm-hypothesis / pm-github-sync.yml | `8fb88eb47d6a8e569d8e15a87c36d96693c4447d` | +| pm-jev / pm-github-closeout.yml | `9f3b13e8d2bdb739c0b717a3754edd6be4e0ada7` | +| pm-jev / pm-github-sync.yml | `bf24cf138c54edcbbeaccad5b580e1f990898720` | +| pm-jira / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-jira / pm-github-sync.yml | `451a8c80209acd9e0cf4fd22cb14a334be1ca951` | +| pm-linear / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-linear / pm-github-sync.yml | `da793ddc78eb4f192aaa1374d178d0a42f47c111` | +| pm-lint / pm-github-closeout.yml | `38709d463904942fbf800a45963a9d544e6b378d` | +| pm-lint / pm-github-sync.yml | `d49f6bafa1234490c5bf59db48c42bbc03843708` | +| pm-memory / pm-github-sync.yml | `b56226445786fcc338361c12c6a98f936dd4ae8f` | +| pm-ops / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-ops / pm-github-sync.yml | `491d597b05a5de56fc60828aae573bd46b572e5b` | +| pm-presets / pm-github-closeout.yml | `2abe5c332c5cc525e2cc5e0d948e9d6e3b6753e2` | +| pm-presets / pm-github-sync.yml | `451a8c80209acd9e0cf4fd22cb14a334be1ca951` | +| pm-review / pm-github-closeout.yml | `533f69847bedeb36217761ef7cee2e26d06dca93` | +| pm-review / pm-github-sync.yml | `9eb2b196a77fc6909ae8bdbb98e83520a0f798e0` | +| pm-rl / pm-github-closeout.yml | `292ecd5b16ffb9f80c7b0691730a4ed302199054` | +| pm-rl / pm-github-sync.yml | `ace3c2fc93bde30b5b8e1b3a39079dde9ff0d4ce` | +| pm-rlm / pm-github-sync.yml | `927648b7646f0d788f5715bdf8bc1f4c6760df89` | +| pm-rust / pm-github-closeout.yml | `22a990f0dd958b5eb8ca04a606192cc4c555c7a2` | +| pm-rust / pm-github-sync.yml | `368132ea9d46fa293d02ac2dbfb02e489a738f14` | +| pm-slack / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-slack / pm-github-sync.yml | `491d597b05a5de56fc60828aae573bd46b572e5b` | +| pm-slack-standup / pm-github-closeout.yml | `fd228b6cafddf85e9644f119ab3c3975e4d232e7` | +| pm-slack-standup / pm-github-sync.yml | `43bf182284e73da1c59e24806dca3082d31c5968` | +| pm-starter / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-starter / pm-github-sync.yml | `200ddcdece64ebc7ddbc2cf869ef78387d00c9ef` | +| pm-swarm / pm-github-closeout.yml | `28b65f3fb7cd582052db100edaf3149cbaa4f126` | +| pm-swarm / pm-github-sync.yml | `de2e09cd72047976e01637e470c77f3ad553f02f` | +| pm-todos / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-todos / pm-github-sync.yml | `da793ddc78eb4f192aaa1374d178d0a42f47c111` | +| pm-ts-starter / pm-github-closeout.yml | `7a95e866ac022111d4102f05cd0e3c0c7b7607c3` | +| pm-ts-starter / pm-github-sync.yml | `451a8c80209acd9e0cf4fd22cb14a334be1ca951` | +| pm-vcs / pm-github-closeout.yml | `c3373b2f7da2ec441c904e532b32b0a514ec6640` | +| pm-vcs / pm-github-sync.yml | `d72b6616a5893e37a2b6625a03f403927e44a585` | diff --git a/test/self-versioned-workflows.test.ts b/test/self-versioned-workflows.test.ts index a7154acb..0f17b8f9 100644 --- a/test/self-versioned-workflows.test.ts +++ b/test/self-versioned-workflows.test.ts @@ -1,18 +1,19 @@ -/** Execute release-tag resolution and exact installation from the real workflows. */ +/** Execute manifest-based resolution and real package installation from workflow bash. */ import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import test from "node:test"; import { decideDailyRelease } from "../scripts/daily-release-plan.ts"; const root = resolve(import.meta.dirname, ".."); +const cli = join(root, "node_modules/.bin/pm"); const files = [".github/workflows/pm-github-sync.yml", ".github/workflows/pm-github-closeout.yml"]; const release = readFileSync(join(root, ".github/workflows/release.yml"), "utf8"); const workflowSha = "a".repeat(40); -const otherSha = "b".repeat(40); const version = "2027.1.2-3"; +const template = mkdtempSync(join(tmpdir(), "workflow-tracker-template-")); /** Extract one named step's real bash without executing adjacent steps. */ function shell(source: string, name: string): string { @@ -29,116 +30,183 @@ function fixture(run: (cwd: string) => void): void { try { run(cwd); } finally { rmSync(cwd, { recursive: true, force: true }); } } -/** Execute real bash steps with an explicit environment and bounded runtime. */ +/** Execute real bash steps with isolated pm configuration and bounded runtime. */ function bash(cwd: string, script: string, env: NodeJS.ProcessEnv = {}) { - return spawnSync("bash", ["-c", script], { cwd, env: { ...process.env, ...env }, encoding: "utf8", timeout: 30_000 }); + const childEnv: NodeJS.ProcessEnv = { ...process.env, ...env, PM_AUTHOR: "fixture", PM_TELEMETRY_INLINE_FLUSH: "1", + PM_GLOBAL_PATH: join(cwd, "global"), PM_PATH: join(cwd, ".agents/pm"), NPM_CONFIG_USERCONFIG: "/dev/null" }; + for (const key of ["NPM_TOKEN", "NODE_AUTH_TOKEN", "NPM_MEDIA_SERVER"]) delete childEnv[key]; + return spawnSync("bash", ["-c", script], { cwd, env: childEnv, encoding: "utf8", timeout: 30_000 }); } -/** Inject only remote transport and package installation, retaining real resolver bash. */ +test.before(() => { + const init = bash(template, '"$REAL_PM" init fixture --defaults --agent-guidance skip', { REAL_PM: cli }); + assert.equal(init.status, 0, init.stderr + init.stdout); + const seed = bash(template, '"$REAL_PM" create task "Existing curated item" --id curated --description "Curated content"', { REAL_PM: cli }); + assert.equal(seed.status, 0, seed.stderr + seed.stdout); +}); +test.after(() => rmSync(template, { recursive: true, force: true })); + +/** Snapshot every durable tracker byte, including native append-only history. */ +function snapshot(directory: string): Record { + return Object.fromEntries(readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name)) + .flatMap(entry => entry.isDirectory() + ? Object.entries(snapshot(join(directory, entry.name))).map(([key, value]) => [entry.name + "/" + key, value]) + : [[entry.name, readFileSync(join(directory, entry.name)).toString("base64")]])); +} + +/** Replace external HTTP transport only; local fixture installation uses the real pinned pm. */ function setup(cwd: string): NodeJS.ProcessEnv { + cpSync(join(template, ".agents"), join(cwd, ".agents"), { recursive: true }); mkdirSync(join(cwd, "bin")); - mkdirSync(join(cwd, ".agents/pm/extensions/pm-github"), { recursive: true }); - writeFileSync(join(cwd, "bin/git"), `#!/usr/bin/env bash + mkdirSync(join(cwd, "packages")); + // Deliberately unrelated caller metadata must never determine the installed version. + writeFileSync(join(cwd, "package.json"), '{"name":"caller","version":"1999.1.1"}'); + writeFileSync(join(cwd, "bin/curl"), `#!/usr/bin/env bash set -euo pipefail -[[ "$#" == 4 && "$1" == ls-remote && "$2" == --tags && "$3" == https://github.com/unbraind/pm-github && "$4" == 'refs/tags/v*' ]] || exit 95 -printf '%s\\n' "$REMOTE_TAGS" -exit "\${REMOTE_STATUS:-0}" +url="\${@: -1}" +printf '%s\\n' "$url" >> http-receipt +case "$url" in + "https://raw.githubusercontent.com/unbraind/pm-github/$WORKFLOW_SHA/package.json") + printf '%s' "$WORKFLOW_MANIFEST"; exit "\${MANIFEST_STATUS:-0}" ;; + "https://registry.npmjs.org/pm-github/"*) + selected="\${url##*/}" + [[ "$selected" != "\${MISSING_VERSION:-}" ]] || exit 22 + [[ "\${REGISTRY_STATUS:-0}" == 0 ]] || exit "$REGISTRY_STATUS" + if [[ -n "\${REGISTRY_METADATA:-}" ]]; then printf '%s' "$REGISTRY_METADATA"; else + printf '{"name":"pm-github","version":"%s"}' "$selected" + fi ;; + *) exit 95 ;; +esac `, { mode: 0o755 }); writeFileSync(join(cwd, "bin/pm"), `#!/usr/bin/env bash set -euo pipefail -[[ "$1" == package && "$2" == install && "$4" == --project ]] -printf '%s\\n' "$3" > receipt -printf '{"version":"%s"}' "\${INSTALLED_VERSION:-\${3#npm:pm-github@}}" > "$PM_SYNC_TRACKER/extensions/pm-github/package.json" +if [[ "$1 $2" == 'package install' ]]; then + [[ "$3" == npm:pm-github@* && "$4" == --project ]] || exit 95 + printf '%s\\n' "$3" > receipt + exec "$REAL_PM" package install "$FIXTURE_PACKAGES/\${3#npm:pm-github@}" --project +fi +exec "$REAL_PM" "$@" `, { mode: 0o755 }); - return { WORKFLOW_SHA: workflowSha, REMOTE_TAGS: "", REMOTE_STATUS: "0", INSTALLED_VERSION: "", - REQUESTED_PM_GITHUB_VERSION: "", GITHUB_ENV: join(cwd, "github-env"), - PM_SYNC_TRACKER: ".agents/pm", PATH: join(cwd, "bin") + ":" + process.env.PATH }; + return { WORKFLOW_SHA: workflowSha, WORKFLOW_MANIFEST: JSON.stringify({ name: "pm-github", version }), + REQUESTED_PM_GITHUB_VERSION: "", GITHUB_ENV: join(cwd, "github-env"), REAL_PM: cli, + PM_SYNC_TRACKER: ".agents/pm", FIXTURE_PACKAGES: join(cwd, "packages"), RUNNER_TEMP: cwd, + PATH: join(cwd, "bin") + ":" + process.env.PATH }; +} + +/** Supply a minimal real local extension, avoiding npm downloads while retaining pm installation. */ +function packageFixture(cwd: string, selected: string): void { + const directory = join(cwd, "packages", selected); + mkdirSync(directory, { recursive: true }); + writeFileSync(join(directory, "package.json"), JSON.stringify({ name: "pm-github", version: selected, type: "module" })); + writeFileSync(join(directory, "manifest.json"), JSON.stringify({ name: "pm-github", version: selected, + description: "Synthetic workflow installation fixture", entry: "./index.js", capabilities: [] })); + writeFileSync(join(directory, "index.js"), "export default function () {}\n"); +} + +interface Scenario { + name: string; + manifest?: string; + input?: string; + expected?: string; + warning?: boolean; + env?: NodeJS.ProcessEnv; + error?: RegExp; } for (const file of files) { const source = readFileSync(join(root, file), "utf8"); const kind = file.includes("closeout") ? "closeout" : "sync"; - const scenarios = [ - { name: "lightweight tag", tags: `${workflowSha}\trefs/tags/v${version}`, expected: version }, - { name: "peeled annotated tag", tags: `${otherSha}\trefs/tags/v${version}\n${workflowSha}\trefs/tags/v${version}^{}`, expected: version }, - { name: "peeled tag before object", tags: `${workflowSha}\trefs/tags/v${version}^{}\n${otherSha}\trefs/tags/v${version}`, expected: version }, - { name: "unrelated and malformed tags ignored", tags: `${otherSha}\trefs/tags/v2020.1.1\n${workflowSha}\trefs/tags/vlatest\n${workflowSha}\trefs/tags/v${version}`, expected: version }, - { name: "numeric version without suffix", tags: `${workflowSha}\trefs/tags/v2027.1.2`, expected: "2027.1.2" }, - { name: "zero-padded tag resolves to the published unpadded version", tags: `${workflowSha}\trefs/tags/v2026.11.02`, expected: "2026.11.2" }, - { name: "zero-padded tag with suffix keeps the suffix", tags: `${workflowSha}\trefs/tags/v2027.01.01-2`, expected: "2027.1.1-2" }, - { name: "a component past 64-bit range normalizes as text without wrapping", tags: `${workflowSha}\trefs/tags/v18446744073709551616.11.02`, expected: "18446744073709551616.11.2" }, - { name: "an all-zero component normalizes to 0", tags: `${workflowSha}\trefs/tags/v2026.00.000`, expected: "2026.0.0" }, - { name: "zero-padded legacy input normalizes like a tag", tags: `${otherSha}\trefs/tags/v2020.1.1`, input: "2026.11.02", expected: "2026.11.2", warning: true }, - { name: "padded tag matches a normalized input without warning", tags: `${workflowSha}\trefs/tags/v2026.11.02`, input: "2026.11.2", expected: "2026.11.2" }, - { name: "two padded spellings of one version are not ambiguous", tags: `${workflowSha}\trefs/tags/v2026.11.02\n${workflowSha}\trefs/tags/v2026.11.2`, expected: "2026.11.2" }, - { name: "no match with legacy input", tags: `${otherSha}\trefs/tags/v2020.1.1`, input: "2020.1.1", expected: "2020.1.1", warning: true }, - { name: "tag overrides mismatched input", tags: `${workflowSha}\trefs/tags/v${version}`, input: "2020.1.1", expected: version, warning: true }, - { name: "tag overrides malicious input safely", tags: `${workflowSha}\trefs/tags/v${version}`, input: "$(touch injected)\n::error::injected", expected: version, warning: true }, - { name: "matching legacy input", tags: `${workflowSha}\trefs/tags/v${version}`, input: version, expected: version }, - { name: "no match without input", tags: `${otherSha}\trefs/tags/v${version}`, error: /Pin a release SHA/ }, - { name: "tag object is not a commit match", tags: `${workflowSha}\trefs/tags/v${version}\n${otherSha}\trefs/tags/v${version}^{}`, error: /Pin a release SHA/ }, - { name: "multiline fallback refused as a whole value", tags: "", input: "2027.1.2\ninvalid", error: /exact numeric version/ }, - { name: "valid first line cannot hide a second version", tags: "", input: "2027.1.2\n2027.2.3", error: /exact numeric version/ }, - { name: "tag key is data rather than executable text", tags: `${workflowSha}\trefs/tags/v$(touch injected)`, input: "2027.1.2", expected: "2027.1.2", warning: true }, - { name: "floating fallback refused", tags: "", input: "latest", error: /exact numeric version/ }, - { name: "malicious fallback refused safely", tags: "", input: "$(touch injected)\n::error::injected", error: /exact numeric version/ }, - { name: "remote failure cannot use fallback", tags: "", input: "2020.1.1", remoteStatus: "128", error: /Cannot read pm-github release tags/ }, - { name: "missing workflow identity refused", tags: "", sha: "", input: "2020.1.1", error: /job.workflow_sha/ }, - { name: "ambiguous release versions refused", tags: `${workflowSha}\trefs/tags/v2020.1.1\n${workflowSha}\trefs/tags/v${version}`, error: /Multiple release versions/ }, + const scenarios: Scenario[] = [ + { name: "omitted input follows manifest at SHA without release tags", expected: version }, + { name: "zero-padded release normalizes", manifest: "2026.11.04", expected: "2026.11.4" }, + { name: "zero-padded suffix release normalizes", manifest: "2027.01.01-2", expected: "2027.1.1-2" }, + { name: "large numeric component normalizes without arithmetic overflow", manifest: "18446744073709551616.11.02", expected: "18446744073709551616.11.2" }, + { name: "all-zero component stays zero", manifest: "2026.00.000", expected: "2026.0.0" }, + { name: "older explicit hold installs the hold and warns with both versions", input: "2026.10.16", expected: "2026.10.16", warning: true }, + { name: "newer explicit hold remains explicit", input: "2028.1.1", expected: "2028.1.1", warning: true }, + { name: "matching explicit hold needs no warning", input: version, expected: version }, + { name: "both sides normalize before comparison", manifest: "2026.11.04", input: "2026.011.004", expected: "2026.11.4" }, + { name: "non-existent version fails before tracker write", input: "2099.1.1", env: { MISSING_VERSION: "2099.1.1" }, error: /unavailable; refusing tracker writes/ }, + { name: "non-existent derived release fails before tracker write", env: { MISSING_VERSION: version }, error: /unavailable; refusing tracker writes/ }, + { name: "registry outage fails closed", env: { REGISTRY_STATUS: "28" }, error: /unavailable; refusing tracker writes/ }, + { name: "registry wrong version fails closed", env: { REGISTRY_METADATA: '{"name":"pm-github","version":"1999.1.1"}' }, error: /Registry metadata/ }, + { name: "registry wrong package fails closed", env: { REGISTRY_METADATA: `{"name":"other","version":"${version}"}` }, error: /Registry metadata/ }, + { name: "registry malformed JSON fails closed", env: { REGISTRY_METADATA: 'invalid"private-metadata' }, error: /Registry metadata/ }, + { name: "manifest transport failure cannot use explicit fallback", input: "2026.10.16", env: { MANIFEST_STATUS: "22" }, error: /Cannot read pm-github package.json/ }, + { name: "manifest malformed JSON fails closed", env: { WORKFLOW_MANIFEST: 'invalid"private-metadata' }, error: /Invalid pm-github workflow package metadata/ }, + { name: "manifest wrong package fails closed", env: { WORKFLOW_MANIFEST: '{"name":"caller","version":"1999.1.1"}' }, error: /Invalid pm-github workflow package metadata/ }, + { name: "manifest missing version fails closed", env: { WORKFLOW_MANIFEST: '{"name":"pm-github"}' }, error: /Invalid pm-github workflow package metadata/ }, + { name: "manifest version with a trailing newline refused", manifest: "2026.11.4\n", error: /Invalid pm-github workflow package metadata/ }, + { name: "manifest JSON stream refused", env: { WORKFLOW_MANIFEST: '{"name":"pm-github","version":"2026.11.4"} {"name":"other"}' }, error: /Invalid pm-github workflow package metadata/ }, + { name: "registry JSON stream refused", env: { REGISTRY_METADATA: '{"name":"other"} {"name":"pm-github","version":"2027.1.2-3"}' }, error: /Registry metadata/ }, + { name: "manifest floating version refused", manifest: "latest", error: /Workflow package version/ }, + { name: "missing job workflow SHA refused", env: { WORKFLOW_SHA: "" }, error: /job.workflow_sha/ }, + { name: "tag ref cannot substitute for resolved SHA", env: { WORKFLOW_SHA: "refs/tags/v2026.11.04" }, error: /job.workflow_sha/ }, + { name: "floating explicit input refused", input: "latest", error: /exact numeric version/ }, + { name: "multiline explicit input refused as a whole", input: "2026.11.4\n2026.11.5", error: /exact numeric version/ }, + { name: "malicious explicit input refused without execution or disclosure", input: "$(touch injected)\n::error::injected", error: /exact numeric version/ }, ]; for (const scenario of scenarios) { test(`${kind} resolves ${scenario.name}`, () => fixture(cwd => { - const env: NodeJS.ProcessEnv = { ...setup(cwd), REMOTE_TAGS: scenario.tags, REQUESTED_PM_GITHUB_VERSION: scenario.input ?? "", - WORKFLOW_SHA: scenario.sha ?? workflowSha, REMOTE_STATUS: scenario.remoteStatus ?? "0", RUNNER_TEMP: cwd }; - const scope = shell(source, "Resolve sync commit scope").split("<<'SCOPE'\n")[1]!.split("\nSCOPE")[0]!; - writeFileSync(join(cwd, "pm-github-sync-scope.sh"), scope); - const script = shell(source, "Resolve pm-github release version"); - const result = bash(cwd, script, env); + const env: NodeJS.ProcessEnv = { ...setup(cwd), WORKFLOW_MANIFEST: JSON.stringify({ name: "pm-github", version: scenario.manifest ?? version }), + REQUESTED_PM_GITHUB_VERSION: scenario.input ?? "", ...scenario.env }; + const before = snapshot(join(cwd, ".agents/pm")); + // A real tracker mutation immediately after the resolver must remain unreachable on refusal. + const result = bash(cwd, 'set -euo pipefail\n' + shell(source, "Resolve pm-github release version") + + '\npm update fixture-curated --description "Reached tracker write"', env); const output = result.stdout + result.stderr; - assert.doesNotMatch(output, /::error::injected/); - assert.notEqual(bash(cwd, "test -e injected").status, 0); + assert.doesNotMatch(output, /::error::injected|private-metadata/); + assert.equal(existsSync(join(cwd, "injected")), false); if (scenario.error) { assert.notEqual(result.status, 0, output); assert.match(output, scenario.error); - assert.notEqual(bash(cwd, 'test -s "$GITHUB_ENV"', env).status, 0); + assert.equal(existsSync(env.GITHUB_ENV!), false); + assert.deepEqual(snapshot(join(cwd, ".agents/pm")), before, "all real tracker bytes must remain unchanged"); + assert.equal(existsSync(join(cwd, "receipt")), false); } else { assert.equal(result.status, 0, output); + assert.notDeepEqual(snapshot(join(cwd, ".agents/pm")), before, "control mutation proves the real tracker write is reachable"); assert.equal(readFileSync(env.GITHUB_ENV!, "utf8"), `PM_GITHUB_VERSION=${scenario.expected}\n`); assert.equal(output.includes("::warning::pm-github-version is deprecated"), !!scenario.warning, output); - // Consume the real GITHUB_ENV file as the runner does for the install step. - const install = 'set -a; source "$GITHUB_ENV"; set +a\n' + shell(source, "Install pinned pm-github extension"); - const installed = bash(cwd, install, env); + if (scenario.warning) assert.match(output, new RegExp(`workflow ${version} installs extension ${scenario.expected}`.replaceAll(".", "\\."))); + assert.match(readFileSync(join(cwd, "http-receipt"), "utf8"), new RegExp(`/pm-github/${scenario.expected}\\n$`.replaceAll(".", "\\."))); + packageFixture(cwd, scenario.expected!); + const scope = shell(source, "Resolve sync commit scope").split("<<'SCOPE'\n")[1]!.split("\nSCOPE")[0]!; + writeFileSync(join(cwd, "pm-github-sync-scope.sh"), scope); + const installed = bash(cwd, 'set -a; source "$GITHUB_ENV"; set +a\n' + shell(source, "Install pinned pm-github extension"), env); assert.equal(installed.status, 0, installed.stderr + installed.stdout); assert.equal(readFileSync(join(cwd, "receipt"), "utf8").trim(), `npm:pm-github@${scenario.expected}`); - const wrong = bash(cwd, install, { ...env, INSTALLED_VERSION: "1999.1.1" }); - assert.notEqual(wrong.status, 0, "installed-version verification remains fail closed"); - assert.ok((wrong.stdout + wrong.stderr).includes(`::error::Installed pm-github version 1999.1.1 differs from resolved workflow version ${scenario.expected}.`)); + const metadata = JSON.parse(readFileSync(join(cwd, ".agents/pm/extensions/pm-github/package.json"), "utf8")) as { version: string }; + assert.equal(metadata.version, scenario.expected); } })); } - test(`${kind} install verification explains invalid metadata without disclosing its contents`, () => fixture(cwd => { - const env = { ...setup(cwd), RUNNER_TEMP: cwd, PM_GITHUB_VERSION: version }; + test(`${kind} install verification explains invalid metadata without disclosure`, () => fixture(cwd => { + const env = { ...setup(cwd), PM_GITHUB_VERSION: version }; const scope = shell(source, "Resolve sync commit scope").split("<<'SCOPE'\n")[1]!.split("\nSCOPE")[0]!; writeFileSync(join(cwd, "pm-github-sync-scope.sh"), scope); const secret = "ghp_" + "A".repeat(36); - for (const installed of [secret, 'invalid"metadata', 'broken"source\\suffix']) { - const result = bash(cwd, shell(source, "Install pinned pm-github extension"), { ...env, INSTALLED_VERSION: installed }); + for (const installed of ["1999.1.1", secret, 'invalid"metadata', 'broken"source\\suffix']) { + // Model damaged installed metadata at the transport boundary, retaining the real verifier. + mkdirSync(join(cwd, ".agents/pm/extensions/pm-github"), { recursive: true }); + writeFileSync(join(cwd, ".agents/pm/extensions/pm-github/package.json"), `{"version":"${installed}"}`); + writeFileSync(join(cwd, "bin/pm"), "#!/usr/bin/env bash\nexit 0\n", { mode: 0o755 }); + const result = bash(cwd, shell(source, "Install pinned pm-github extension"), env); assert.notEqual(result.status, 0); const output = result.stdout + result.stderr; - assert.ok(output.includes(installed === secret - ? `::error::Installed pm-github version differs from resolved workflow version ${version}.` - : "::error::Cannot read installed pm-github version")); + assert.ok(output.includes(installed === "1999.1.1" + ? `::error::Installed pm-github version 1999.1.1 differs from resolved workflow version ${version}.` + : installed === secret ? `::error::Installed pm-github version differs from resolved workflow version ${version}.` + : "::error::Cannot read installed pm-github version")); assert.ok(!output.includes(secret)); - for (const representation of [installed, JSON.stringify(installed).slice(1, -1)]) { - assert.ok(!output.includes(representation), "every rejected metadata value and its serialized form must remain private"); - } - assert.ok(!(result.stdout + result.stderr).includes(cwd), "module/parser diagnostics must not expose the tracker path"); + assert.ok(!output.includes(cwd), "parser diagnostics must not expose the tracker path"); } })); - test(`${kind} binds documented job identity and omits deprecated template input`, () => { + test(`${kind} binds job identity, preflights before writes, and omits template input`, () => { assert.match(source, /WORKFLOW_SHA: \$\{\{ job.workflow_sha \}\}/); assert.match(source, /REQUESTED_PM_GITHUB_VERSION: \$\{\{ inputs.pm-github-version \}\}/); assert.match(source, /pm-github-version:\n description: [^\n]+\n type: string\n required: false\n default: ""/); + assert.ok(source.indexOf("- name: Resolve pm-github release version") < source.indexOf("- name: Checkout caller default branch")); assert.doesNotMatch(shell(source, "Resolve pm-github release version"), /\$\{\{/); const caller = readFileSync(join(root, `docs/${kind}-workflow-caller.yml`), "utf8"); assert.doesNotMatch(caller, /pm-github-version/); @@ -151,44 +219,18 @@ test("both reusable workflows execute identical version resolution", () => { shell(readFileSync(join(root, files[1]), "utf8"), "Resolve pm-github release version")); }); -/** Every tag the release plan can emit, including zero-padded dates and -N suffixes. */ -const plannedTodays = ["2026.11.02", "2026.09.01", "2026.10.19", "2027.01.01-2"]; - -/** Resolve one planned tag through a real workflow step and return its exported version. */ -function resolvePlannedTag(cwd: string, file: string, tag: string): string { - const env: NodeJS.ProcessEnv = { ...setup(cwd), REMOTE_TAGS: `${workflowSha}\trefs/tags/${tag}`, - REQUESTED_PM_GITHUB_VERSION: "", WORKFLOW_SHA: workflowSha, REMOTE_STATUS: "0", RUNNER_TEMP: cwd }; - const script = shell(readFileSync(join(root, file), "utf8"), "Resolve pm-github release version"); - const result = bash(cwd, script, env); - assert.equal(result.status, 0, result.stdout + result.stderr); - return readFileSync(env.GITHUB_ENV!, "utf8"); -} - -test("workflow resolution equals the release plan's npm version for every planned tag", () => { - for (const today of plannedTodays) { +test("workflow manifest normalization equals the release plan npm version", () => { + for (const today of ["2026.11.04", "2026.09.01", "2026.10.19", "2027.01.01-2"]) { const plan = decideDailyRelease({ existingPrs: [], mainSha: "new-main", lastRelease: null, today }); - for (const file of files) { - fixture(cwd => { - assert.equal(resolvePlannedTag(cwd, file, plan.tag), `PM_GITHUB_VERSION=${plan.npm_version}\n`, - `${plan.tag} must resolve to the npm version the release plan publishes`); - }); - } + for (const file of files) fixture(cwd => { + const env: NodeJS.ProcessEnv = { ...setup(cwd), WORKFLOW_MANIFEST: JSON.stringify({ name: "pm-github", version: plan.tag.slice(1) }) }; + const result = bash(cwd, shell(readFileSync(join(root, file), "utf8"), "Resolve pm-github release version"), env); + assert.equal(result.status, 0, result.stdout + result.stderr); + assert.equal(readFileSync(env.GITHUB_ENV!, "utf8"), `PM_GITHUB_VERSION=${plan.npm_version}\n`); + }); } }); -test("the padded-tag rows fail when the tag normalization is removed", () => fixture(cwd => { - const original = shell(readFileSync(join(root, files[0]), "utf8"), "Resolve pm-github release version"); - const unnormalized = original.replace('candidate="$(normalize_pm_github_version "${candidate}")"', - 'candidate="${candidate}"'); - assert.notEqual(unnormalized, original, "the normalization step must exist to be removed"); - const env: NodeJS.ProcessEnv = { ...setup(cwd), REMOTE_TAGS: `${workflowSha}\trefs/tags/v2026.11.02`, - REQUESTED_PM_GITHUB_VERSION: "", WORKFLOW_SHA: workflowSha, REMOTE_STATUS: "0", RUNNER_TEMP: cwd }; - const result = bash(cwd, unnormalized, env); - assert.equal(result.status, 0, result.stdout + result.stderr); - assert.equal(readFileSync(env.GITHUB_ENV!, "utf8"), "PM_GITHUB_VERSION=2026.11.02\n", - "without normalization the padded tag resolves to the padded version, failing the row that expects 2026.11.2"); -})); - test("release retains token behavior and never stamps or commits reusable workflows", () => { assert.doesNotMatch(release, /release_token|RELEASE_APP_|release-stamped|Stamp the workflow/); assert.match(release, /GH_TOKEN: \$\{\{ github.token \}\}/); @@ -197,7 +239,6 @@ test("release retains token behavior and never stamps or commits reusable workfl } }); -/** Keep the two independent version-discovery requirements explicit in caller documentation. */ test("version discovery documents App-free lookup and no release-time stamping", () => { const readme = readFileSync(join(root, "README.md"), "utf8").replace(/\s+/g, " "); assert.match(readme, /Release version discovery needs no GitHub App, and no release-time workflow stamping is required\./); From e91d7779bc0f0baf0459c85ea297797c966b2d24 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 14 Nov 2026 10:50:23 +0100 Subject: [PATCH 2/4] Record bounded CI verification and pending full gates --- .agents/pm/history/pm-github-workflow-own-release.jsonl | 1 + .agents/pm/issues/pm-github-workflow-own-release.toon | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.agents/pm/history/pm-github-workflow-own-release.jsonl b/.agents/pm/history/pm-github-workflow-own-release.jsonl index 0ee355d2..3e2a5f37 100644 --- a/.agents/pm/history/pm-github-workflow-own-release.jsonl +++ b/.agents/pm/history/pm-github-workflow-own-release.jsonl @@ -14,3 +14,4 @@ {"hash_algorithm":"sha256","ts":"2026-11-14T09:19:32.474Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:19:32.474Z"}],"before_hash":"e421bfa3f5ccb8fef25d54d05b52b8e0ef862073c474a36404ac1cc52d237b0f","after_hash":"0486c6c40cfacafbb198eced14214d3842d613d8016de89b5d11233af040c664","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":"d54b6a3d7f087ce70c040483f72474e15502c7ed3f17d7f6e46cf2400eb26662"} {"hash_algorithm":"sha256","ts":"2026-11-14T09:20:39.544Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:20:39.544Z"},{"op":"replace","path":"/metadata/title","value":"Default reusable workflows to their own release (migration: drop pm-github-version); warn on explicit holds"}],"before_hash":"0486c6c40cfacafbb198eced14214d3842d613d8016de89b5d11233af040c664","after_hash":"ae83130effab24743f525319578108b52f0df38a9e258be55f2a5124c0336dad","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":"8c63900e0c1c2d9b43e1691da95f63230e9fc033e2c6555726e1d33106f9cfb2"} {"hash_algorithm":"sha256","ts":"2026-11-14T09:20:42.014Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:20:41.960Z","author":"codex-github238-1114","text":"Changelog generator renders item titles, so the migration instruction is also in this item title and is visible in release notes. Supplemental read-only strict health found one pre-existing local gate failure: pinned host pm-cli 2026.11.6 versus installed global pm-github host requirement 2026.11.13; tracker settings/directories/values/locks/integrity passed and seven older in-progress items are advisory. No dependency pin or global extension was changed. This environment condition is already recorded by the reference-identity work; clean CI owns the full gate. Changelog generation and check are rerun after this final tracker write."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:20:42.014Z"}],"before_hash":"ae83130effab24743f525319578108b52f0df38a9e258be55f2a5124c0336dad","after_hash":"de042ffa97f9e5a4d420449dc0a21d6a9e023fb0c3ef19dd3a9fd4f0c0a5bf54","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":"1f293b1e93f7804ef5d59584ff7427990172d1954338f8cd9d61124aa55a221c"} +{"hash_algorithm":"sha256","ts":"2026-11-14T09:50:05.388Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:50:05.380Z","author":"codex-github238-1114","text":"CI closeout at 2026-11-14 09:49 UTC after approximately 28 minutes of the 30-minute wait window: PR https://github.com/unbraind/pm-github/pull/245, implementation commit 0f58f1096c33a9fa3d0e9482d64c7a01fc23a16d. CI https://github.com/unbraind/pm-github/actions/runs/43580183069 still has test (22), test (26), bun-release (22), and bun-release (26) queued. CodeQL https://github.com/unbraind/pm-github/actions/runs/43580183044 completed successfully on that implementation head. Greptile and Semgrep checks succeeded; CodeRabbit/Sourcery skipped and cubic neutral are missing review approval. No review comments were returned and no threads were replied to, resolved or reacted to. This final evidence-only commit changes no implementation or test source; fresh final-head checks remain pending under the original wait cutoff. Once replacement checks register, cancel only the superseded queued CI run to avoid duplicate runner consumption. Orchestrator must verify the final-head full npm/Bun gates and unchanged 100/100/100/100 coverage; local strict-health environment skew remains recorded above. The item remains released and in_progress for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:50:05.388Z"}],"before_hash":"de042ffa97f9e5a4d420449dc0a21d6a9e023fb0c3ef19dd3a9fd4f0c0a5bf54","after_hash":"328481471bdcf2fadedebad9ef1d13e748a3d5ac934eb98319a34b13f66b2578","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":"1c80646f15a8cccc62b515db29a93e02aeb0e49cce1d2c1d37eb382a10965c52"} diff --git a/.agents/pm/issues/pm-github-workflow-own-release.toon b/.agents/pm/issues/pm-github-workflow-own-release.toon index 4f01f375..92029dd4 100644 --- a/.agents/pm/issues/pm-github-workflow-own-release.toon +++ b/.agents/pm/issues/pm-github-workflow-own-release.toon @@ -7,15 +7,16 @@ status: in_progress priority: 1 tags[3]: changelog-unreleased,"gh:unbraind/pm-github#238",workflows created_at: "2026-11-14T09:04:23.981Z" -updated_at: "2026-11-14T09:20:42.014Z" +updated_at: "2026-11-14T09:50:05.388Z" author: codex-github238-1114 -comments[6]{created_at,author,text}: +comments[7]{created_at,author,text}: "2026-11-14T09:04:30.564Z",codex-github238-1114,"Plan: replace tag enumeration with a public package.json fetch at the reusable job workflow SHA, normalize exact numeric versions, honor explicit holds and warn with both versions, then check the selected exact registry release before any tracker write. Execute extracted workflow bash with real scratch pm trackers, cover the issue regression cases and behavioral reverts, document caller migration, and inventory public fleet callers through the contents API without changing them. Targeted gates follow the task brief; CI runs the full gate." "2026-11-14T09:12:12.957Z",codex-github238-1114,"Design verified against GitHub Actions job context documentation: job.workflow_sha identifies the reusable job commit for both tag and SHA pins. Both workflows fetch their own package.json at that SHA, validate and normalize its version, honor explicit exact holds, and warn with both versions on a mismatch. Exact public registry metadata is checked before checkout/setup or tracker writes. Live transport smoke: omitted input resolved 2026.11.14; explicit 2026.10.16 remained 2026.10.16 with both versions in the warning; 2099.1.1 returned a refusal with no exported install version. Migration is in the item description and README: callers should drop pm-github-version." "2026-11-14T09:12:15.097Z",codex-github238-1114,"Behavioral revert proofs ran in disposable copies, leaving the fixed checkout untouched. Reverting only default selection: 4/4 selected tests fail. Ignoring explicit holds: 2/2 fail. Removing the two-version warning: 2/2 fail. Removing registry preflight: 2/2 fail, including a real tracker mutation sentinel. Restoring the entire origin/main resolver: all 8 selected issue regressions fail (omitted, padded default, older hold, unavailable version across both workflows). Each refusal case snapshots every real tracker byte including native history; successes perform a real pinned-pm local fixture extension installation. Baseline focused run: 58/58; additional malformed metadata cases are in the linked final run." "2026-11-14T09:15:57.370Z",codex-github238-1114,"Caller inventory complete: 217 workflow files read via public contents API across 37 canonical fleet repository names, zero unavailable reads; 51 calls in 28 repositories still provide pm-github-version. docs/workflow-version-callers.md records every caller file, exact reusable workflow pin, pin comment, input version, and contents blob SHA. No callers changed. Existing caller-adoption follow-up pm-github-samq can carry the later migration sweep. Focused workflow-order checks passed 2/2; typecheck, build:test and lint passed; privacy audited 9288 Git objects without findings; docstrings checked 33 files and 315 declarations. actionlint is unavailable. No authored TypeScript/JavaScript source modules changed (34 inventoried); full CI retains unchanged 100/100/100/100 coverage thresholds. The first linked run reached its default 120-second deadline; retry uses 300 seconds. A request to disable linked pm context in the source workspace was correctly refused, so the retry retains schema isolation." "2026-11-14T09:19:26.367Z",codex-github238-1114,"Final linked focused run passed 64/64 tests, zero failures/skips/cancellations, in 286.7 seconds using pm test --run --progress --timeout 300. This passing run followed the final disposable revert proofs (default 4 failures, hold 2, warning 2, existence 2, full old resolver 8). Linked-test timeout is now 600 seconds for slower shared execution; the first 120-second deadline was execution overhead, not an assertion failure. Additional workflow-order tests passed 2/2. npm run typecheck, npm run build:test, npm run lint, npm run privacy, npm run docstring and git diff --check passed; both changed workflows parse as YAML. actionlint was not installed. Full npm/Bun release and all-source coverage gates remain CI responsibilities under the targeted task brief. Remaining rollout work is caller pin adoption and removal of the 51 explicit holds; raw manifest/registry transport failure deliberately stops before writes. No pm SDK defect was observed; linked execution requires an explicit timeout for this real-installer test file." "2026-11-14T09:20:41.960Z",codex-github238-1114,"Changelog generator renders item titles, so the migration instruction is also in this item title and is visible in release notes. Supplemental read-only strict health found one pre-existing local gate failure: pinned host pm-cli 2026.11.6 versus installed global pm-github host requirement 2026.11.13; tracker settings/directories/values/locks/integrity passed and seven older in-progress items are advisory. No dependency pin or global extension was changed. This environment condition is already recorded by the reference-identity work; clean CI owns the full gate. Changelog generation and check are rerun after this final tracker write." + "2026-11-14T09:50:05.380Z",codex-github238-1114,"CI closeout at 2026-11-14 09:49 UTC after approximately 28 minutes of the 30-minute wait window: PR https://github.com/unbraind/pm-github/pull/245, implementation commit 0f58f1096c33a9fa3d0e9482d64c7a01fc23a16d. CI https://github.com/unbraind/pm-github/actions/runs/43580183069 still has test (22), test (26), bun-release (22), and bun-release (26) queued. CodeQL https://github.com/unbraind/pm-github/actions/runs/43580183044 completed successfully on that implementation head. Greptile and Semgrep checks succeeded; CodeRabbit/Sourcery skipped and cubic neutral are missing review approval. No review comments were returned and no threads were replied to, resolved or reacted to. This final evidence-only commit changes no implementation or test source; fresh final-head checks remain pending under the original wait cutoff. Once replacement checks register, cancel only the superseded queued CI run to avoid duplicate runner consumption. Orchestrator must verify the final-head full npm/Bun gates and unchanged 100/100/100/100 coverage; local strict-health environment skew remains recorded above. The item remains released and in_progress for orchestrator verification." files[4]{path,scope}: .github/workflows/pm-github-closeout.yml,project .github/workflows/pm-github-sync.yml,project From 8171c9a45a4b619d4c5f047ffd79b86e268da581 Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 14 Nov 2026 11:15:42 +0100 Subject: [PATCH 3/4] Tell callers to move the workflow pin and drop pm-github-version in one change A pin update alone keeps a stale pm-github-version as an explicit hold, so the caller would keep installing the older extension (now with a warning). The caller inventory and the README migration note now say to make both edits atomically. (CodeRabbit, docs/workflow-version-callers.md:6) --- README.md | 4 +++- docs/workflow-version-callers.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c650b781..3f18dcf2 100644 --- a/README.md +++ b/README.md @@ -995,7 +995,9 @@ fails closed even with an explicit input. Release version discovery needs no GitHub App, and no release-time workflow stamping is required. The release workflow keeps its existing token behavior. -**Migration:** remove `pm-github-version` from existing callers. Pin the workflow +**Migration:** remove `pm-github-version` from existing callers in the same change +that moves their workflow pin; a pin update alone keeps a stale input as an +explicit hold. Pin the workflow release SHA and keep its same-line release tag comment for Dependabot. With the input omitted, a workflow pin update also updates the installed extension, including the curated import identity fix released in `2026.11.14`. diff --git a/docs/workflow-version-callers.md b/docs/workflow-version-callers.md index 5d476086..b5be783b 100644 --- a/docs/workflow-version-callers.md +++ b/docs/workflow-version-callers.md @@ -3,7 +3,7 @@ Public default-branch contents API scan completed: 2026-11-14 09:14 UTC. Scanned 37 canonical fleet repository names and read 217 workflow files through `gh api repos/unbraind//contents/.github/workflows/`. Private repositories are excluded. No caller was edited. -Migration: remove `pm-github-version` in a follow-up sweep after adopting the release containing #238. Keep the Dependabot-maintained workflow SHA and release comment. Explicit holds continue to install the requested version and warn when it differs from the workflow release. +Migration: in each caller, move the workflow pin to the release containing #238 **and remove `pm-github-version` in the same change**. A pin update alone keeps every stale input below as an explicit hold, so the caller would go on installing the older extension (now with a warning). Keep the Dependabot-maintained workflow SHA and its same-line release comment. Keep an input only as a deliberate hold; it installs the requested version and warns when it differs from the workflow release. | Caller | Workflow file | Reusable workflow | Current pin | Pin comment | Input version | | --- | --- | --- | --- | --- | --- | From 4bd7c31c3952ed6c2fa20e361ed1b5689910806c Mon Sep 17 00:00:00 2001 From: SteveBot <1153461+unbraind@users.noreply.github.com> Date: Sat, 14 Nov 2026 21:23:28 +0100 Subject: [PATCH 4/4] fix: regenerate ownership inventory after workflow merge --- .../pm-github-workflow-own-release.jsonl | 7 ++++ .../pm-github-workflow-own-release.toon | 33 +++++++++++++++---- docs/identity-ownership-inventory.md | 2 +- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.agents/pm/history/pm-github-workflow-own-release.jsonl b/.agents/pm/history/pm-github-workflow-own-release.jsonl index 3e2a5f37..98b150fd 100644 --- a/.agents/pm/history/pm-github-workflow-own-release.jsonl +++ b/.agents/pm/history/pm-github-workflow-own-release.jsonl @@ -15,3 +15,10 @@ {"hash_algorithm":"sha256","ts":"2026-11-14T09:20:39.544Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:20:39.544Z"},{"op":"replace","path":"/metadata/title","value":"Default reusable workflows to their own release (migration: drop pm-github-version); warn on explicit holds"}],"before_hash":"0486c6c40cfacafbb198eced14214d3842d613d8016de89b5d11233af040c664","after_hash":"ae83130effab24743f525319578108b52f0df38a9e258be55f2a5124c0336dad","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":"8c63900e0c1c2d9b43e1691da95f63230e9fc033e2c6555726e1d33106f9cfb2"} {"hash_algorithm":"sha256","ts":"2026-11-14T09:20:42.014Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:20:41.960Z","author":"codex-github238-1114","text":"Changelog generator renders item titles, so the migration instruction is also in this item title and is visible in release notes. Supplemental read-only strict health found one pre-existing local gate failure: pinned host pm-cli 2026.11.6 versus installed global pm-github host requirement 2026.11.13; tracker settings/directories/values/locks/integrity passed and seven older in-progress items are advisory. No dependency pin or global extension was changed. This environment condition is already recorded by the reference-identity work; clean CI owns the full gate. Changelog generation and check are rerun after this final tracker write."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:20:42.014Z"}],"before_hash":"ae83130effab24743f525319578108b52f0df38a9e258be55f2a5124c0336dad","after_hash":"de042ffa97f9e5a4d420449dc0a21d6a9e023fb0c3ef19dd3a9fd4f0c0a5bf54","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":"1f293b1e93f7804ef5d59584ff7427990172d1954338f8cd9d61124aa55a221c"} {"hash_algorithm":"sha256","ts":"2026-11-14T09:50:05.388Z","author":"codex-github238-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"b8a6e793d100f7f4487a97c2","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-11-14T09:50:05.380Z","author":"codex-github238-1114","text":"CI closeout at 2026-11-14 09:49 UTC after approximately 28 minutes of the 30-minute wait window: PR https://github.com/unbraind/pm-github/pull/245, implementation commit 0f58f1096c33a9fa3d0e9482d64c7a01fc23a16d. CI https://github.com/unbraind/pm-github/actions/runs/43580183069 still has test (22), test (26), bun-release (22), and bun-release (26) queued. CodeQL https://github.com/unbraind/pm-github/actions/runs/43580183044 completed successfully on that implementation head. Greptile and Semgrep checks succeeded; CodeRabbit/Sourcery skipped and cubic neutral are missing review approval. No review comments were returned and no threads were replied to, resolved or reacted to. This final evidence-only commit changes no implementation or test source; fresh final-head checks remain pending under the original wait cutoff. Once replacement checks register, cancel only the superseded queued CI run to avoid duplicate runner consumption. Orchestrator must verify the final-head full npm/Bun gates and unchanged 100/100/100/100 coverage; local strict-health environment skew remains recorded above. The item remains released and in_progress for orchestrator verification."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T09:50:05.388Z"}],"before_hash":"de042ffa97f9e5a4d420449dc0a21d6a9e023fb0c3ef19dd3a9fd4f0c0a5bf54","after_hash":"328481471bdcf2fadedebad9ef1d13e748a3d5ac934eb98319a34b13f66b2578","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":"1c80646f15a8cccc62b515db29a93e02aeb0e49cce1d2c1d37eb382a10965c52"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:19:06.752Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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-11-14T20:19:06.752Z"},{"op":"add","path":"/metadata/assignee","value":"codex-followups-1114"},{"op":"add","path":"/metadata/claim_principal","value":"codex-followups-1114"}],"before_hash":"328481471bdcf2fadedebad9ef1d13e748a3d5ac934eb98319a34b13f66b2578","after_hash":"dae95a68f22a6b35965acc962843983eebc6ff8d0b87e19b038313dd7bdab6c9","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":"2154c84968bbe6aa1f1bf387cd55da5f8a9faa056402d0d7e3b9220c85529d2f"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:19:11.394Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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-11-14T20:19:11.380Z","author":"codex-followups-1114","text":"Review follow-up for PR 245: the merged source shifted ownership anchors. Before regeneration, identity-inventory.test.ts reproduces four failures and one pass. Regenerate only with node scripts/identity-inventory.ts --write, run the complete inventory-related test files plus typecheck and lint, then carry the fix into PR 246. Targeted local gates follow the brief; full gates remain in CI."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T20:19:11.394Z"}],"before_hash":"dae95a68f22a6b35965acc962843983eebc6ff8d0b87e19b038313dd7bdab6c9","after_hash":"8223656ae053dd34e8dae1716471ed24210146c7ee592e61823a71091fd03094","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":"81daa0a4d94724dd14f5bd6e7b24de2ecafab116cc15a7fa944e00d0ab24b8f9"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:19:16.082Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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/files/3/path","value":"test/identity-inventory.test.ts"},{"op":"add","path":"/metadata/files/4","value":{"path":"test/self-versioned-workflows.test.ts","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T20:19:16.082Z"}],"before_hash":"8223656ae053dd34e8dae1716471ed24210146c7ee592e61823a71091fd03094","after_hash":"b78f6462551f7ab78fa6b68cb794ac5a3ceaf28b5de37da4e973a1088c654ad1","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":"337d2decdf0b7f96c2e859a1262eaa1f53975c9a878e83110e0a21e3a21b6441"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:19:17.293Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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/1/path","value":"docs/workflow-version-callers.md"},{"op":"replace","path":"/metadata/docs/0/path","value":"docs/identity-ownership-inventory.md"},{"op":"add","path":"/metadata/docs/2","value":{"path":"README.md","scope":"project"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T20:19:17.293Z"}],"before_hash":"b78f6462551f7ab78fa6b68cb794ac5a3ceaf28b5de37da4e973a1088c654ad1","after_hash":"acb0ce4a482955095aa9f58e1cfba67e1bc3b5321b54689896fdaee809962aeb","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":"5d6fdbcd3ae0a4e13dfdf9fd47c350775bb426f58735d420ba26f89b12f5f4d3"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:19:18.581Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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-concurrency=2 test/identity-inventory.test.ts test/round-twelve.test.ts","scope":"project","timeout_seconds":600,"provenance":{"author":"codex-followups-1114","created_at":"2026-11-14T20:19:18.462Z","source_kind":"local_mutation","source_ref":"fix/workflow-installs-own-release"}}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T20:19:18.581Z"}],"before_hash":"acb0ce4a482955095aa9f58e1cfba67e1bc3b5321b54689896fdaee809962aeb","after_hash":"29e6ac91e7918aa3457bcd7cdd76ba5565acfed2335e387ec3ebc31eaf6b0f3a","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":"52debde3df4790aa7cead5f7bac98fd05b9e45ae42df5439b036b3edd1f14a21"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:21:23.611Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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-11-14T20:21:23.562Z","author":"codex-followups-1114","text":"Generated fix changes one auxiliary workflow anchor from line 466 to 440. Before generation the inventory file caused 4/5 inventory tests to fail; after generation the complete test/identity-inventory.test.ts and test/round-twelve.test.ts run passes 37/37 with no skipped or failed tests via pinned pm test. npm run typecheck, npm run lint and npm run build:test pass. The existing stale-anchor and line-shift regressions remain intact; no generator or anchor hand edits. Full release certification remains in CI."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-11-14T20:21:23.611Z"}],"before_hash":"29e6ac91e7918aa3457bcd7cdd76ba5565acfed2335e387ec3ebc31eaf6b0f3a","after_hash":"3d94e535c763223f0b296456a976fe70035c61e4b7c1ddd2ff05cfad70fbf30c","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":"51a1351037e9a40bf764e2d8d4fc076f51d543567b27665e0e554240539c7bfd"} +{"hash_algorithm":"sha256","ts":"2026-11-14T20:21:27.457Z","author":"codex-followups-1114","author_source":"asserted","agent_harness":"codex","agent_model":"gpt-6.1-sol","agent_model_source":"probe","agent_instance":"3cfd5fadd87f9c45b3e054f8","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-11-14T20:21:27.457Z"}],"before_hash":"3d94e535c763223f0b296456a976fe70035c61e4b7c1ddd2ff05cfad70fbf30c","after_hash":"dcfc6886aff10bdbf2ff0cc315ce26a98e80b83977219ecf84000a99372dca1b","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":"9a03e26b920ad2ec2c558ee20a507374624c710aa25db08f9766201425683185"} diff --git a/.agents/pm/issues/pm-github-workflow-own-release.toon b/.agents/pm/issues/pm-github-workflow-own-release.toon index 92029dd4..8e9e2a6a 100644 --- a/.agents/pm/issues/pm-github-workflow-own-release.toon +++ b/.agents/pm/issues/pm-github-workflow-own-release.toon @@ -7,9 +7,9 @@ status: in_progress priority: 1 tags[3]: changelog-unreleased,"gh:unbraind/pm-github#238",workflows created_at: "2026-11-14T09:04:23.981Z" -updated_at: "2026-11-14T09:50:05.388Z" +updated_at: "2026-11-14T20:21:27.457Z" author: codex-github238-1114 -comments[7]{created_at,author,text}: +comments[9]{created_at,author,text}: "2026-11-14T09:04:30.564Z",codex-github238-1114,"Plan: replace tag enumeration with a public package.json fetch at the reusable job workflow SHA, normalize exact numeric versions, honor explicit holds and warn with both versions, then check the selected exact registry release before any tracker write. Execute extracted workflow bash with real scratch pm trackers, cover the issue regression cases and behavioral reverts, document caller migration, and inventory public fleet callers through the contents API without changing them. Targeted gates follow the task brief; CI runs the full gate." "2026-11-14T09:12:12.957Z",codex-github238-1114,"Design verified against GitHub Actions job context documentation: job.workflow_sha identifies the reusable job commit for both tag and SHA pins. Both workflows fetch their own package.json at that SHA, validate and normalize its version, honor explicit exact holds, and warn with both versions on a mismatch. Exact public registry metadata is checked before checkout/setup or tracker writes. Live transport smoke: omitted input resolved 2026.11.14; explicit 2026.10.16 remained 2026.10.16 with both versions in the warning; 2099.1.1 returned a refusal with no exported install version. Migration is in the item description and README: callers should drop pm-github-version." "2026-11-14T09:12:15.097Z",codex-github238-1114,"Behavioral revert proofs ran in disposable copies, leaving the fixed checkout untouched. Reverting only default selection: 4/4 selected tests fail. Ignoring explicit holds: 2/2 fail. Removing the two-version warning: 2/2 fail. Removing registry preflight: 2/2 fail, including a real tracker mutation sentinel. Restoring the entire origin/main resolver: all 8 selected issue regressions fail (omitted, padded default, older hold, unavailable version across both workflows). Each refusal case snapshots every real tracker byte including native history; successes perform a real pinned-pm local fixture extension installation. Baseline focused run: 58/58; additional malformed metadata cases are in the linked final run." @@ -17,14 +17,35 @@ comments[7]{created_at,author,text}: "2026-11-14T09:19:26.367Z",codex-github238-1114,"Final linked focused run passed 64/64 tests, zero failures/skips/cancellations, in 286.7 seconds using pm test --run --progress --timeout 300. This passing run followed the final disposable revert proofs (default 4 failures, hold 2, warning 2, existence 2, full old resolver 8). Linked-test timeout is now 600 seconds for slower shared execution; the first 120-second deadline was execution overhead, not an assertion failure. Additional workflow-order tests passed 2/2. npm run typecheck, npm run build:test, npm run lint, npm run privacy, npm run docstring and git diff --check passed; both changed workflows parse as YAML. actionlint was not installed. Full npm/Bun release and all-source coverage gates remain CI responsibilities under the targeted task brief. Remaining rollout work is caller pin adoption and removal of the 51 explicit holds; raw manifest/registry transport failure deliberately stops before writes. No pm SDK defect was observed; linked execution requires an explicit timeout for this real-installer test file." "2026-11-14T09:20:41.960Z",codex-github238-1114,"Changelog generator renders item titles, so the migration instruction is also in this item title and is visible in release notes. Supplemental read-only strict health found one pre-existing local gate failure: pinned host pm-cli 2026.11.6 versus installed global pm-github host requirement 2026.11.13; tracker settings/directories/values/locks/integrity passed and seven older in-progress items are advisory. No dependency pin or global extension was changed. This environment condition is already recorded by the reference-identity work; clean CI owns the full gate. Changelog generation and check are rerun after this final tracker write." "2026-11-14T09:50:05.380Z",codex-github238-1114,"CI closeout at 2026-11-14 09:49 UTC after approximately 28 minutes of the 30-minute wait window: PR https://github.com/unbraind/pm-github/pull/245, implementation commit 0f58f1096c33a9fa3d0e9482d64c7a01fc23a16d. CI https://github.com/unbraind/pm-github/actions/runs/43580183069 still has test (22), test (26), bun-release (22), and bun-release (26) queued. CodeQL https://github.com/unbraind/pm-github/actions/runs/43580183044 completed successfully on that implementation head. Greptile and Semgrep checks succeeded; CodeRabbit/Sourcery skipped and cubic neutral are missing review approval. No review comments were returned and no threads were replied to, resolved or reacted to. This final evidence-only commit changes no implementation or test source; fresh final-head checks remain pending under the original wait cutoff. Once replacement checks register, cancel only the superseded queued CI run to avoid duplicate runner consumption. Orchestrator must verify the final-head full npm/Bun gates and unchanged 100/100/100/100 coverage; local strict-health environment skew remains recorded above. The item remains released and in_progress for orchestrator verification." -files[4]{path,scope}: + "2026-11-14T20:19:11.380Z",codex-followups-1114,"Review follow-up for PR 245: the merged source shifted ownership anchors. Before regeneration, identity-inventory.test.ts reproduces four failures and one pass. Regenerate only with node scripts/identity-inventory.ts --write, run the complete inventory-related test files plus typecheck and lint, then carry the fix into PR 246. Targeted local gates follow the brief; full gates remain in CI." + "2026-11-14T20:21:23.562Z",codex-followups-1114,"Generated fix changes one auxiliary workflow anchor from line 466 to 440. Before generation the inventory file caused 4/5 inventory tests to fail; after generation the complete test/identity-inventory.test.ts and test/round-twelve.test.ts run passes 37/37 with no skipped or failed tests via pinned pm test. npm run typecheck, npm run lint and npm run build:test pass. The existing stale-anchor and line-shift regressions remain intact; no generator or anchor hand edits. Full release certification remains in CI." +files[5]{path,scope}: .github/workflows/pm-github-closeout.yml,project .github/workflows/pm-github-sync.yml,project docs/scheduled-workflow-watch-1106.md,project + test/identity-inventory.test.ts,project test/self-versioned-workflows.test.ts,project -tests[1]{command,scope,timeout_seconds,provenance{author,created_at,source_kind,source_ref},updated_by,updated_at}: - node --test --test-concurrency=2 test/self-versioned-workflows.test.ts,project,600,codex-github238-1114,"2026-11-14T09:09:34.220Z",local_mutation,fix/workflow-installs-own-release,codex-github238-1114,"2026-11-14T09:19:21.734Z" -docs[2]{path,scope}: +tests[2]: + - command: node --test --test-concurrency=2 test/self-versioned-workflows.test.ts + scope: project + timeout_seconds: 600 + provenance: + author: codex-github238-1114 + created_at: "2026-11-14T09:09:34.220Z" + source_kind: local_mutation + source_ref: fix/workflow-installs-own-release + updated_by: codex-github238-1114 + updated_at: "2026-11-14T09:19:21.734Z" + - command: node --test --test-concurrency=2 test/identity-inventory.test.ts test/round-twelve.test.ts + scope: project + timeout_seconds: 600 + provenance: + author: codex-followups-1114 + created_at: "2026-11-14T20:19:18.462Z" + source_kind: local_mutation + source_ref: fix/workflow-installs-own-release +docs[3]{path,scope}: + docs/identity-ownership-inventory.md,project docs/workflow-version-callers.md,project README.md,project body: "" diff --git a/docs/identity-ownership-inventory.md b/docs/identity-ownership-inventory.md index 011cc706..b68b763b 100644 --- a/docs/identity-ownership-inventory.md +++ b/docs/identity-ownership-inventory.md @@ -123,4 +123,4 @@ The identity-field/tag scan finds 5 auxiliary locations. The inventory generator | `scripts/dependabot-merge.ts:145` | Explicit GitHub CLI transport parameter; targets come from repository/PR arguments. | | `scripts/prove-gate-public-forms.ts:4` | Privacy-gate documentation reference; no target lookup. | | `.github/workflows/pm-github-sync.yml:27` | Importer option documentation or typed diagnostic rendering; no independent target lookup. | -| `.github/workflows/pm-github-sync.yml:466` | Importer option documentation or typed diagnostic rendering; no independent target lookup. | +| `.github/workflows/pm-github-sync.yml:440` | Importer option documentation or typed diagnostic rendering; no independent target lookup. |