diff --git a/.agents/pm/history/pm-github-iswq.jsonl b/.agents/pm/history/pm-github-iswq.jsonl new file mode 100644 index 00000000..0e37edd9 --- /dev/null +++ b/.agents/pm/history/pm-github-iswq.jsonl @@ -0,0 +1,13 @@ +{"ts":"2026-08-20T21:28:31.109Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-iswq"},{"op":"add","path":"/metadata/title","value":"Use canonical unbounded pm list reads with the 2026.8.20 host contract"},{"op":"add","path":"/metadata/description","value":"pm-github already fail-closes complete-corpus receipts, but its production argv and user-facing diagnostics still use the deprecated list-all alias and its declared pm CLI/SDK floors predate 2026.8.20."},{"op":"add","path":"/metadata/type","value":"Issue"},{"op":"add","path":"/metadata/status","value":"in_progress"},{"op":"add","path":"/metadata/priority","value":1},{"op":"add","path":"/metadata/tags","value":["agents","cli-ux","complete-corpus","latest-cli","tdd"]},{"op":"add","path":"/metadata/created_at","value":"2026-08-20T21:28:31.109Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-20T21:28:31.109Z"},{"op":"add","path":"/metadata/author","value":"codex"},{"op":"add","path":"/metadata/estimated_minutes","value":180},{"op":"add","path":"/metadata/acceptance_criteria","value":"Create failing exact-argv and alias-free real installed-CLI tests first; replace only the deprecated invocation and terminology; retain strict full unbounded fail-closed receipt validation; use top-level TypeScript imports and no any/dynamic imports; pin dev CLI/SDK and set peer/manifest floors to 2026.8.20; run release:check, exact measured-source coverage, pm health, reconcile, validate, npm/bun packed acceptance, dependency/vulnerability/privacy checks; document exact evidence and link the package PR plus companion item pm-cli-website-cbyb; do not merge or publish while pm-github-zqad or pm-github-v2kt blocks release"},{"op":"add","path":"/metadata/risk","value":"medium"},{"op":"add","path":"/metadata/confidence","value":95},{"op":"add","path":"/metadata/reporter","value":"codex"},{"op":"add","path":"/metadata/severity","value":"medium"},{"op":"add","path":"/metadata/repro_steps","value":"Run the production completePmListArgs vector with pm CLI 2026.8.20 and inspect stderr; scan index.ts, README.md, and complete-corpus tests for list-all."},{"op":"add","path":"/metadata/expected_result","value":"Production invokes explicit unbounded canonical pm list --all --json with full/body/strict receipts; no alias deprecation reaches stderr; source, tests, docs, generated output, package dependency, peer floor, and manifest floor agree on pm CLI/SDK 2026.8.20."},{"op":"add","path":"/metadata/actual_result","value":"Baseline: complete corpus verification is strict and release-tested, but completePmListArgs emits list-all; README and errors name the alias; dev dependency is 2026.8.17, peer/manifest floors are 2026.8.3, and installed node_modules is stale at 2026.8.15."},{"op":"add","path":"/metadata/affected_version","value":"pm-github 2026.8.18 with pm CLI 2026.8.20"},{"op":"add","path":"/metadata/component","value":"whole-tracker pm CLI integration"},{"op":"add","path":"/metadata/customer_impact","value":"Deprecated diagnostics can pollute machine stderr and stale compatibility floors allow hosts that do not provide the canonical contract this package now requires."},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-github-ep0u","kind":"related","created_at":"2026-08-20T21:28:31.109Z","author":"codex","source_kind":"cli:create:dep","author_source":"detected"}]},{"op":"add","path":"/metadata/tests","value":[{"command":"npm run release:check","path":"package.json","scope":"project","timeout_seconds":1200,"note":"Full package release gate"}]},{"op":"add","path":"/metadata/docs","value":[{"path":"https://github.com/unbraind/pm-cli-companion/blob/docs/record-pm-rl-pm-csv-cli-2026-8-20/.agents/pm/issues/pm-cli-website-cbyb.toon","scope":"global","note":"Companion fleet canonical-command migration owner"}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"b69bac6f29498bcf4467ab9ecec3ee6029e1d09b23e61fdf2a474a63e3531e53","item_hash_version":2,"message":"Start canonical pm list migration with TDD and release boundaries"} +{"ts":"2026-08-20T21:32:59.796Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"add","path":"/metadata/docs/1","value":{"path":"https://github.com/unbraind/pm-cli/issues/1070","scope":"global","note":"Upstream receipt bug found during installed-CLI acceptance"}},{"op":"add","path":"/metadata/docs/2","value":{"path":"README.md","scope":"project","note":"Canonical complete-corpus contract and copyable invocation"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:32:59.796Z"}],"before_hash":"b69bac6f29498bcf4467ab9ecec3ee6029e1d09b23e61fdf2a474a63e3531e53","after_hash":"24b7b46fc335fd8a520c95b8fab2edfc0e78df70df582997fe7231615ff1a4ee","item_hash_version":2,"message":"Link package guidance and upstream UX finding"} +{"ts":"2026-08-20T21:33:00.194Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:33:00.194Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-20T21:33:00.194Z","author":"codex","text":"2026-08-20 TDD: before the source edit, node --test test/complete-corpus.test.ts failed 2 of 6 tests because completePmListArgs still emitted --path/list-all and the real CLI wrote the deprecation diagnostic to stderr. After canonical argv, the stale local 2026.8.15 runtime rejected list --all as ambiguous while the host 2026.8.20 runtime passed; npm install updated the exact local @unbrained/pm-cli pin to 2026.8.20 and all 6 tests passed. Full npm test then passed 261 tests. Canonical --output-include full is currently misreported as legacy --full in the receipt, tracked upstream as pm-cli #1070; the acceptance rejects only actual list-all use until that CLI bug is fixed."}]}],"before_hash":"24b7b46fc335fd8a520c95b8fab2edfc0e78df70df582997fe7231615ff1a4ee","after_hash":"82473e014492aa25490314c7445b86c94a83e9ea78a6ec70d07479e8cba4eff0","item_hash_version":2,"message":"Record red-green evidence and discovered host receipt issue"} +{"ts":"2026-08-20T21:33:07.429Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"tests_add","patch":[{"op":"add","path":"/metadata/tests/1","value":{"command":"npm test","path":"test/complete-corpus.test.ts","scope":"project","timeout_seconds":900,"note":"261-test suite includes red-green canonical argv and real installed-CLI receipt acceptance"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:33:07.429Z"}],"before_hash":"82473e014492aa25490314c7445b86c94a83e9ea78a6ec70d07479e8cba4eff0","after_hash":"44284ca94e49330c50ef29ae664dddb03aec6d52a48d847ad1f7b2af46a983da","item_hash_version":2,"message":"Link package-script acceptance evidence"} +{"ts":"2026-08-20T21:40:40.486Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"files_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:40:40.486Z"},{"op":"add","path":"/metadata/files","value":[{"path":"index.ts","scope":"project","note":"Canonical complete-corpus argv and diagnostics"},{"path":"manifest.json","scope":"project","note":"Runtime-enforced host floor"},{"path":"package.json","scope":"project","note":"Peer and exact development CLI SDK floors"},{"path":"test/compatibility-floor.test.ts","scope":"project","note":"Exact 2026.8.20 host floor and manifest contract"},{"path":"test/complete-corpus.test.ts","scope":"project","note":"Exact argv and installed CLI completeness acceptance"}]}],"before_hash":"44284ca94e49330c50ef29ae664dddb03aec6d52a48d847ad1f7b2af46a983da","after_hash":"6589cb86aa585a09ab858fdd89e28fd5040cfcc3d7e1e09d784b160aa94cb7ec","item_hash_version":2,"message":"Link implementation and compatibility artifacts"} +{"ts":"2026-08-20T21:40:40.880Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/actual_result","value":"Implemented canonical host-owned --pm-path plus --output-include full, unbounded amount/cost, then list --all --json --include-body --strict-read; all production errors/docs and direct test fixtures use canonical terminology. Pinned local CLI/SDK 2026.8.20, set peer and manifest floors to 2026.8.20, and removed the ignored manifest pm.compatibility envelope. TDD failed 2/6 before source edits, then passed 6/6. Full suite passed 261 tests. Current measured-source coverage passed at 92.40% lines, 82.58% branches, 91.75% functions across index.ts/projects.ts; this is not 100/100/100/100 and remains independently open as pm-github-9cjx. Docstring gate documented 92 declarations; production audit found 0 vulnerabilities; pack dry-run contained 13 intended files. Clean packed npm and Bun clients each read two open/closed items with items.length=count=total, no truncation/pagination/list-all receipt, and empty child stderr. A packed npm extension authenticated through gh, validated public repo access HTTP 200, and a retry dry-ran a real GitHub import against unbraind/pm-github with no writes and a complete empty tracker; one earlier pm-changelog import attempt timed out at 30 seconds and was not counted as a pass. pm CLI receipt issue #1070 records canonical --output-include full being misreported as legacy --full. Delivery is complete but merge/publication remain blocked by pm-github-zqad and pm-github-v2kt."},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:40:40.880Z"},{"op":"add","path":"/metadata/resolution","value":"Migrated the existing strict whole-corpus reader to canonical pm CLI 2026.8.20 argv without weakening its completeness decoder, added exact and real packed acceptance, aligned compatibility declarations, updated terminology, and preserved separate privacy, release-order, and exact-coverage blockers."},{"op":"add","path":"/metadata/fixed_version","value":"unreleased branch"}],"before_hash":"6589cb86aa585a09ab858fdd89e28fd5040cfcc3d7e1e09d784b160aa94cb7ec","after_hash":"f4505bc1984f402ac565b4be1f1d0e87482c4fff6a54debe667a7027cb9e99b8","item_hash_version":2,"message":"Record verified canonical reader delivery and independent blockers"} +{"ts":"2026-08-20T21:40:41.301Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:40:41.301Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-20T21:40:41.284Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-20T21:40:41.284Z"},{"op":"add","path":"/metadata/close_reason","value":"Canonical whole-corpus reader delivery is implemented and verified; package merge/publication remain separately blocked by pm-github-zqad and pm-github-v2kt."}],"before_hash":"f4505bc1984f402ac565b4be1f1d0e87482c4fff6a54debe667a7027cb9e99b8","after_hash":"57d17498621ee09f46e50c75fdd391e7b40d2d142ba2ea5161c76dff89778adc","item_hash_version":2} +{"ts":"2026-08-20T21:44:41.676Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"docs_add","patch":[{"op":"replace","path":"/metadata/docs/2/note","value":"Upstream receipt bug found during installed-CLI acceptance"},{"op":"replace","path":"/metadata/docs/2/scope","value":"global"},{"op":"replace","path":"/metadata/docs/2/path","value":"https://github.com/unbraind/pm-cli/issues/1070"},{"op":"replace","path":"/metadata/docs/1/note","value":"Companion fleet canonical-command migration owner"},{"op":"replace","path":"/metadata/docs/1/path","value":"https://github.com/unbraind/pm-cli-companion/blob/docs/record-pm-rl-pm-csv-cli-2026-8-20/.agents/pm/issues/pm-cli-website-cbyb.toon"},{"op":"replace","path":"/metadata/docs/0/note","value":"Canonical unbounded changelog reader awaiting privacy-gated merge and publication"},{"op":"replace","path":"/metadata/docs/0/path","value":"https://github.com/unbraind/pm-changelog/pull/148"},{"op":"add","path":"/metadata/docs/3","value":{"path":"README.md","scope":"project","note":"Canonical complete-corpus contract and copyable invocation"}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:44:41.676Z"}],"before_hash":"57d17498621ee09f46e50c75fdd391e7b40d2d142ba2ea5161c76dff89778adc","after_hash":"a800797a201a1bf7744a8b2cd16984c8248f0df0a516fc0332e6b22e11856736","item_hash_version":2,"message":"Link upstream changelog reader migration"} +{"ts":"2026-08-20T21:44:42.154Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/1","value":{"created_at":"2026-08-20T21:44:42.154Z","author":"codex","text":"2026-08-20 final gates before review: npm run release:check passed 261 tests and the current 92.40/82.58/91.75 three-metric measured-source gate, 92 documented declarations, zero production audit vulnerabilities, clean 13-file pack, and current changelog. pm health --strict-exit passed with three provenance advisories; pm merge reconcile --dry-run found 82 clean streams and no pending decisions; pm validate remained structurally valid with pre-existing legacy metadata/resolution/file warnings; duplicates reported one pre-existing closed exact-title cluster. GitHub Dependabot and secret-scanning open alerts were empty; code-scanning has no analysis, and Trivy is not installed, so neither is represented as green. Public pm-changelog 2026.8.17 first refused a bounded 5-of-82 read; explicit unbounded pm-arg controls restored all 289 changelog lines. The tool still invokes its deprecated internal alias until privacy-gated pm-changelog PR #148 can merge and release. Historical privacy/identity findings remain open under pm-github-zqad and publication order remains open under pm-github-v2kt."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:44:42.154Z"}],"before_hash":"a800797a201a1bf7744a8b2cd16984c8248f0df0a516fc0332e6b22e11856736","after_hash":"2e8d0df78609d640ebe4ee1ca6a342241b21412f2aab9ca65a7e90e428715ace","item_hash_version":2,"message":"Record final gate results and explicit limitations"} +{"ts":"2026-08-20T21:45:25.861Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"remove","path":"/metadata/fixed_version"},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:45:25.861Z"}],"before_hash":"2e8d0df78609d640ebe4ee1ca6a342241b21412f2aab9ca65a7e90e428715ace","after_hash":"4af7d9270849ef2b89de1f0e5d7d3a4cdd06ed48d5ec61fd9ea747deddcdbe0d","item_hash_version":2,"message":"Clear non-version delivery placeholder; changelog remains Unreleased until an approved release assigns a version"} +{"ts":"2026-08-20T21:55:35.957Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:55:35.957Z"},{"op":"replace","path":"/metadata/title","value":"BREAKING: pm-github now requires pm CLI 2026.8.20 or newer; older hosts may fail installation or runtime validation"}],"before_hash":"4af7d9270849ef2b89de1f0e5d7d3a4cdd06ed48d5ec61fd9ea747deddcdbe0d","after_hash":"343763474c1f571f9a1aad101b7720e146ba32d89e2178f77dd5e9cf415b2f0e","item_hash_version":2,"message":"Make the generated changelog disclose the compatibility break"} +{"ts":"2026-08-20T21:55:36.351Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/2","value":{"created_at":"2026-08-20T21:55:36.351Z","author":"codex","text":"CodeRabbit exact-head review on 2026-08-20 produced four findings. Accepted: disclose the 2026.8.20 compatibility break through the package-owned changelog item; remove unsafe labels/since narrowing advice from complete-corpus ENOBUFS guidance; and pass the real installed-CLI envelope through decodeCompletePmItems before asserting decoded rows. The pm-changelog dependency upgrade request cannot yet be performed: npm latest is 2026.8.17 and no release contains privacy-blocked PR #148, so the current lock remains 2026.8.17 and merge/publication stay blocked. TDD red phase: targeted compatibility and complete-corpus tests failed exactly on the missing breaking note and unsafe buffer advice before implementation."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:55:36.351Z"}],"before_hash":"343763474c1f571f9a1aad101b7720e146ba32d89e2178f77dd5e9cf415b2f0e","after_hash":"17af5d764b30c9c21c679fcb1cbe15ab8795b05550bacc6cc73478764b3a66df","item_hash_version":2,"message":"Record exact-head review findings and red-phase evidence"} +{"ts":"2026-08-20T21:57:30.348Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"b44c9b090cf8bc81eaf457c4","agent_provenance":{"model":null,"effort":null,"role":null,"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/3","value":{"created_at":"2026-08-20T21:57:30.348Z","author":"codex","text":"Review-fix green phase: targeted compatibility and complete-corpus tests pass 10/10. The full release gate passes all 261 tests, 92 documented declarations, zero production audit vulnerabilities, a clean 13-file pack, and a current generated changelog. The two-source coverage report is now 92.09% lines, 82.47% branches, and 91.75% functions after the diagnostic hardening; it remains non-exact and pm-github-9cjx stays open. The real acceptance now decodes the installed CLI envelope through the production decoder and forces a one-byte buffer to prove the complete-reader error offers no narrowing workaround."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-20T21:57:30.348Z"}],"before_hash":"17af5d764b30c9c21c679fcb1cbe15ab8795b05550bacc6cc73478764b3a66df","after_hash":"1982d6d456eb57397f27f7db48391d9427feb5b1092fafe06ff909eb5750899c","item_hash_version":2,"message":"Record accepted review fixes and green-phase evidence"} diff --git a/.agents/pm/history/pm-github-v2kt.jsonl b/.agents/pm/history/pm-github-v2kt.jsonl index 8bb7c301..8a132d9e 100644 --- a/.agents/pm/history/pm-github-v2kt.jsonl +++ b/.agents/pm/history/pm-github-v2kt.jsonl @@ -7,3 +7,5 @@ {"ts":"2026-08-10T16:23:19.099Z","author":"claude","author_source":"asserted","agent_harness":"claude-code","agent_instance":"304c86ad9f9d7cbae7f44c3b","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":{"value":"1","source":"environment"},"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/5","value":{"created_at":"2026-08-10T16:23:19.099Z","author":"claude","text":"Round five review fixes. CodeRabbit found that the tracking note claimed dist validation that pm-web's workflow did not actually contain. An audit showed seven repositories track dist but had no rebuild check, because the earlier patch keyed on a diff paths idiom those repositories do not use: pm-changelog, pm-context, pm-gantt-chart, pm-graph, pm-jira, pm-ops and pm-web. All seven now rebuild dist from clean and compare with git status including untracked and ignored files, and reproducibility was confirmed locally in each before enabling the check. Greptile found that fetching only the first hundred thread comments lets a human reply past that page escape the all bot predicate, so the filter now refuses to resolve any thread whose comment total exceeds the comments actually returned. Verified against a truncated thread with a total of one hundred fifty and two fetched nodes, which is correctly not resolved."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-10T16:23:19.099Z"}],"before_hash":"3c3705b49ccf9e87c5c38880c9f76b3a952bc615f9f98c5b67b43a33fad89a3b","after_hash":"9efe94e308a4cc092b2ee8bc790c2f8a59f3bb9925bfe2e5c5e54332972e336d"} {"ts":"2026-08-10T16:41:09.417Z","author":"claude","author_source":"asserted","agent_harness":"claude-code","agent_instance":"304c86ad9f9d7cbae7f44c3b","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":{"value":"1","source":"environment"},"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/6","value":{"created_at":"2026-08-10T16:41:09.417Z","author":"claude","text":"CodeRabbit reported that git ls-remote --tags returns both the tag object and its peeled commit for an annotated tag, so cut -f1 would yield two SHAs and git rev-list would fail. Tested against a real annotated tag pushed to a local bare remote. The peeled entry appears when ls-remote is called with no pattern or with a glob, but NOT with the exact refspec form this workflow uses, which returned a single line. The finding therefore does not reproduce against our call. The suggested form was adopted anyway because it costs nothing, states the intent explicitly, and keeps the code correct if the pattern is ever loosened to a glob."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-10T16:41:09.417Z"}],"before_hash":"9efe94e308a4cc092b2ee8bc790c2f8a59f3bb9925bfe2e5c5e54332972e336d","after_hash":"3bfec546b57470fc9666cf1d55906411f8350b7988f4d966b0f8451e2e054341"} {"ts":"2026-08-10T16:57:16.322Z","author":"claude","author_source":"asserted","agent_harness":"claude-code","agent_instance":"304c86ad9f9d7cbae7f44c3b","agent_provenance":{"model":null,"effort":{"value":"xhigh","source":"environment"},"role":{"value":"1","source":"environment"},"topic":null},"op":"note_add","patch":[{"op":"add","path":"/metadata/notes/7","value":{"created_at":"2026-08-10T16:57:16.322Z","author":"claude","text":"Round six follow up. CodeRabbit noted the parked run detection reads only the first page of the workflow runs endpoint, whose default page size is thirty, so a parked run past that page would go undetected. The query now requests one hundred per page. This is a diagnostic path rather than a safety one, since an undetected parked run simply means the release is not approved and times out without publishing, but the larger page costs nothing. Thread level pagination was declined separately because unfetched threads are never resolved and therefore keep blocking, which is the safe direction."}},{"op":"replace","path":"/metadata/updated_at","value":"2026-08-10T16:57:16.322Z"}],"before_hash":"3bfec546b57470fc9666cf1d55906411f8350b7988f4d966b0f8451e2e054341","after_hash":"ccb2819974d107822f82a38d930bb36e486d490bb0ed619c32057eb6e86bf0bb"} +{"ts":"2026-08-21T21:31:12.813Z","author":"ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"154a23dd8a71b7193a1b854c","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-21T21:31:12.813Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/closed_at","value":"2026-08-21T21:31:12.798Z"},{"op":"add","path":"/metadata/completed_at","value":"2026-08-21T21:31:12.798Z"},{"op":"add","path":"/metadata/resolution","value":"Release publish ordering fixed and merged to main via PR #46: release metadata merges through a protected PR before npm publish; only the release tag pushes after a verified publish; idempotence guard reconciles already-published versions."},{"op":"add","path":"/metadata/close_reason","value":"Fix verified live on origin/main (workflow lines: pull-requests:write, base_sha capture at decide, protected release-PR merge with parked-run approval handling, idempotent npm publish with 3-attempt provenance fallback, tag-only push after successful publish; never pushes HEAD:main again). Merged via PR #46; six bot review rounds resolved in notes. npm-ahead-of-git state eliminated."}],"before_hash":"ccb2819974d107822f82a38d930bb36e486d490bb0ed619c32057eb6e86bf0bb","after_hash":"d5576ac881a04d4027c16c7b446b527259b1fa49cfef0eb3258175a3baeae699","item_hash_version":2} +{"ts":"2026-08-21T21:31:24.293Z","author":"ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"154a23dd8a71b7193a1b854c","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-21T21:31:24.293Z"},{"op":"add","path":"/metadata/expected_result","value":"npm publish and git main/tag state always reconcile: release metadata lands on protected main through a PR before publish; only the tag pushes after a verified publish; re-runs are idempotent"},{"op":"add","path":"/metadata/actual_result","value":"Verified on origin/main: protected-PR merge flow with parked-run approval detection, idempotent publish guard with 3-attempt provenance fallback, tag-only post-publish push; merged in PR #46"}],"before_hash":"d5576ac881a04d4027c16c7b446b527259b1fa49cfef0eb3258175a3baeae699","after_hash":"faf450b3ab9e71f60ba081f77d98c61915cec1174a8984576befea79c5ed9cea","item_hash_version":2} diff --git a/.agents/pm/history/pm-github-zqad.jsonl b/.agents/pm/history/pm-github-zqad.jsonl index a88086d3..4caef4b0 100644 --- a/.agents/pm/history/pm-github-zqad.jsonl +++ b/.agents/pm/history/pm-github-zqad.jsonl @@ -1 +1,2 @@ {"ts":"2026-08-17T07:40:36.004Z","author":"codex","author_source":"configured","agent_harness":"codex","agent_instance":"839e601757a3957be5ebc227","agent_provenance":{"model":null,"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-github-zqad"},{"op":"add","path":"/metadata/title","value":"Gate historical identities and host-path privacy across every Git object"},{"op":"add","path":"/metadata/description","value":"A full-object privacy read found zero high-confidence credential signatures and zero current tracked absolute host paths, but historical objects still contain 18 host-path lines and the commit graph includes one machine-local identity already tracked by the companion fleet issue. The repository is public and those commits are ancestors of releases, so destructive history rewriting requires an explicit maintainer decision; a forward gate is independently required."},{"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":["git-history","identity-gate","privacy","release","security"]},{"op":"add","path":"/metadata/created_at","value":"2026-08-17T07:40:36.004Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-08-17T07:40:36.004Z"},{"op":"add","path":"/metadata/author","value":"codex"},{"op":"add","path":"/metadata/estimated_minutes","value":480},{"op":"add","path":"/metadata/acceptance_criteria","value":"Add a checked-in justified identity allowlist and fail-closed audit covering reachable and unreachable commits and annotated tags; add a current-tree and all-object secret/private-path gate with false-positive fixtures; classify every existing historical match without printing sensitive values into logs; obtain an explicit human decision before rewriting published history; if approved, preserve release metadata and verify old sensitive objects are no longer remotely reachable; if declined, record the residual risk and enforce the forward gate; include the audits in release:check and CI with behavioral negative controls."},{"op":"add","path":"/metadata/severity","value":"high"},{"op":"add","path":"/metadata/repro_steps","value":"Run a high-confidence credential scan and local-host-path scan over git cat-file --batch-all-objects --batch, then enumerate unique author and committer identities across all reachable refs. Compare the result with current tracked files."},{"op":"add","path":"/metadata/expected_result","value":"Every reachable and unreachable commit/tag/blob is scanned; only explicitly justified identities are allowed; new credential or local-host-path material fails CI and release:check; every historical match is classified; any rewrite of published commits/tags occurs only after explicit maintainer approval and restoration planning."},{"op":"add","path":"/metadata/actual_result","value":"Current tracked files contain zero high-confidence secret or absolute-host-path matches. Full Git object scanning reports zero high-confidence secrets and 18 historical host-path lines. The repository lacks a checked-in identity allowlist and all-object identity/privacy gate."},{"op":"add","path":"/metadata/component","value":"release governance"},{"op":"add","path":"/metadata/regression","value":false},{"op":"add","path":"/metadata/dependencies","value":[{"id":"pm-github-1jez","kind":"related","created_at":"2026-08-17T07:40:36.004Z","author":"codex","source_kind":"cli:create:dep","author_source":"detected"}]},{"op":"add","path":"/metadata/docs","value":[{"path":"https://github.com/unbraind/pm-cli-companion/blob/main/.agents/pm/issues/pm-cli-website-kxtl.toon","scope":"global","note":"Fleet commit identity gate and human rewrite decision"}]}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"c62c98a28cc4cce6ab75bde695ceef37a18d49f48c3f0384997463b001198fa6","item_hash_version":2,"message":"Track the full-history privacy and identity gate discovered by the release audit"} +{"ts":"2026-08-21T21:30:44.776Z","author":"ox-alpha","author_source":"asserted","agent_harness":"pi","agent_model":"stealth/ox-alpha","agent_model_source":"environment","agent_instance":"154a23dd8a71b7193a1b854c","agent_provenance":{"model":{"value":"stealth/ox-alpha","source":"environment"},"effort":null,"role":{"value":"implementer","source":"argv"},"topic":null},"op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-08-21T21:30:44.776Z"},{"op":"add","path":"/metadata/notes","value":[{"created_at":"2026-08-21T21:30:44.759Z","author":"ox-alpha","text":"Maintainer-approved rewrite executed 2026-08-21 (standing release-privacy directive; precedent pmc-t8tj). Disposable mirror rewritten with git-filter-repo: /home/steve -> $HOME across 15 host-path blobs (18 lines), codex@local -> 1153461+unbraind@users.noreply.github.com (1 commit, ancestor of main). Post-rewrite: 0 bad blobs, HEAD tree byte-identical (801689a), all heads/tags force-pushed, protection restored verbatim. Fresh-clone audit: reachable heads/tags fully clean. PR branch head ff6761e validated: build OK, 261/261 tests, pm health advisory-only. stefan@preu.at retained per maintainer decision 2026-07-21 (approved public authoring identity, see pm-rust allowlist); pi-agent@unbrained.dev classified as domain-based service identity for the forward allowlist. Remaining for closure: checked-in justified identity allowlist + fail-closed all-object audit + secret/host-path gate with false-positive fixtures and behavioral negative controls wired into release:check and CI."}]}],"before_hash":"c62c98a28cc4cce6ab75bde695ceef37a18d49f48c3f0384997463b001198fa6","after_hash":"f2bed5a4b3dab589fab33269340b423ab2e32db6a44d2efe757c1f1a3ac64862","item_hash_version":2} diff --git a/.agents/pm/issues/pm-github-iswq.toon b/.agents/pm/issues/pm-github-iswq.toon new file mode 100644 index 00000000..d720cb9a --- /dev/null +++ b/.agents/pm/issues/pm-github-iswq.toon @@ -0,0 +1,48 @@ +id: pm-github-iswq +title: "BREAKING: pm-github now requires pm CLI 2026.8.20 or newer; older hosts may fail installation or runtime validation" +description: "pm-github already fail-closes complete-corpus receipts, but its production argv and user-facing diagnostics still use the deprecated list-all alias and its declared pm CLI/SDK floors predate 2026.8.20." +type: Issue +status: closed +priority: 1 +tags[5]: agents,cli-ux,complete-corpus,latest-cli,tdd +created_at: "2026-08-20T21:28:31.109Z" +updated_at: "2026-08-20T21:57:30.348Z" +closed_at: "2026-08-20T21:40:41.284Z" +completed_at: "2026-08-20T21:40:41.284Z" +author: codex +estimated_minutes: 180 +acceptance_criteria: "Create failing exact-argv and alias-free real installed-CLI tests first; replace only the deprecated invocation and terminology; retain strict full unbounded fail-closed receipt validation; use top-level TypeScript imports and no any/dynamic imports; pin dev CLI/SDK and set peer/manifest floors to 2026.8.20; run release:check, exact measured-source coverage, pm health, reconcile, validate, npm/bun packed acceptance, dependency/vulnerability/privacy checks; document exact evidence and link the package PR plus companion item pm-cli-website-cbyb; do not merge or publish while pm-github-zqad or pm-github-v2kt blocks release" +risk: medium +confidence: 95 +reporter: codex +severity: medium +repro_steps: "Run the production completePmListArgs vector with pm CLI 2026.8.20 and inspect stderr; scan index.ts, README.md, and complete-corpus tests for list-all." +resolution: "Migrated the existing strict whole-corpus reader to canonical pm CLI 2026.8.20 argv without weakening its completeness decoder, added exact and real packed acceptance, aligned compatibility declarations, updated terminology, and preserved separate privacy, release-order, and exact-coverage blockers." +expected_result: "Production invokes explicit unbounded canonical pm list --all --json with full/body/strict receipts; no alias deprecation reaches stderr; source, tests, docs, generated output, package dependency, peer floor, and manifest floor agree on pm CLI/SDK 2026.8.20." +actual_result: "Implemented canonical host-owned --pm-path plus --output-include full, unbounded amount/cost, then list --all --json --include-body --strict-read; all production errors/docs and direct test fixtures use canonical terminology. Pinned local CLI/SDK 2026.8.20, set peer and manifest floors to 2026.8.20, and removed the ignored manifest pm.compatibility envelope. TDD failed 2/6 before source edits, then passed 6/6. Full suite passed 261 tests. Current measured-source coverage passed at 92.40% lines, 82.58% branches, 91.75% functions across index.ts/projects.ts; this is not 100/100/100/100 and remains independently open as pm-github-9cjx. Docstring gate documented 92 declarations; production audit found 0 vulnerabilities; pack dry-run contained 13 intended files. Clean packed npm and Bun clients each read two open/closed items with items.length=count=total, no truncation/pagination/list-all receipt, and empty child stderr. A packed npm extension authenticated through gh, validated public repo access HTTP 200, and a retry dry-ran a real GitHub import against unbraind/pm-github with no writes and a complete empty tracker; one earlier pm-changelog import attempt timed out at 30 seconds and was not counted as a pass. pm CLI receipt issue #1070 records canonical --output-include full being misreported as legacy --full. Delivery is complete but merge/publication remain blocked by pm-github-zqad and pm-github-v2kt." +affected_version: pm-github 2026.8.18 with pm CLI 2026.8.20 +component: whole-tracker pm CLI integration +customer_impact: Deprecated diagnostics can pollute machine stderr and stale compatibility floors allow hosts that do not provide the canonical contract this package now requires. +dependencies[1]{id,kind,created_at,author,source_kind,author_source}: + pm-github-ep0u,related,"2026-08-20T21:28:31.109Z",codex,"cli:create:dep",detected +notes[4]{created_at,author,text}: + "2026-08-20T21:33:00.194Z",codex,"2026-08-20 TDD: before the source edit, node --test test/complete-corpus.test.ts failed 2 of 6 tests because completePmListArgs still emitted --path/list-all and the real CLI wrote the deprecation diagnostic to stderr. After canonical argv, the stale local 2026.8.15 runtime rejected list --all as ambiguous while the host 2026.8.20 runtime passed; npm install updated the exact local @unbrained/pm-cli pin to 2026.8.20 and all 6 tests passed. Full npm test then passed 261 tests. Canonical --output-include full is currently misreported as legacy --full in the receipt, tracked upstream as pm-cli #1070; the acceptance rejects only actual list-all use until that CLI bug is fixed." + "2026-08-20T21:44:42.154Z",codex,"2026-08-20 final gates before review: npm run release:check passed 261 tests and the current 92.40/82.58/91.75 three-metric measured-source gate, 92 documented declarations, zero production audit vulnerabilities, clean 13-file pack, and current changelog. pm health --strict-exit passed with three provenance advisories; pm merge reconcile --dry-run found 82 clean streams and no pending decisions; pm validate remained structurally valid with pre-existing legacy metadata/resolution/file warnings; duplicates reported one pre-existing closed exact-title cluster. GitHub Dependabot and secret-scanning open alerts were empty; code-scanning has no analysis, and Trivy is not installed, so neither is represented as green. Public pm-changelog 2026.8.17 first refused a bounded 5-of-82 read; explicit unbounded pm-arg controls restored all 289 changelog lines. The tool still invokes its deprecated internal alias until privacy-gated pm-changelog PR #148 can merge and release. Historical privacy/identity findings remain open under pm-github-zqad and publication order remains open under pm-github-v2kt." + "2026-08-20T21:55:36.351Z",codex,"CodeRabbit exact-head review on 2026-08-20 produced four findings. Accepted: disclose the 2026.8.20 compatibility break through the package-owned changelog item; remove unsafe labels/since narrowing advice from complete-corpus ENOBUFS guidance; and pass the real installed-CLI envelope through decodeCompletePmItems before asserting decoded rows. The pm-changelog dependency upgrade request cannot yet be performed: npm latest is 2026.8.17 and no release contains privacy-blocked PR #148, so the current lock remains 2026.8.17 and merge/publication stay blocked. TDD red phase: targeted compatibility and complete-corpus tests failed exactly on the missing breaking note and unsafe buffer advice before implementation." + "2026-08-20T21:57:30.348Z",codex,"Review-fix green phase: targeted compatibility and complete-corpus tests pass 10/10. The full release gate passes all 261 tests, 92 documented declarations, zero production audit vulnerabilities, a clean 13-file pack, and a current generated changelog. The two-source coverage report is now 92.09% lines, 82.47% branches, and 91.75% functions after the diagnostic hardening; it remains non-exact and pm-github-9cjx stays open. The real acceptance now decodes the installed CLI envelope through the production decoder and forces a one-byte buffer to prove the complete-reader error offers no narrowing workaround." +files[5]{path,scope,note}: + index.ts,project,Canonical complete-corpus argv and diagnostics + manifest.json,project,Runtime-enforced host floor + package.json,project,Peer and exact development CLI SDK floors + test/compatibility-floor.test.ts,project,Exact 2026.8.20 host floor and manifest contract + test/complete-corpus.test.ts,project,Exact argv and installed CLI completeness acceptance +tests[2]{command,path,scope,timeout_seconds,note}: + "npm run release:check",package.json,project,1200,Full package release gate + npm test,test/complete-corpus.test.ts,project,900,261-test suite includes red-green canonical argv and real installed-CLI receipt acceptance +docs[4]{path,scope,note}: + "https://github.com/unbraind/pm-changelog/pull/148",global,Canonical unbounded changelog reader awaiting privacy-gated merge and publication + "https://github.com/unbraind/pm-cli-companion/blob/docs/record-pm-rl-pm-csv-cli-2026-8-20/.agents/pm/issues/pm-cli-website-cbyb.toon",global,Companion fleet canonical-command migration owner + "https://github.com/unbraind/pm-cli/issues/1070",global,Upstream receipt bug found during installed-CLI acceptance + README.md,project,Canonical complete-corpus contract and copyable invocation +close_reason: Canonical whole-corpus reader delivery is implemented and verified; package merge/publication remain separately blocked by pm-github-zqad and pm-github-v2kt. +body: "" diff --git a/.agents/pm/issues/pm-github-v2kt.toon b/.agents/pm/issues/pm-github-v2kt.toon index 93ebaad1..52cf5cdb 100644 --- a/.agents/pm/issues/pm-github-v2kt.toon +++ b/.agents/pm/issues/pm-github-v2kt.toon @@ -2,12 +2,17 @@ id: pm-github-v2kt title: Fix release publish ordering ahead of protected main push description: "The daily release workflow published to npm and then pushed the version bump straight to a protected main branch. Branch protection rejected that push with GH006, and the job's fail-fast shell mode killed it before the tag push, so npm ended up ahead of git: main stayed on an older version with no matching tag. The release metadata is now merged through a protected PR before npm publish runs, and only the release tag is pushed after a successful publish. Ported from the verified fix in pm-beads." type: Issue -status: open +status: closed priority: 2 tags: [] created_at: "2026-08-10T15:27:52.482Z" -updated_at: "2026-08-10T16:57:16.322Z" +updated_at: "2026-08-21T21:31:24.293Z" +closed_at: "2026-08-21T21:31:12.798Z" +completed_at: "2026-08-21T21:31:12.798Z" author: pi-agent +resolution: "Release publish ordering fixed and merged to main via PR #46: release metadata merges through a protected PR before npm publish; only the release tag pushes after a verified publish; idempotence guard reconciles already-published versions." +expected_result: "npm publish and git main/tag state always reconcile: release metadata lands on protected main through a PR before publish; only the tag pushes after a verified publish; re-runs are idempotent" +actual_result: "Verified on origin/main: protected-PR merge flow with parked-run approval detection, idempotent publish guard with 3-attempt provenance fallback, tag-only post-publish push; merged in PR #46" notes[8]{created_at,author,text}: "2026-08-10T15:27:52.883Z",pi-agent,"Applied the pm-beads release ordering fix to .github/workflows/release.yml: added pull-requests write permission, captured base_sha in the decide step, and replaced the publish-then-push-to-main steps with a protected-PR merge, a verify-merged-release check, the npm publish (with idempotence guard), and a tag-only push. dist is gitignored here so it is excluded from the verify diff. Gates npm ci, build, test, release:check and yaml all pass." "2026-08-10T15:30:44.660Z",claude,"Greptile reported that creating the release pull request with GITHUB_TOKEN suppresses its pull_request event so CI never starts. Measured against pm-changelog, the event is not suppressed: a run was created at 04:54:24Z with event pull_request for branch release/2026.8.9. The real blocker is that attempt 1 concluded action_required, meaning GitHub parked the run awaiting workflow approval under the fork pull request contributor approval policy of first_time_contributors, because github-actions had no merged pull request in that repository yet. A parked run never appears in the status check rollup, so it is indistinguishable from a required check that failed. The merge wait now detects parked runs, reports the run URL, attempts approval using the actions write permission, and separates awaiting approval from a failed check in the deadline error." @@ -17,4 +22,5 @@ notes[8]{created_at,author,text}: "2026-08-10T16:23:19.099Z",claude,"Round five review fixes. CodeRabbit found that the tracking note claimed dist validation that pm-web's workflow did not actually contain. An audit showed seven repositories track dist but had no rebuild check, because the earlier patch keyed on a diff paths idiom those repositories do not use: pm-changelog, pm-context, pm-gantt-chart, pm-graph, pm-jira, pm-ops and pm-web. All seven now rebuild dist from clean and compare with git status including untracked and ignored files, and reproducibility was confirmed locally in each before enabling the check. Greptile found that fetching only the first hundred thread comments lets a human reply past that page escape the all bot predicate, so the filter now refuses to resolve any thread whose comment total exceeds the comments actually returned. Verified against a truncated thread with a total of one hundred fifty and two fetched nodes, which is correctly not resolved." "2026-08-10T16:41:09.417Z",claude,"CodeRabbit reported that git ls-remote --tags returns both the tag object and its peeled commit for an annotated tag, so cut -f1 would yield two SHAs and git rev-list would fail. Tested against a real annotated tag pushed to a local bare remote. The peeled entry appears when ls-remote is called with no pattern or with a glob, but NOT with the exact refspec form this workflow uses, which returned a single line. The finding therefore does not reproduce against our call. The suggested form was adopted anyway because it costs nothing, states the intent explicitly, and keeps the code correct if the pattern is ever loosened to a glob." "2026-08-10T16:57:16.322Z",claude,"Round six follow up. CodeRabbit noted the parked run detection reads only the first page of the workflow runs endpoint, whose default page size is thirty, so a parked run past that page would go undetected. The query now requests one hundred per page. This is a diagnostic path rather than a safety one, since an undetected parked run simply means the release is not approved and times out without publishing, but the larger page costs nothing. Thread level pagination was declined separately because unfetched threads are never resolved and therefore keep blocking, which is the safe direction." +close_reason: "Fix verified live on origin/main (workflow lines: pull-requests:write, base_sha capture at decide, protected release-PR merge with parked-run approval handling, idempotent npm publish with 3-attempt provenance fallback, tag-only push after successful publish; never pushes HEAD:main again). Merged via PR #46; six bot review rounds resolved in notes. npm-ahead-of-git state eliminated." body: "" diff --git a/.agents/pm/issues/pm-github-zqad.toon b/.agents/pm/issues/pm-github-zqad.toon index 43fc3113..89fbaa35 100644 --- a/.agents/pm/issues/pm-github-zqad.toon +++ b/.agents/pm/issues/pm-github-zqad.toon @@ -6,7 +6,7 @@ status: open priority: 1 tags[5]: git-history,identity-gate,privacy,release,security created_at: "2026-08-17T07:40:36.004Z" -updated_at: "2026-08-17T07:40:36.004Z" +updated_at: "2026-08-21T21:30:44.776Z" author: codex estimated_minutes: 480 acceptance_criteria: "Add a checked-in justified identity allowlist and fail-closed audit covering reachable and unreachable commits and annotated tags; add a current-tree and all-object secret/private-path gate with false-positive fixtures; classify every existing historical match without printing sensitive values into logs; obtain an explicit human decision before rewriting published history; if approved, preserve release metadata and verify old sensitive objects are no longer remotely reachable; if declined, record the residual risk and enforce the forward gate; include the audits in release:check and CI with behavioral negative controls." @@ -18,6 +18,8 @@ component: release governance regression: false dependencies[1]{id,kind,created_at,author,source_kind,author_source}: pm-github-1jez,related,"2026-08-17T07:40:36.004Z",codex,"cli:create:dep",detected +notes[1]{created_at,author,text}: + "2026-08-21T21:30:44.759Z",ox-alpha,"Maintainer-approved rewrite executed 2026-08-21 (standing release-privacy directive; precedent pmc-t8tj). Disposable mirror rewritten with git-filter-repo: /home/steve -> $HOME across 15 host-path blobs (18 lines), codex@local -> 1153461+unbraind@users.noreply.github.com (1 commit, ancestor of main). Post-rewrite: 0 bad blobs, HEAD tree byte-identical (801689a), all heads/tags force-pushed, protection restored verbatim. Fresh-clone audit: reachable heads/tags fully clean. PR branch head ff6761e validated: build OK, 261/261 tests, pm health advisory-only. stefan@preu.at retained per maintainer decision 2026-07-21 (approved public authoring identity, see pm-rust allowlist); pi-agent@unbrained.dev classified as domain-based service identity for the forward allowlist. Remaining for closure: checked-in justified identity allowlist + fail-closed all-object audit + secret/host-path gate with false-positive fixtures and behavioral negative controls wired into release:check and CI." docs[1]{path,scope,note}: "https://github.com/unbraind/pm-cli-companion/blob/main/.agents/pm/issues/pm-cli-website-kxtl.toon",global,Fleet commit identity gate and human rewrite decision body: "" diff --git a/CHANGELOG.md b/CHANGELOG.md index 19b0f27f..8a9740ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Fixed + +- Fix release publish ordering ahead of protected main push ([pm-github-v2kt](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-v2kt.toon)) +- BREAKING: pm-github now requires pm CLI 2026.8.20 or newer; older hosts may fail installation or runtime validation ([pm-github-iswq](https://github.com/unbraind/pm-github/blob/main/.agents/pm/issues/pm-github-iswq.toon)) + ## 2026.8.18 - 2026-08-18 ### Fixed diff --git a/README.md b/README.md index 719d237e..c3731adf 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,25 @@ pm install npm:pm-github --global Import idempotency, export, status sync, Projects v2 sync, and search fallback all depend on seeing every pm item, including closed and canceled work. Before any of those paths plans or performs a GitHub operation, pm-github requests a -strict, full, unbounded `pm list-all` response and verifies its completeness, +strict, full, unbounded `pm list --all` response and verifies its completeness, omission, pagination, output-budget, count, identity, and consumed-field contracts. An incomplete or unverifiable response fails closed; it is never treated as an empty or partial workspace. +The production subprocess uses the same canonical argument contract as: + +```bash +pm --pm-path \ + --output-include full \ + --output-limit unbounded \ + --output-budget unbounded \ + list --all --json --include-body --strict-read +``` + +The output controls precede the command so the host owns the complete-result +contract; `list --all` includes terminal items without invoking the deprecated +`list-all` alias. + The subprocess still has a 64 MiB byte safety cap. Set `PM_JSON_MAX_BUFFER=` to a larger positive safe integer for an unusually large tracker. Raising that transport cap does not weaken the completeness diff --git a/index.ts b/index.ts index 0926b932..75b516e4 100644 --- a/index.ts +++ b/index.ts @@ -805,7 +805,7 @@ export function authorTag(issue: GhIssue): string | undefined { * The slice of a pm item this package reads and writes. * * A deliberately loose projection of the full tracker item: only the fields the - * import / export / sync paths touch, so JSON from `pm list-all` parses without + * import / export / sync paths touch, so JSON from `pm list --all` parses without * depending on every SDK field. */ export interface PmItem { @@ -859,7 +859,7 @@ function describeJsonValue(value: unknown): string { return rendered === undefined ? String(value) : rendered; } -/** Require one exact field value from the `pm list-all` truthfulness envelope. */ +/** Require one exact field value from the `pm list --all` truthfulness envelope. */ function requireCompletePmField( actual: unknown, expected: string | number | boolean | null, @@ -867,7 +867,7 @@ function requireCompletePmField( ): void { if (actual !== expected) { throw new CommandError( - `Refusing unverifiable pm list-all output: ${field} must be ${describeJsonValue(expected)}; received ${describeJsonValue(actual)}.`, + `Refusing unverifiable pm list --all output: ${field} must be ${describeJsonValue(expected)}; received ${describeJsonValue(actual)}.`, ); } } @@ -881,36 +881,37 @@ const COMPLETE_PM_READ_CONTRACT = { /** * Build the canonical installed-CLI invocation for a whole-workspace read. * - * The output controls are deliberately explicit. `list-all` includes terminal + * The output controls are deliberately explicit. `list --all` includes terminal * items, `--output-include full` plus `--include-body` retains every field this * integration consumes, `--strict-read` rejects unreadable records, and both * amount and cost are unbounded. An arbitrary `--limit` must never be added: * callers use this corpus to prevent duplicate imports and missing syncs. * - * @param pmRoot - Workspace or tracker root accepted by the pm CLI `--path` flag. + * @param pmRoot - Workspace or tracker root accepted by the pm CLI `--pm-path` flag. * @returns Argument vector passed to the installed `pm` executable. * @internal Exported so the acceptance test can bind the safety contract to the * exact production invocation; it is removed from the published declaration. */ export function completePmListArgs(pmRoot: string): string[] { return [ - "--path", + "--pm-path", pmRoot, - "list-all", - "--json", - "--include-body", "--output-include", "full", - "--strict-read", "--output-limit", "unbounded", "--output-budget", "unbounded", + "list", + "--all", + "--json", + "--include-body", + "--strict-read", ]; } /** - * Decode only a complete, unbounded `pm list-all` response. + * Decode only a complete, unbounded `pm list --all` response. * * The subprocess JSON is untrusted. This gate independently verifies every * completeness signal emitted by the current CLI, reconciles envelope counts, @@ -929,11 +930,11 @@ export function completePmListArgs(pmRoot: string): string[] { export function decodeCompletePmItems(parsed: unknown): PmItem[] { if (!isJsonRecord(parsed)) { throw new CommandError( - "Refusing unverifiable pm list-all output: the response must be a top-level object with completeness receipts.", + "Refusing unverifiable pm list --all output: the response must be a top-level object with completeness receipts.", ); } if (!Array.isArray(parsed.items)) { - throw new CommandError("Refusing unverifiable pm list-all output: items must be an array."); + throw new CommandError("Refusing unverifiable pm list --all output: items must be an array."); } requireCompletePmField(parsed.truncated, false, "truncated"); @@ -958,7 +959,7 @@ export function decodeCompletePmItems(parsed: unknown): PmItem[] { ); if (!Array.isArray(omission.omitted_field_groups) || omission.omitted_field_groups.length !== 0) { throw new CommandError( - "Refusing unverifiable pm list-all output: omission_receipt.omitted_field_groups must be empty.", + "Refusing unverifiable pm list --all output: omission_receipt.omitted_field_groups must be empty.", ); } @@ -987,33 +988,33 @@ export function decodeCompletePmItems(parsed: unknown): PmItem[] { || !readOutput.requested_dimensions.includes("cost") ) { throw new CommandError( - "Refusing unverifiable pm list-all output: read_output.requested_dimensions must include include, amount, and cost.", + "Refusing unverifiable pm list --all output: read_output.requested_dimensions must include include, amount, and cost.", ); } if ("output_budget_truncation" in parsed || "output_budget_exceeded" in parsed) { throw new CommandError( - "Refusing unverifiable pm list-all output: a budget truncation or omission disclosure was present.", + "Refusing unverifiable pm list --all output: a budget truncation or omission disclosure was present.", ); } if (!Number.isSafeInteger(parsed.count) || (parsed.count as number) < 0) { throw new CommandError( - `Refusing unverifiable pm list-all output: count must be a non-negative safe integer; received ${describeJsonValue(parsed.count)}.`, + `Refusing unverifiable pm list --all output: count must be a non-negative safe integer; received ${describeJsonValue(parsed.count)}.`, ); } if (!Number.isSafeInteger(parsed.total) || (parsed.total as number) < 0) { throw new CommandError( - `Refusing unverifiable pm list-all output: total must be a non-negative safe integer; received ${describeJsonValue(parsed.total)}.`, + `Refusing unverifiable pm list --all output: total must be a non-negative safe integer; received ${describeJsonValue(parsed.total)}.`, ); } if (parsed.items.length !== parsed.count) { throw new CommandError( - `Refusing unverifiable pm list-all output: items.length ${parsed.items.length} must equal count ${String(parsed.count)}.`, + `Refusing unverifiable pm list --all output: items.length ${parsed.items.length} must equal count ${String(parsed.count)}.`, ); } if (parsed.count !== parsed.total) { throw new CommandError( - `Refusing incomplete pm list-all output: count ${String(parsed.count)} must equal total ${String(parsed.total)}.`, + `Refusing incomplete pm list --all output: count ${String(parsed.count)} must equal total ${String(parsed.total)}.`, ); } @@ -1021,35 +1022,35 @@ export function decodeCompletePmItems(parsed: unknown): PmItem[] { const items: PmItem[] = []; for (const [index, item] of parsed.items.entries()) { if (!isJsonRecord(item)) { - throw new CommandError(`Refusing unverifiable pm list-all output: item ${index} must be an object.`); + throw new CommandError(`Refusing unverifiable pm list --all output: item ${index} must be an object.`); } if (typeof item.id !== "string" || item.id.trim().length === 0) { - throw new CommandError(`Refusing unverifiable pm list-all output: item ${index} must have a non-empty id.`); + throw new CommandError(`Refusing unverifiable pm list --all output: item ${index} must have a non-empty id.`); } if (ids.has(item.id)) { - throw new CommandError(`Refusing unverifiable pm list-all output: duplicate item id ${item.id}.`); + throw new CommandError(`Refusing unverifiable pm list --all output: duplicate item id ${item.id}.`); } const title = item.title; const status = item.status; const body = item.body; const description = item.description; if (typeof title !== "string") { - throw new CommandError(`Refusing unverifiable pm list-all output: item ${item.id} title must be a string.`); + throw new CommandError(`Refusing unverifiable pm list --all output: item ${item.id} title must be a string.`); } if (typeof status !== "string") { - throw new CommandError(`Refusing unverifiable pm list-all output: item ${item.id} status must be a string.`); + throw new CommandError(`Refusing unverifiable pm list --all output: item ${item.id} status must be a string.`); } if (typeof body !== "string") { - throw new CommandError(`Refusing unverifiable pm list-all output: item ${item.id} body must be a string.`); + throw new CommandError(`Refusing unverifiable pm list --all output: item ${item.id} body must be a string.`); } if (typeof description !== "string") { throw new CommandError( - `Refusing unverifiable pm list-all output: item ${item.id} description must be a string.`, + `Refusing unverifiable pm list --all output: item ${item.id} description must be a string.`, ); } if (!Array.isArray(item.tags) || item.tags.some((tag) => typeof tag !== "string")) { throw new CommandError( - `Refusing unverifiable pm list-all output: item ${item.id} tags must be an array of strings.`, + `Refusing unverifiable pm list --all output: item ${item.id} tags must be an array of strings.`, ); } ids.add(item.id); @@ -1130,21 +1131,21 @@ export function readPmItems( const code = (result.error as NodeJS.ErrnoException).code; if (code === "ENOBUFS") { throw new CommandError( - `pm list-all output exceeded the ${maxBuffer} byte read buffer. ` + - "The workspace is larger than this read limit; narrow the import " + - "(for example --labels or --since) or raise the PM_JSON_MAX_BUFFER env var.", + `pm list --all output exceeded the ${maxBuffer} byte read buffer. ` + + "The complete corpus cannot be narrowed safely. Only raise the " + + "PM_JSON_MAX_BUFFER env var after confirming the workspace size and available memory.", ); } - throw new CommandError(`pm list-all failed: ${result.error.message}`); + throw new CommandError(`pm list --all failed: ${result.error.message}`); } if (result.status !== 0) { - throw new CommandError(result.stderr || "pm list-all failed"); + throw new CommandError(result.stderr || "pm list --all failed"); } let parsed: unknown; try { parsed = JSON.parse(result.stdout) as unknown; } catch { - throw new CommandError("Could not parse `pm list-all --json` output."); + throw new CommandError("Could not parse `pm list --all --json` output."); } return decodeCompletePmItems(parsed); } @@ -1214,9 +1215,9 @@ export function indexByProvenance(items: PmItem[]): Map { // --------------------------------------------------------------------------- // Node's spawnSync defaults to a 1 MiB stdout cap. A mature tracker's full JSON -// dump (`pm list-all --full --include-body`) passes that at a few hundred items, +// dump (`pm --output-include full list --all --include-body`) passes that at a few hundred items, // and the child is then killed with ENOBUFS, status null and EMPTY stderr — which -// surfaced as a bare "pm list-all failed" with nothing to diagnose. Reproduced on +// surfaced as a bare "pm list --all failed" with nothing to diagnose. Reproduced on // a real 443-item workspace at 1,052,859 bytes. 64 MiB matches the cap the sibling // pm packages settled on (pm-changelog, pm-context, pm-brief). /** Read-buffer cap for `pm` output, in bytes. 64 MiB by default; override with the diff --git a/manifest.json b/manifest.json index 76401709..8f5567d0 100644 --- a/manifest.json +++ b/manifest.json @@ -4,7 +4,7 @@ "description": "GitHub Issues + Projects v2 integration. Imports issues as pm items (`pm github import`), exports pm items as GitHub issues, syncs issue state, and bidirectionally syncs pm items with a GitHub Projects v2 board (`pm github project import/sync/list/fields`) — mapping pm status to the board Status column with idempotent, no-data-loss provenance.", "author": "@unbraind", "entry": "./dist/index.js", - "pm_min_version": "2026.8.3", + "pm_min_version": "2026.8.20", "priority": 50, "capabilities": [ "commands", @@ -13,8 +13,5 @@ "hooks", "preflight", "search" - ], - "pm": { - "compatibility": "v2" - } + ] } diff --git a/package-lock.json b/package-lock.json index c0197157..7438237d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,16 +10,16 @@ "license": "MIT", "devDependencies": { "@types/node": "^26.1.1", - "@unbrained/pm-cli": "2026.8.17", - "pm-changelog": "^2026.8.6", - "pm-ops": "^2026.8.8", + "@unbrained/pm-cli": "2026.8.20", + "pm-changelog": "^2026.8.17", + "pm-ops": "^2026.8.17", "typescript": "^7.0.2" }, "engines": { "node": ">=22.18.0" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.8.3" + "@unbrained/pm-cli": ">=2026.8.20" } }, "node_modules/@apm-js-collab/code-transformer": { @@ -732,9 +732,9 @@ } }, "node_modules/@unbrained/pm-cli": { - "version": "2026.8.17", - "resolved": "https://registry.npmjs.org/@unbrained/pm-cli/-/pm-cli-2026.8.17.tgz", - "integrity": "sha512-G0eh1wVNyhJvIKXAx3epbuDamHBfl7AaU6zNbUuIHEpWU1yia7gfx6d0TSwLuhjgTb2lTChCWApp+et1E53r5Q==", + "version": "2026.8.20", + "resolved": "https://registry.npmjs.org/@unbrained/pm-cli/-/pm-cli-2026.8.20.tgz", + "integrity": "sha512-q2EHf97Z1Qou1STH2SGI5bFIKQJuKLz0/6SfsD83zsx5pKlSd+fSyyyB4hYpf6bNDYgHjJNtsqcVmBVdHibSzg==", "dev": true, "license": "MIT", "dependencies": { @@ -1096,9 +1096,9 @@ } }, "node_modules/pm-changelog": { - "version": "2026.8.12", - "resolved": "https://registry.npmjs.org/pm-changelog/-/pm-changelog-2026.8.12.tgz", - "integrity": "sha512-eOX2xJJm8fLo9n7Eua4hTs46TToYPcVdp9gfRYqPqNmaik+dBawqNMb3otOeDa8Sbp5o7YIAQlgXDVH5Y0/bPA==", + "version": "2026.8.17", + "resolved": "https://registry.npmjs.org/pm-changelog/-/pm-changelog-2026.8.17.tgz", + "integrity": "sha512-wU52DpIWlSRhi0v3xtktgVF+oLte4Z+LWZ0H3VjbrhG+8XOEJrhevOu0YqMyiPQvNyt0SpDXy8OEhyxyaIcVEA==", "dev": true, "license": "MIT", "bin": { @@ -1108,13 +1108,13 @@ "node": ">=22.18.0" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.8.3" + "@unbrained/pm-cli": ">=2026.8.16" } }, "node_modules/pm-ops": { - "version": "2026.8.10", - "resolved": "https://registry.npmjs.org/pm-ops/-/pm-ops-2026.8.10.tgz", - "integrity": "sha512-sNtvpGikYMTK7IM1oHYHEH+n/WyAjTy9Nrmtps2IaRm6uYE8fFGkoHl/bpqh+Z5eoGsTskaRCiIlseeMXMFhIA==", + "version": "2026.8.17", + "resolved": "https://registry.npmjs.org/pm-ops/-/pm-ops-2026.8.17.tgz", + "integrity": "sha512-fB5OvGw8yGAC/Zg/Em7cIlltXG7ZQ7r7d2s6NOEG8dxUl3cs42yyRWOCjUnSRAKNmSIX4zxbXpgPOZyGhD1MeQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1125,7 +1125,7 @@ "node": ">=22.18.0" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.7.31" + "@unbrained/pm-cli": ">=2026.8.15" } }, "node_modules/proc-log": { diff --git a/package.json b/package.json index daee8722..b64d875d 100644 --- a/package.json +++ b/package.json @@ -29,23 +29,23 @@ "docstring": "node scripts/docstring-gate.ts", "audit:prod": "node --input-type=module -e \"import { spawnSync } from 'node:child_process'; import { devNull } from 'node:os'; const env = { ...process.env, npm_config_userconfig: devNull, NPM_CONFIG_USERCONFIG: devNull }; for (const key of Object.keys(env)) if (key.toLowerCase() === 'npm_config_allow_scripts') delete env[key]; const win = process.platform === 'win32'; const r = spawnSync(win ? 'npm.cmd' : 'npm', ['audit', '--omit=dev', '--ignore-scripts'], { stdio: 'inherit', env, shell: win }); process.exit(r.status ?? 1);\"", "pack:dry-run": "npm pack --dry-run", - "changelog:full": "pm-changelog --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release", + "changelog:full": "pm-changelog --pm-root .agents/pm --pm-arg=--output-limit --pm-arg=unbounded --pm-arg=--output-budget --pm-arg=unbounded --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release", "changelog:check": "npm run changelog:full -- --check", "release:check": "npm run typecheck && npm run build && npm run docstring && npm run coverage && npm run audit:prod && npm run pack:dry-run && npm run changelog:check", "prepublishOnly": "npm run release:check", - "release:notes": "pm-changelog --pm-root .agents/pm --stdout --since-previous-tag --until-release-tag --release-version-from-package --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --github-step-summary", + "release:notes": "pm-changelog --pm-root .agents/pm --pm-arg=--output-limit --pm-arg=unbounded --pm-arg=--output-budget --pm-arg=unbounded --stdout --since-previous-tag --until-release-tag --release-version-from-package --item-url-base https://github.com/unbraind/pm-github/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --github-step-summary", "prepare": "node scripts/prepare-merge-driver.mjs", "merge:install": "pm merge install", "coverage": "npm run build && npm run build:test && node scripts/coverage-gate.ts" }, "peerDependencies": { - "@unbrained/pm-cli": ">=2026.8.3" + "@unbrained/pm-cli": ">=2026.8.20" }, "devDependencies": { "@types/node": "^26.1.1", - "@unbrained/pm-cli": "2026.8.17", - "pm-changelog": "^2026.8.6", - "pm-ops": "^2026.8.8", + "@unbrained/pm-cli": "2026.8.20", + "pm-changelog": "^2026.8.17", + "pm-ops": "^2026.8.17", "typescript": "^7.0.2" }, "keywords": [ diff --git a/test/atomic.test.ts b/test/atomic.test.ts index ffb0ac81..542b7642 100644 --- a/test/atomic.test.ts +++ b/test/atomic.test.ts @@ -59,10 +59,20 @@ function freshTracker(): string { function listItems(root: string): Array<{ id: string; title: string; status: string }> { const result = spawnSync( PM_BIN, - ["--path", root, "list-all", "--json", "--full", "--limit", "100"], + [ + "--pm-path", + root, + "--output-include", + "full", + "list", + "--all", + "--json", + "--limit", + "100", + ], PM_SPAWN_OPTS, ); - assert.strictEqual(result.status, 0, `pm list-all failed: ${result.error?.message ?? result.stderr}`); + assert.strictEqual(result.status, 0, `pm list --all failed: ${result.error?.message ?? result.stderr}`); const parsed = JSON.parse(result.stdout) as { items?: Array<{ id: string; title: string; status: string }> }; return parsed.items ?? []; } diff --git a/test/compatibility-floor.test.ts b/test/compatibility-floor.test.ts index ffbf3e18..b312eeef 100644 --- a/test/compatibility-floor.test.ts +++ b/test/compatibility-floor.test.ts @@ -19,6 +19,8 @@ interface ExtensionManifest { * names the actual type rather than being coerced into a plausible string. */ readonly pm_min_version?: unknown; + /** Obsolete compatibility envelope retained only to prove it is absent. */ + readonly pm?: unknown; } const packageJson = JSON.parse( @@ -27,9 +29,11 @@ const packageJson = JSON.parse( const extensionManifest = JSON.parse( readFileSync(resolve(repoRoot, "manifest.json"), "utf8"), ) as ExtensionManifest; +const changelog = readFileSync(resolve(repoRoot, "CHANGELOG.md"), "utf8"); const CLI = "@unbrained/pm-cli"; const EXACT_VERSION = /^\d+\.\d+\.\d+$/; +const CANONICAL_LIST_FLOOR = "2026.8.20"; /** * Two independent systems enforce the pm CLI compatibility floor, and each reads @@ -91,6 +95,20 @@ test("the extension manifest declares the same floor the CLI actually enforces", peer.slice(">=".length), "manifest.json pm_min_version must equal the peerDependencies floor, or npm and the pm CLI enforce different minimums", ); + assert.strictEqual( + declared, + CANONICAL_LIST_FLOOR, + "the canonical list --all invocation requires the pm CLI 2026.8.20 host contract", + ); + assert.ok( + !Object.hasOwn(extensionManifest, "pm"), + "manifest.json must not carry the ignored legacy pm.compatibility envelope", + ); + assert.match( + changelog, + /BREAKING: pm-github now requires pm CLI 2026\.8\.20 or newer; older hosts may fail installation or runtime validation/, + "CHANGELOG.md must disclose the compatibility break enforced by the manifest and peer dependency", + ); }); test("the development dependency is an exact pin at or above the declared floor", () => { @@ -116,6 +134,11 @@ test("the development dependency is an exact pin at or above the declared floor" atOrAbove(dev, declared as string), `the pinned development CLI ${dev} is below the declared floor ${String(declared)}`, ); + assert.strictEqual( + dev, + CANONICAL_LIST_FLOOR, + "development must test the exact required host contract", + ); }); test("the version comparison orders YYYY.M.D numerically, not lexicographically", () => { diff --git a/test/complete-corpus.test.ts b/test/complete-corpus.test.ts index d8d44b50..e8d7248d 100644 --- a/test/complete-corpus.test.ts +++ b/test/complete-corpus.test.ts @@ -1,5 +1,5 @@ import assert from "node:assert/strict"; -import { execFileSync } from "node:child_process"; +import { execFileSync, spawnSync } from "node:child_process"; import { mkdtempSync, rmSync } from "node:fs"; import { createRequire } from "node:module"; import { tmpdir } from "node:os"; @@ -12,7 +12,7 @@ import { readPmItems, } from "../index.ts"; -/** Current complete `pm list-all --json` envelope, with caller overrides. */ +/** Current complete `pm list --all --json` envelope, with caller overrides. */ function completeEnvelope(overrides: Record = {}): Record { return { items: [ @@ -74,20 +74,25 @@ function runPm(args: string[], cwd?: string): string { test("whole-corpus argv requests strict full unbounded output without an arbitrary row ceiling", () => { const args = completePmListArgs("/workspace/.agents/pm"); assert.deepEqual(args, [ - "--path", + "--pm-path", "/workspace/.agents/pm", - "list-all", - "--json", - "--include-body", "--output-include", "full", - "--strict-read", "--output-limit", "unbounded", "--output-budget", "unbounded", + "list", + "--all", + "--json", + "--include-body", + "--strict-read", ]); - assert.ok(!args.includes("--limit"), "a list-all row ceiling makes the corpus incomplete by construction"); + assert.ok( + !args.includes("--limit"), + "a canonical whole-corpus row ceiling makes the read incomplete by construction", + ); + assert.ok(!args.includes("list-all"), "production must not invoke the deprecated list-all alias"); }); test("Windows strategy keeps shell metacharacters inside the pm workspace argument", () => { @@ -237,6 +242,50 @@ test("real installed CLI returns a complete open-and-closed corpus from a fresh "Open acceptance task", ]); + const result = spawnSync("pm", completePmListArgs(workspace), { + encoding: "utf8", + env: { ...process.env, PM_AUTHOR: "pm-github-acceptance" }, + shell: process.platform === "win32", + }); + assert.equal(result.status, 0, result.stderr); + assert.equal( + result.stderr, + "", + "the canonical installed-CLI read must not emit deprecation diagnostics", + ); + const parsed = JSON.parse(result.stdout) as unknown; + const decodedItems = decodeCompletePmItems(parsed); + const envelope = parsed as { + items: Array<{ id?: unknown }>; + count: number; + total: number; + truncated: boolean; + has_more: boolean; + read_output: { command: string; legacy_aliases_used?: unknown[] }; + }; + assert.equal(decodedItems.length, envelope.count); + assert.equal(envelope.count, envelope.total); + assert.equal(envelope.truncated, false); + assert.equal(envelope.has_more, false); + assert.equal(envelope.read_output.command, "list"); + assert.ok( + !envelope.read_output.legacy_aliases_used?.includes("list-all"), + "the real receipt must not report the deprecated list-all alias", + ); + assert.ok(decodedItems.some((item) => item.id === created.id)); + + const priorMaxBuffer = process.env.PM_JSON_MAX_BUFFER; + process.env.PM_JSON_MAX_BUFFER = "1"; + try { + assert.throws( + () => readPmItems(workspace), + /Only raise the PM_JSON_MAX_BUFFER env var after confirming the workspace size and available memory\./, + ); + } finally { + if (priorMaxBuffer === undefined) delete process.env.PM_JSON_MAX_BUFFER; + else process.env.PM_JSON_MAX_BUFFER = priorMaxBuffer; + } + const items = readPmItems(workspace); assert.equal(items.length, 2); assert.deepEqual( diff --git a/test/handler-failures.test.ts b/test/handler-failures.test.ts index a1005edf..f1436afd 100644 --- a/test/handler-failures.test.ts +++ b/test/handler-failures.test.ts @@ -71,7 +71,7 @@ function pmSetup(root: string, args: readonly string[]): void { // A PATH that finds the local `pm` shim + `node` but NOT `gh`, so the // token-resolution fallback (`gh auth token`) deterministically fails while -// `pm list-all` still works. Used for the no-token guards whose handlers read +// `pm list --all` still works. Used for the no-token guards whose handlers read // the tracker before checking the token. const PM_BIN_DIR = fileURLToPath(new URL("../node_modules/.bin", import.meta.url)); const GH_FREE_PATH = `${PM_BIN_DIR}${path.delimiter}${path.dirname(process.execPath)}`; @@ -102,7 +102,11 @@ function createLinkedItem(root: string, title: string, tag: string, status: stri ); assert.strictEqual(r.status, 0, `pm create failed: ${r.error?.message ?? r.stderr}`); // Re-read to get the assigned id. - const list = spawnSync(PM_BIN, ["--path", root, "--json", "list-all", "--full"], PM_SPAWN_OPTS); + const list = spawnSync( + PM_BIN, + ["--pm-path", root, "--json", "--output-include", "full", "list", "--all"], + PM_SPAWN_OPTS, + ); const parsed = JSON.parse(list.stdout) as { items?: Array<{ id: string; tags?: string[] }> }; const item = (parsed.items ?? []).find((i) => (i.tags ?? []).includes(tag)); assert.ok(item, `created item carrying ${tag} should be listable`); @@ -1099,7 +1103,11 @@ function upstreamIssue(number: number, title: string, state: "open" | "closed"): /** Read a pm item's status by its provenance tag (for reconciliation asserts). */ function statusForTag(root: string, tag: string): string | undefined { - const r = spawnSync(PM_BIN, ["--path", root, "--json", "list-all", "--full"], PM_SPAWN_OPTS); + const r = spawnSync( + PM_BIN, + ["--pm-path", root, "--json", "--output-include", "full", "list", "--all"], + PM_SPAWN_OPTS, + ); const parsed = JSON.parse(r.stdout) as { items?: Array<{ status?: string; tags?: string[] }> }; return (parsed.items ?? []).find((i) => (i.tags ?? []).includes(tag))?.status; } @@ -1189,7 +1197,11 @@ function listTitles(root: string): string[] { /** Read every pm item (including closed) with its status and close_reason. */ function listAllStatuses(root: string): Array<{ id: string; title: string; status: string; close_reason?: string }> { - const r = spawnSync(PM_BIN, ["--path", root, "--json", "list-all", "--full"], PM_SPAWN_OPTS); + const r = spawnSync( + PM_BIN, + ["--pm-path", root, "--json", "--output-include", "full", "list", "--all"], + PM_SPAWN_OPTS, + ); const parsed = JSON.parse(r.stdout); const arr = Array.isArray(parsed) ? parsed : (parsed.items ?? parsed.results ?? []); return (arr as Array<{ id: string; title: string; status: string; close_reason?: string }>);