From d95c7557dcf55ea1b04b0338164b52c62ca706cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Topi=20J=C3=A4rvinen?= Date: Sun, 2 Aug 2026 22:22:04 +0300 Subject: [PATCH 1/3] fix: report the PR source as unavailable when gh pr list fails, never as empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit, Major, found on cs-toolkit's copy of this workflow rather than here โ€” which is the shared-workflow design paying for itself on its first day: an adopter converting its forked adapter to a pointer got the fork's reviewer aimed at the kit's text. The gather told you what to do when `gh pr list` TRUNCATES and said nothing about what to do when it FAILS. A non-zero exit, a partial response, or an absent `gh` all return nothing, and nothing is indistinguishable from a repo that genuinely has no open PRs. The first case renders an all-clear ๐Ÿ”ด bucket off a command that never ran โ€” a briefing that is confidently wrong rather than visibly incomplete, which is the same failure the truncation caveat two lines above exists to prevent. What makes it clearly a defect rather than a design choice: the TRACKER source in this same step already carries exactly this rule ("if the script/key fails, note the gap and continue โ€ฆ never act on a partial payload"). The two sources differ only in that one said so. The render template now has an explicit `PRs: unavailable ()` alternative so the gap has somewhere to appear. Deliberately narrow. This is not the search-route work: PR #244 tried to give the remediation check a route when no parameter-passing search tool exists, drew two HIGHs from both panel lenses, and was closed unmerged under a pre-declared bound (#245 carries the findings). This touches a different paragraph, a different failure mode, and nothing #245 covers. VERIFIED: `make test` 721 passed; `python scripts/kit_doctor.py` 32 unchanged, 0 differ, 0 missing. Neither executes this prose. The finding itself came from a reviewer reading it, and the fail-open it describes has not been reproduced live โ€” stated because "a failed gh pr list renders as all-clear" is a claim about agent behaviour I have not executed. --- docs/agentic-dev-kit/workflows/session-start.md | 9 ++++++++- kit-manifest.json | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/agentic-dev-kit/workflows/session-start.md b/docs/agentic-dev-kit/workflows/session-start.md index a89bf1b..8627e86 100644 --- a/docs/agentic-dev-kit/workflows/session-start.md +++ b/docs/agentic-dev-kit/workflows/session-start.md @@ -49,6 +49,13 @@ Fire these together โ€” they're independent: person opened; those are guarded out of `pr-watch` by your cron runner's job-name signal, so their bot findings get no automated follow-through and the next cockpit must adopt them โ€” see *Render the briefing*.) + + **If the command fails, report the PR source as unavailable โ€” never as empty.** + A non-zero exit, a partial response, or an absent `gh` returns nothing, and + nothing is indistinguishable from a repo that genuinely has no open PRs. The + first renders an all-clear ๐Ÿ”ด bucket off a command that never ran. This is the + same rule the tracker source below already states for itself; the two sources + differ only in that one said so. - your cron/CI health command (adapt to your infra) - your config-drift check, if you have one (parse its output for a ๐Ÿ”ด-worthy line in *Render the briefing*) - Read `` (focus: the **"Latest session"** block and its `Next:` / `Follow-ups:` lines, plus the top-of-file "Last updated" trail for the active sprint) @@ -222,7 +229,7 @@ something already classified ๐ŸŸก is later raised to ๐Ÿ”ด, it gets the check the ๐Ÿงญ Session Start โ€” Where things stand - โ€ข () ยท open PRs ยท CI/cron: + โ€ข () ยท open PRs | PRs: unavailable () ยท CI/cron: โ€ข Active sprint: โ€ข Last session: diff --git a/kit-manifest.json b/kit-manifest.json index a778faf..a6ad825 100644 --- a/kit-manifest.json +++ b/kit-manifest.json @@ -44,7 +44,7 @@ }, "docs/agentic-dev-kit/workflows/session-start.md": { "role": "workflow", - "sha256": "00cae6afe47b6817f92d012c6dcac4447a3e7114d403e7fae03891c35a01d3d6" + "sha256": "818c4a329693b5a84f18c1878eb61e7506b0ba304a4190e0639f8b4171477714" }, "docs/agentic-dev-kit/workflows/wrap-up.md": { "role": "workflow", From 3212ba4d7f639d9eb83bb50ffdf8899dde29adf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Topi=20J=C3=A4rvinen?= Date: Sun, 2 Aug 2026 22:39:11 +0300 Subject: [PATCH 2/3] fix: make the unavailable rule cover every gather source, and follow the file's own bracket convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Panel round 1 on this PR โ€” both lenses, no HIGH. Three findings, all acted on. 1. BOTH LENSES: the render template broke the file's own alternation convention. Every other either/or wraps BOTH sides in one bracket group (``, ``, ``). Mine put the `|` outside: ` open PRs | PRs: unavailable ()`. An agent following the template literally emits `0 open PRs | PRs: unavailable (gh: command not found)` โ€” a fabricated zero in front of the caveat, which recreates the exact fail-open the paragraph exists to close. Now ``. Verified: `grep -n '<[^<>]*|[^<>]*>'` returns every alternation in the file and all of them are fully wrapped; no bare `|` survives outside a bracket. 2. BOTH LENSES, and the correctness one found the sharper version: my consistency argument was selective. I claimed the PR and tracker sources "differ only in that one said so" โ€” while the CI/cron field IMMEDIATELY TO THE RIGHT in the same rendered line carries the identical fail-open with no handling at all. A cron health command that never ran renders as `all green`. So the rule is not a PR-source rule. It is now stated once for the whole gather, and CI/cron gets the `unavailable: reason` alternative it lacked. This is the same rule applied at its correct scope, not a new mechanism โ€” the finding was that my scope was wrong, and narrowing the claim instead would have left a known fail-open in the field next to the one I was fixing. 3. ADVERSARIAL: "a partial response returns nothing" was wrong. A truncated but parseable response returns FEWER rows, not none โ€” no exit code reveals it, and it is the adjacent full-page check's concern, not this one's. The two failure shapes are now distinguished explicitly instead of being collapsed. WHAT THE LENSES ALSO ESTABLISHED, worth carrying: both mutation-tested this change in isolated copies and both got `720 passed, 1 deselected` with the mutation SURVIVING. One reverted the whole paragraph, the other inverted its opening sentence to say the opposite. Nothing behavioural caught either. This file has no test coverage of its prose meaning at all, so the panel is the only check it gets โ€” which is the argument for having run one on a nine-line diff. VERIFIED: `make test` 721 passed; `python scripts/kit_doctor.py` 32 unchanged, 0 differ, 0 missing. --- .../workflows/session-start.md | 22 ++++++++++++------- kit-manifest.json | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/agentic-dev-kit/workflows/session-start.md b/docs/agentic-dev-kit/workflows/session-start.md index 8627e86..9509b3e 100644 --- a/docs/agentic-dev-kit/workflows/session-start.md +++ b/docs/agentic-dev-kit/workflows/session-start.md @@ -35,7 +35,15 @@ Read `config/dev-model.yaml` first. In this workflow: ### 0 ยท Gather (run in parallel) -Fire these together โ€” they're independent: +Fire these together โ€” they're independent. + +**A source that fails is reported as unavailable, never as its empty value.** A +non-zero exit, a missing binary, or an absent credential returns nothing โ€” and +nothing is indistinguishable from a genuine zero: no open PRs, no failing jobs, no +drift. Rendering the empty value turns a command that never ran into an all-clear, +which is worse than a visible gap because nothing on the briefing says to look +again. This applies to every source below; the tracker bullet states it for itself +only because it was written first, not because it is the only one it covers. - `git status --short` and `git branch --show-current` - `gh pr list --state open --json number,title,isDraft,reviewDecision,statusCheckRollup,author --limit 100` @@ -50,12 +58,10 @@ Fire these together โ€” they're independent: signal, so their bot findings get no automated follow-through and the next cockpit must adopt them โ€” see *Render the briefing*.) - **If the command fails, report the PR source as unavailable โ€” never as empty.** - A non-zero exit, a partial response, or an absent `gh` returns nothing, and - nothing is indistinguishable from a repo that genuinely has no open PRs. The - first renders an all-clear ๐Ÿ”ด bucket off a command that never ran. This is the - same rule the tracker source below already states for itself; the two sources - differ only in that one said so. + Note the two failure shapes are different and only one is covered above: a + **failed** `gh pr list` returns nothing and is caught by the unavailable rule; a + **truncated** one returns valid JSON with fewer rows than exist, which no exit + code reveals and only the full-page check catches. - your cron/CI health command (adapt to your infra) - your config-drift check, if you have one (parse its output for a ๐Ÿ”ด-worthy line in *Render the briefing*) - Read `` (focus: the **"Latest session"** block and its `Next:` / `Follow-ups:` lines, plus the top-of-file "Last updated" trail for the active sprint) @@ -229,7 +235,7 @@ something already classified ๐ŸŸก is later raised to ๐Ÿ”ด, it gets the check the ๐Ÿงญ Session Start โ€” Where things stand - โ€ข () ยท open PRs | PRs: unavailable () ยท CI/cron: + โ€ข () ยท ยท CI/cron: โ€ข Active sprint: โ€ข Last session: diff --git a/kit-manifest.json b/kit-manifest.json index a6ad825..3bb7422 100644 --- a/kit-manifest.json +++ b/kit-manifest.json @@ -44,7 +44,7 @@ }, "docs/agentic-dev-kit/workflows/session-start.md": { "role": "workflow", - "sha256": "818c4a329693b5a84f18c1878eb61e7506b0ba304a4190e0639f8b4171477714" + "sha256": "04ffcc718b979bfedaa480f1914a92203f0c232ba9e9ff6ac7d5b5b0712dccf0" }, "docs/agentic-dev-kit/workflows/wrap-up.md": { "role": "workflow", From 271fdbf8d32c17949208d1dbace8d91154e632af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Topi=20J=C3=A4rvinen?= Date: Sun, 2 Aug 2026 22:51:11 +0300 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20make=20the=20widened=20claim=20true?= =?UTF-8?q?=20of=20every=20source=20it=20names=20=E2=80=94=20config-drift?= =?UTF-8?q?=20render=20slot,=20and=20an=20accurate=20enumeration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delta pass, one MEDIUM regression, no HIGH. Declared before this round: it is the last fix round on this PR; anything surviving is logged rather than patched again. THE FINDING. Round 1's widened preamble claimed the rule "applies to every source below" and named "no drift" among its examples โ€” while the config-drift render note was byte-identical to base and still binary: the line "only appears when your drift check reports something outstanding". So a drift check that could not run rendered exactly like one that found nothing. The paragraph named the failure shape it left unfixed, which is round 1's own finding recurring one level up: widening the claim created coverage I had not operationalised. Fixed by giving config-drift the slot the other two already had, and by replacing "every source below" with an enumeration that is checkable. AND THE ENUMERATION WAS WRONG ON ITS FIRST DRAFT โ€” caught by verifying it rather than by a reviewer. The replacement sentence said all four named sources "each have a slot in Render the briefing". The tracker does not; it carries the rule inline and reports its gap in prose. Grepping for a slot per named source returned nothing for the tracker, before push. That is the third overclaim in three rounds on this paragraph, and the only one caught by its author. Every claim the paragraph now makes was re-checked mechanically: PR list has a render slot 1 CI/cron has a render slot 1 config-drift has a render slot 1 tracker states it inline 1 file reads excluded, with why 1 Also from the delta pass, NOT fixed and logged instead, per the declared bound: `` puts its label inside the alternation while `CI/cron: ` puts it outside. Both render sensibly; it is template-authoring inconsistency, not a defect, and a third round to restyle it would cost more than it returns. WHAT THREE ROUNDS ESTABLISHED ABOUT THIS FILE. All three lenses mutation-tested it independently and all three got the mutation SURVIVING at `720 passed, 1 deselected` โ€” reverting the paragraph, inverting its opening sentence, and restoring the old render line respectively. There is no behavioural coverage of this document's meaning. The panel is the only check it gets, and on a change this size it found a real defect in every round. VERIFIED: `make test` 721 passed; `python scripts/kit_doctor.py` 32 unchanged, 0 differ, 0 missing. --- docs/agentic-dev-kit/workflows/session-start.md | 15 ++++++++++++--- kit-manifest.json | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/agentic-dev-kit/workflows/session-start.md b/docs/agentic-dev-kit/workflows/session-start.md index 9509b3e..249c05a 100644 --- a/docs/agentic-dev-kit/workflows/session-start.md +++ b/docs/agentic-dev-kit/workflows/session-start.md @@ -42,8 +42,14 @@ non-zero exit, a missing binary, or an absent credential returns nothing โ€” and nothing is indistinguishable from a genuine zero: no open PRs, no failing jobs, no drift. Rendering the empty value turns a command that never ran into an all-clear, which is worse than a visible gap because nothing on the briefing says to look -again. This applies to every source below; the tracker bullet states it for itself -only because it was written first, not because it is the only one it covers. +again. + +This governs every source whose failure can pass for a benign zero. The PR list, +your cron/CI health command and your config-drift check each have a slot in +*Render the briefing* for saying so; the tracker bullet carries the rule inline +instead, and reports its gap in the briefing text rather than in a fixed field. +The two narrative-file reads are not in this set: a failed read there does not look +like good news, it looks like a missing handoff. - `git status --short` and `git branch --show-current` - `gh pr list --state open --json number,title,isDraft,reviewDecision,statusCheckRollup,author --limit 100` @@ -255,7 +261,10 @@ What to do next this week; see ๐ŸŸข Whenever for backlog.` - Order items within a bucket by leverage (blocking > high-value > cheap-win). - The config-drift line only appears when your drift check reports something - outstanding; name the affected items. A less-urgent "orphan" class of drift (config + outstanding; name the affected items. **If the check could not run, say so where + that line would go** โ€” "config drift: unavailable (``)". Silence here + otherwise means "nothing outstanding", and a check that never ran would claim it. + A less-urgent "orphan" class of drift (config present with nothing applying it, or vice versa) is a separate, lower-urgency concern โ€” mention it only under ๐ŸŸข Whenever if present, never conflated with the ๐Ÿ”ด line above. diff --git a/kit-manifest.json b/kit-manifest.json index 3bb7422..26716e7 100644 --- a/kit-manifest.json +++ b/kit-manifest.json @@ -44,7 +44,7 @@ }, "docs/agentic-dev-kit/workflows/session-start.md": { "role": "workflow", - "sha256": "04ffcc718b979bfedaa480f1914a92203f0c232ba9e9ff6ac7d5b5b0712dccf0" + "sha256": "491df1e12fa7f01cd1bd7dd27860413f5c42cf1c135dc5afa9941d5ef4ecdb2c" }, "docs/agentic-dev-kit/workflows/wrap-up.md": { "role": "workflow",