Skip to content

fix(doctor): cover triage's homing prerequisites, and tell a failed read from an absent one (#4300) - #4337

Merged
usirin merged 1 commit into
mainfrom
umut-sirin/doctor-vocabulary-milestone-preflight-4843154D
Jul 27, 2026
Merged

fix(doctor): cover triage's homing prerequisites, and tell a failed read from an absent one (#4300)#4337
usirin merged 1 commit into
mainfrom
umut-sirin/doctor-vocabulary-milestone-preflight-4843154D

Conversation

@usirin

@usirin usirin commented Jul 26, 2026

Copy link
Copy Markdown
Member

Fixes #4300

doctor greened a repo where triage had no non-kill home for any issue. Two causes, and the second is the one worth reading: the required-label list was narrower than what the guards consume, and the check that read it could not tell a failed read from a genuine absence — so a checker passed while the thing it checks was unknown.

What changed

1. doctor.sh check 1c — the label table is now a presentation mirror, not a second source.
The required set is single-sourced in packages/pipeline-cli/src/tools/vocabulary-preflight/vocabulary.ts (#4272, landed), which assembles it from the constants the guards themselves scope on. doctor.sh's table only adds the colour + description a gh label create needs. Rows gained a TIER column: tier 1 fails the run, tier 3 only ever WARNs.

Tier-1 rows added: wayfinder:backlog, axis:pipeline-hardening (the two labels that make triage's standing-lane exemption reachable) and area:infra (the platform discriminator lane scopes on). wayfinder:map is a tier-3 row — it is the wayfinder chart front door, an ideation surface, not a first-run prerequisite.

2. New check 1d — the mirror cannot silently fall behind the source.
doctor.sh reads the source through a new pipeline-cli vocabulary-preflight labels verb (the only seam a bash preflight has onto a TS constant) and reds if its table no longer covers it. This is the check that would have caught the original bug: with wayfinder:backlog removed from the table, 1c still reports ✓ all 17 required pipeline labels exist and 1d reports ✗ … DRIFTED … absent from the table above: wayfinder:backlog.

3. Every check reports THREE states, never two.
This is the point of the fix, not a side effect. 1c previously captured gh api … 2>/dev/null into a string and branched on emptiness, so a 403 and a genuinely label-less repo were the same value — and the message picked one ("could not read repo labels") for both. Now the read's outcome is captured separately from its content:

1c labels 1d vocabulary source 3d open milestone
present ✓ all N required pipeline labels exist ✓ … covers all N labels of the shared vocabulary ✓ N open milestone(s)
absent ✗ N of M required … absent + create commands ✗ … has DRIFTED … absent from the table above: … ⚠ no open milestone — triage can exempt … but cannot home one into an arc
undetermined ✗ … UNDETERMINED — the label read on <repo> FAILED (unknown, NOT absent) ⚠ … UNVERIFIED against the shared vocabulary (unknown, NOT confirmed) ⚠ … UNDETERMINED — the read did not succeed (unknown, NOT 'no milestone')

A failed read never resolves to "fine", and never scores absence off a value it never obtained.

4. Open-milestone existence is a Tier-3 WARN (3d), never a Tier-1 fail.
Triage homes an issue into an existing open milestone and is forbidden from creating one (ADR 0072 §3), so a freshly-adopted repo legitimately has none — reddening on that would fail the correct state of a brand-new adopter. The WARN names the consequence: triage can exempt to a standing lane but cannot home into an arc/campaign.

5. The hardcoded 15 is gone — the count is derived from the table (all 18 required pipeline labels exist today).

The label auto-create question, settled by observation

#4268 flagged as explicitly unverified whether POST /repos/{owner}/{repo}/issues/{n}/labels auto-creates a missing label. doctor.sh's header rested on the assertion that it does not. It does. Measured 2026-07-26 against this repo: POSTing a label name that returned 404 from GET /labels/{name} succeeded with HTTP 200 and materialized the label repo-wide at GitHub's default grey ededed with a null description. (The probe label was removed from the issue and deleted repo-wide; GET re-confirms 404.)

Corroborating trace: p3, area:infra, and axis:a11y in this repo all carry exactly that signature — color=ededed, description=null — the fingerprint of labels minted by a write rather than created deliberately.

So the stated rationale for Tier 1 was false, and the header now says the true thing: report silently succeeds and mints an off-taxonomy label, and the damage lands on the read side, where ?labels=status:triaged and every guard's label scoping match nothing and the pipeline runs protecting nothing. That is a stronger reason for Tier 1 than the one it replaces, so the check keeps its tier — the design is safe under either answer, and the answer is now recorded rather than assumed.

Verification

Four states exercised by running the script, not by argument:

  • Real repo — exit 0, ✓ all 18 required pipeline labels exist, ✓ … covers all 16 labels of the shared vocabulary, ✓ 14 open milestone(s).
  • Stubbed fresh repo, both standing-lane labels absent, no milestone (AC6) — exit 1, ✗ 2 of 18 required pipeline label(s) absent naming wayfinder:backlog and axis:pipeline-hardening each with its create command, plus the wayfinder:map and no-milestone WARNs.
  • Stubbed label read fails (403)✗ required labels UNDETERMINED … (unknown, NOT absent), exit 1, and zero labels reported absent.
  • Vocabulary source unresolvable (script run detached from the plugin tree) — ⚠ … UNVERIFIED … (unknown, NOT confirmed), every other check unaffected.
  • Drift path — with a tier-1 row removed, 1c still greens and 1d reds by name.

Checks: pnpm typecheck clean; pnpm lint:worktree clean (3 files); pipeline-cli suite 177 files / 2794 tests passing, including core-import-closure.unit.test.ts (ADR 0218 — the new subcommand is reached only through registry.ts's pruned fan-out edge and adds no core import); gh-phoenix lint-skills clean on both edited skill files; shellcheck clean on the new code (one pre-existing SC2043 on an untouched line); script re-run under /bin/bash 3.2 (the macOS default) since the heredoc parsing note in the file depends on it.

Deviations / scope left out

  1. The shared vocabulary was not widened. REQUIRED_LABELS (16) and doctor's tier-1 set (18) are not equal in either direction: doctor additionally requires status:planning and status:awaiting-release, which no guard scopes on but plan-epic and ship-it write. Rather than edit Pipeline label vocabulary + roadmap table + §CP path are hardcoded with no config seam #4272's landed set, 1d asserts only the direction that matters — doctor's set must cover the shared one. Doctor being a deliberate superset is recorded in the file.
  2. 1d degrades to a WARN when the CLI cannot be resolved, rather than failing Tier 1. Doctor's own Tier 3 treats @kampus/pipeline-cli resolving as optional, so making Tier 1 hard-depend on it would contradict the tier design for the exact fresh-repo adopter doctor serves. The honest report is "unverified", not a silent pass and not a false red.
  3. ship-it's enqueue needs repo auto-merge + a queue ruleset no fresh repo has #4303 (repo allow_auto_merge + merge-queue ruleset) is untouched — same file, different proposition and API surface, independently pickable per triage note 4.
  4. (rebase round 1, 2026-07-26) Supersedes item 3's status, not its reasoning: ship-it's enqueue needs repo auto-merge + a queue ruleset no fresh repo has #4303 landed as PR feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346 while this branch waited, so this head is now rebased on top of it and carries both changes in doctor.sh / doctor/SKILL.md. This PR still authors none of ship-it's enqueue needs repo auto-merge + a queue ruleset no fresh repo has #4303's checks — feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's 2c/2d blocks are byte-identical here (72 lines, verified by diff against origin/main).
  5. (rebase round 1) claude-plugins/kampus-pipeline/README.md is now in scope — one file more than the pre-rebase head. feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346 left the README's two the 15 required labels phrasings standing; this PR is what widens the required set to 18, so that prose went stale as a direct consequence of this diff and is corrected here rather than deferred. Both sites are now count-free (a hardcoded count is the thing that goes stale; doctor.sh derives the number at runtime). The same edit also drops the README's copy of the falsified "a first run that fails deep inside a gh api call" claim, which this PR measured and removed from doctor.sh and doctor/SKILL.md — leaving the third copy would have shipped the PR contradicting itself.
  6. (rebase round 1) Two conflict hunks in doctor/SKILL.md were resolved semantically, keeping both sides: (a) the "load-bearing pair" paragraph — this PR's corrected wording (which deletes the falsified round-trips-into-a-raw-API-error clause) is kept plus feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's repo-admin-governance-pair paragraph, and feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's Tier-2 pairTier-2 checks rewording is kept because Tier 2 now holds four checks; (b) the Conventions bullet — feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's new An unreadable state is UNKNOWN bullet is kept alongside this PR's LABELS table is a presentation mirror bullet, which replaced the older canonical-set bullet the two sides fought over.

Rebase (2026-07-26)

Rebased c7220a75f176c618 onto origin/main at ce581d3c, which now contains #4346 (merged 23:40:56Z). Three conflict hunks, all in the two shared doctor/ files; the three vocabulary-preflight files applied clean. Re-verified against the rebased head, not inherited from the pre-rebase run: pnpm typecheck clean, pnpm lint clean, @kampus/pipeline-cli 177 files / 2805 tests passing, doctor.sh run live (exit 0, all four of this PR's checks and both of #4346's green), and the stubbed-403 label read re-reproduced — ✗ required labels UNDETERMINED … (unknown, NOT absent), exit 1, zero labels reported absent.

Per ADR 0058 the head moved, so this PR carries no bound verdict — it was deliberately rebased before review so the review binds the head that ships.

§CP

This PR is control-plane: claude-plugins/kampus-pipeline/skills/doctor/doctor.sh matches the ^claude-plugins/kampus-pipeline/skills/([^/]+/)*[^/]+\.sh$ clause of CONTROL_PLANE_RE as re-resolved from origin/main. It is human-merged and takes a review-skill verdict. The packages/pipeline-cli/src/tools/vocabulary-preflight/** files are not §CP on their own; the .sh is what carries it.

@usirin
usirin requested a review from a team as a code owner July 26, 2026 22:45
@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown

No preview deploy

  • No preview deploy for this PR — its diff touches no deploy-relevant path, so no preview stack was minted and e2e is not applicable. (f176c61)
  • web — Stage pr-4337 torn down.

notusirin
notusirin previously approved these changes Jul 27, 2026
@usirin
usirin force-pushed the umut-sirin/doctor-vocabulary-milestone-preflight-4843154D branch from c7220a7 to f176c61 Compare July 27, 2026 01:15
@usirin

usirin commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

review-skill: advisory — blocking-set PR (manual merge)

PR #4337 touches the control plane — claude-plugins/kampus-pipeline/skills/doctor/doctor.sh
matches the .sh-at-any-depth clause of CONTROL_PLANE_RE as re-resolved live from
origin/main (cp-classifycontrol-plane, exit 0, path-match — not the stale
pre-#4255 exit 1). My verdict is advisory only: it does not authorize a merge.
Under the §CP hard gate (ADR 0135), a @kamp-us/control-plane member approves this at its
current head and ship-it then enqueues it (ADR 0048 single merge authority).

Reviewed-head: @ f176c61

Verified against #4300's acceptance criteria + the skill-rigor checklist — all checks pass.
Every claim below was re-derived at this head, not taken from the PR body.

Acceptance criteria

  • [PASS] AC1 — 1c includes both standing lanes, each with a create-command fix line. wayfinder:backlog and axis:pipeline-hardening are tier-1 rows in the LABELS heredoc. Reproduced live against a stubbed label read that omits them: ✗ 2 of 18 required pipeline label(s) absent, each with its full gh label create line.
  • [PASS] AC2 — wayfinder:map is covered at the wayfinder tier, not excluded. It is a tier-3 row surfaced by new check 3c; the SKILL.md tier table gains the matching Tier-3 row ("an ideation front door, not a first-run prerequisite"). Live: ⚠ 1 ideation-layer label(s) absent — the wayfinder map surface degrades + create command.
  • [PASS] AC3 — open-milestone existence is a Tier-3 WARN, never a Tier-1 fail, and names the consequence. Check 3d; live against a stubbed 0-milestone read: ⚠ no open milestone — triage can exempt an issue to a standing lane, but cannot home one into an arc/campaign. Confirmed non-blocking: the verdict line counted 1 blocking failure (the label check alone), so the WARN did not contribute to fails.
  • [PASS] AC4 — the hardcoded 15 is gone and the count is derived from the table. Live prints all 18 required pipeline labels exist. Derivation proven, not assumed: with one tier-1 row deleted the same line printed all 17. Repo-wide sweep for the old count phrasings returns zero hits across the whole tree.
  • [PASS] AC5 — doctor consumes the shared vocabulary rather than minting a third list. A new pipeline-cli vocabulary-preflight labels verb plus new check 1d assert doctor's tier-1 set covers the 16-label source in packages/pipeline-cli/src/tools/vocabulary-preflight/vocabulary.ts. Live: ✓ doctor's required set covers all 16 labels of the shared vocabulary. The guard is reachable and fires — with wayfinder:backlog removed from the table, 1c still greens (all 17 …) while 1d reds by name (… has DRIFTED … absent from the table above: wayfinder:backlog) and the run exits 1. Pointers to the source are carried in the 1c comment and the SKILL.md Conventions bullet.
  • [PASS] AC6 — verified by running against a stubbed repo missing the two standing lanes: exit 1, and it names them. Reproduced independently, not read from the transcript.

Skill rigor

  • [PASS] Behavioral correctness — the three-state contract is implemented by separating the read's outcome (labels_read = no-repo/failed/ok) from its content (EXISTING), with the || continue guard placed after the required_total increment, so the total stays correct on a failed read while absence is never scored. The LABELS loop is fed by a heredoc, not a pipe — load-bearing, since a pipe would run the loop in a subshell and lose every counter; verified under /bin/bash 3.2 (the macOS default), which counted 18 correctly. All three states were reproduced live at this head, and the base defect they fix was reproduced too: against the identical 403 stub, origin/main's doctor.sh reports all 15 labels absent with 15 bogus gh label create commands against a repo that already has them, while this head reports ✗ required labels UNDETERMINED — the label read on kamp-us/phoenix FAILED (unknown, NOT absent…), exit 1, and zero labels absent. Tier-3 3c cascades off the same flag.
  • [PASS] Trigger / description quality — the frontmatter is untouched (the SKILL.md change starts at body line 12). The description never named a label count, so widening the set does not stale it; no trigger surface changed, so no new shadowing is introduced. gh-phoenix lint-skills clean on both edited files.
  • [PASS] Cross-skill conflict / shadowing — the change removes a contradiction rather than adding one: the Conventions bullet that declared doctor.sh "the canonical set" is replaced by one naming vocabulary.ts as the source with doctor.sh as a presentation mirror, matching what 1d now enforces. The CLI seam is purely additive — adding the labels subcommand leaves check untouched.
  • [PASS] Gate-invariant preservation — no gate skill is in this change's reach: ship-it, review-code/review-doc/review-skill/review-plan and gh-issue-intake-formats.md are untouched. Within doctor the change strengthens fail-closed behavior (ADR 0092): it adds a failure count on the previously-unhandled no-repo state, and replaces a false-absence with an honest UNDETERMINED that still exits non-zero. Nothing softened.
  • [PASS] deviation-disclosure (§DEV) — the body carries a ## Deviations / scope left out section with six numbered items, including all three rebase-round disclosures. Nothing this gate found is undisclosed.

Rebase verification — the three conflict hunks

The rebase is genuine and linear: the head's sole parent is ce581d3c, which sits 3 commits above #4346 (03860001). The change set is therefore computed against a base that already contains #4346, so every #4346 line appearing as unchanged context is preserved by construction. Each hunk was checked independently anyway:

  1. doctor.sh header tier block — both sides present. fix(doctor): cover triage's homing prerequisites, and tell a failed read from an absent one (#4300) #4337's rewritten Tier-1 and Tier-3 lines and its two new paragraphs are there; feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's Tier-2 line (the merge-queue governance ship-it's enqueue silently depends on) survives verbatim as context. I re-ran the coder's comparison independently: extracted the 2c/2d block from ce581d3c and from the head and compared them — identical, 71 lines, comparison exit 0. (The body says 72; the true count is 71 — an off-by-one in the disclosure, immaterial to the identity claim.) Both of feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's checks run green in the live run.
  2. doctor/SKILL.md "load-bearing pair" paragraph — both sides present. fix(doctor): cover triage's homing prerequisites, and tell a failed read from an absent one (#4300) #4337's corrected sentence stands and the falsified "the very first reporttriage round trips into a raw GitHub API error" clause stays deleted (repo-wide sweep confirms zero occurrences). feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's repo-admin-governance paragraph follows verbatim, and its Tier-2 pairTier-2 checks rewording is retained — correct, since Tier 2 now holds four checks.
  3. Conventions bullets — the judgment call, and I agree with it. feat(doctor): preflight the two merge-queue governance preconditions ship-it needs (#4303) #4346's An unreadable state is UNKNOWN, never the negative answer bullet and fix(doctor): cover triage's homing prerequisites, and tell a failed read from an absent one (#4300) #4337's LABELS table is a presentation mirror bullet are both present; a mechanical resolution would have dropped one. On the deliberate non-collapse of the residual overlap with this PR's new three-states paragraph: keeping both is right. They are not duplicates at the same level — the body paragraph describes the reporting model an adopter reads off the checklist output, while the Conventions bullet is maintainer-facing and states the mechanism (keep gh's exit status, never apply --jq to an error body, admit only the literal values expected) with its §ZS / ADR 0092 / ship-it's §CP approval gate resolves head, author, and roster with unguarded reads #4223 citations. Collapsing them would lose either the reader-facing model or the maintainer-facing rule.

The falsified claim, and the stale count

  • The falsified claim is not re-introduced anywhere. Swept the entire head tree, not just the plugin, for the "fails deep inside a gh api call" phrasing, the "round trips into a raw GitHub API error" phrasing, and the old count phrasings — zero hits in all three.
  • The count-free README fix is the right call. Re-pinning to 18 would have recreated the exact defect this PR exists to kill, one surface over: doctor.sh derives the number at runtime, so a prose copy is a second source that goes stale on the next vocabulary change. The second site also gained precision without a number ("plus the standing lanes and the platform discriminator triage homes into"). The scope expansion to a 6th file is legitimate and correctly disclosed (Deviation 5) — the staleness is a direct consequence of this change widening 15 to 18, and the same edit drops the README's third copy of the falsified claim, without which the PR would have shipped contradicting itself.

Claimed verification, spot-checked at this head

Re-ran rather than assumed: doctor.sh live → exit 0, with all four of this PR's checks and both of #4346's green; tsgo -p tsconfig.json → clean; biome check on the changed TS → clean; the @kampus/pipeline-cli suite → 177 files / 2805 tests, all passing, matching the body exactly. shellcheck -x shows only the one pre-existing SC2043, confirmed present in ce581d3c on an untouched line.

Read-failure note — this gate's own artifact, not a PR defect. My first full-suite run showed 3 adoption-lint failures. They were caused entirely by this gate's mandated config-pin isolation, which deletes .claude from the isolated review tree; those tests read .claude/workflows/drive-issue.js. Proven rather than assumed: the file exists at this head (blob 5c0bffff), the base-to-head delta restricted to .claude/ is empty, and restoring only that one file turned adoption-lint 17/17 green and the full suite to 2805/2805. Recorded here so it is not mistaken for a PR defect later.

One non-blocking observation (out of scope for #4300 — the PR is not blocked by it)

doctor.sh's Tier-1 section header still prints Tier 1 — load-bearing (first run fails without these). Under this PR's own corrected model a missing label does not fail the first run — it silently mints an off-taxonomy label. The line is pre-existing and untouched here, and it is defensible as a compressed tier label (it is literally true for the auth half), so this is neither a re-introduction nor a gate failure. But by the same reasoning the body applies to the README in Deviation 5, it is arguably a fourth copy of the retired framing sitting in the most-read surface of all: the script's own output. It does not trace to #4300's stated goal (a narrow required-set / homing gap), so per ADR 0079 it routes out-of-scope rather than becoming an acceptance criterion.


All six acceptance criteria and all five rigor checks pass. This advisory authorizes no merge.
As a §CP PR it needs a @kamp-us/control-plane approval at
f176c6188d90ee0b7fb770a4e1c36a256b3975de before ship-it can enqueue it, and the head must
not move first or this verdict unbinds.

Verdict-written: 2026-07-27T01:37:48Z

@usirin

usirin commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

review-code: advisory — blocking-set PR (manual merge)

PR #4337 is control-plane: claude-plugins/kampus-pipeline/skills/doctor/doctor.sh matches
the .sh-at-any-depth clause of CONTROL_PLANE_RE as re-resolved live from origin/main
(cp-classifycontrol-plane, exit 0, path-match — not the stale pre-#4255 exit 1).
The three packages/pipeline-cli/src/tools/vocabulary-preflight/** files reviewed here are not
§CP on their own, but §CP is a property of the PR, so this verdict is advisory only: it does
not authorize a merge. A @kamp-us/control-plane member approves at head and ship-it
enqueues (ADR 0135 / ADR 0048).

Reviewed-head: @ f176c61

This is the code half of a mixed code + skill PR; the skill half carries its own
review-skill advisory at this same head, posted separately. Code surface under review:

  • packages/pipeline-cli/src/tools/vocabulary-preflight/command.ts (+18/-2)
  • packages/pipeline-cli/src/tools/vocabulary-preflight/vocabulary.ts (+8/-0)
  • packages/pipeline-cli/src/tools/vocabulary-preflight/vocabulary.unit.test.ts (+16/-0)

Acceptance criteria (the code half's contribution)

  • [PASS] AC5 — this is the criterion the code half exists to satisfy: doctor must consume Pipeline label vocabulary + roadmap table + §CP path are hardcoded with no config seam #4272's landed vocabulary rather than mint a third list. renderLabelList is added to vocabulary.ts as a pure exported function over REQUIRED_LABELS, and command.ts exposes it as a new labels subcommand. Exercised live at this head: pipeline-cli vocabulary-preflight labels prints exactly 16 labels, one per line, including wayfinder:backlog, axis:pipeline-hardening and area:infra. That is the seam doctor.sh's new 1d check reads, and I confirmed 1d both greens on a covering table and reds by name on a drifted one.
  • [PASS] AC1 / AC2 / AC3 / AC4 / AC6 — satisfied on the skill surface (doctor.sh), verified in the review-skill advisory at this head. No code-half regression touches them; the code half adds a read-only print verb and changes no existing behavior.

Code hygiene / correctness

  • [PASS] Typecheck — tsgo -p tsconfig.json on @kampus/pipeline-cli at this head: clean, no output.
  • [PASS] Lint — biome check over the changed directory: clean, 6 files, no fixes applied.
  • [PASS] Tests — full @kampus/pipeline-cli suite at this head: 177 files / 2805 tests, all passing, exactly matching the PR body's claim. The vocabulary-preflight file alone is 18/18.
  • [PASS] New behavior is covered by new tests, and they are meaningful rather than tautological. Two were added: one pins the render contract a while read consumer depends on (one label per line and nothing else), the other is a vacuous-scope guard in the ADR 0092 shape — it asserts the list is non-empty and contains the standing lanes, so an empty render can never let doctor's drift check pass against nothing. That second test is the one that matters: without it, 1d would silently degrade to a no-op if the source list ever emptied.
  • [PASS] Effect idiom — the new labels subcommand mirrors the existing check shape exactly (Command.make with an empty flag record, an Effect.fn body, Command.withDescription, registered through Command.withSubcommands). Console is added to the existing effect import rather than a second import site. No new dependency, so no catalog: implication.
  • [PASS] Import-closure discipline (ADR 0218) — core-import-closure.unit.test.ts passes in the run above: the new subcommand is reached only through the registry's pruned fan-out edge and pulls nothing new into the core.
  • [PASS] Comments earn their place — the one docblock added to vocabulary.ts states why the seam exists (a bash preflight cannot import a TS constant, so without it the set would have to be retyped, which is the parallel hand-written list that drifted) rather than restating the one-line join. That is a load-bearing note at its enforcement site.
  • [PASS] Surface is minimal and additive — withSubcommands([check, labels]) leaves check and its exit-code contract untouched; the new verb reads no repo state, which is what lets it answer in the very repo whose labels are missing. No existing export or signature changed.
  • [PASS] deviation-disclosure (§DEV) — the body's ## Deviations / scope left out discloses the relevant code-half judgment (Deviation 1: the shared vocabulary was deliberately not widened; doctor's 18 is a superset of the shared 16 by status:planning + status:awaiting-release, which plan-epic/ship-it write but no guard scopes on, so 1d asserts only the covering direction). I verified that direction is the one implemented and that the arithmetic holds: 18 = 16 + 2. Nothing undisclosed that this gate could see.

All checks pass on the code half. This advisory authorizes no merge. As a §CP PR it needs a
@kamp-us/control-plane approval at f176c6188d90ee0b7fb770a4e1c36a256b3975de before ship-it
can enqueue it, and the head must not move first or this verdict unbinds.

Verdict-written: 2026-07-27T01:38:41Z

@usirin
usirin requested a review from a team July 27, 2026 01:40
@usirin

usirin commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

Handoff — PASSED and banked, awaiting a control-plane approval

Engine instance 98177c03 (session fcd74bd3-…) is winding down under a founder-directed stop. This lane is complete on the engine side; nothing is in flight against it.

State: all 6 ACs and all 5 rigor checks PASS at head f176c6188d90ee0b7fb770a4e1c36a256b3975de, across both required namespaces (review-code, review-skill). §CP control-plane, exit 0 (path-match on doctor/doctor.sh). Assigned to the control-plane approver with a team review requested.

Next step, and the only one: a @kamp-us/control-plane approval at f176c618, then the approval-aware shipper enqueues. No code change is owed.

Do not rebase or push to this branch. Any head movement unbinds both verdicts (ADR 0058) and would cost a full re-review. Three human approvals were destroyed that way earlier today.

Why the rebase was safe, for whoever needs to trust it

This PR was deliberately held behind #4346 (both touch doctor/SKILL.md and doctor/doctor.sh), then rebased onto it — so the merge was semantic, not mechanical. The structural proof: the head's sole parent is ce581d3c, which already contains #4346, so every #4346 line showing as context is preserved by construction. The 2c/2d block was independently re-extracted from origin/main and from the resolved file and diffed — identical.

The hunk worth knowing about: #4346 added an "unreadable state is UNKNOWN, never the negative answer" bullet while this PR replaced an adjacent one. A mechanical resolution would have silently dropped one. Both were kept, deliberately uncollapsed — the body paragraph is the adopter-facing reporting model, the Conventions bullet is maintainer-facing mechanism with its own citations. Collapsing loses one audience.

Base defect reproduced, not argued: against a gh stub that 403s only the label read, origin/main's script reports all 15 labels absent and emits 15 bogus create commands against a repo that already has them. At this head the same stub yields UNDETERMINED … (unknown, NOT absent) with zero labels reported absent.

One non-blocking observation, deliberately NOT fixed here

doctor.sh still prints Tier 1 — load-bearing (first run fails without these). Under this PR's own corrected model a missing label does not fail the first run. It is pre-existing and untouched, and defensible for the auth half — but by the same reasoning this PR used for the README, it is arguably a fourth copy of the retired framing in the most-read surface of all: the script's own output. It does not trace to #4300's goal, so ADR 0079 routes it out-of-scope. Worth a follow-up issue; none was filed (the reviewer lane is verify-and-verdict, and the engine is under a no-new-work stop).

Marker hygiene: do not hand-edit, PATCH, or delete any verdict marker here. verdict post keys on (gate, run, head); head-first resolution drops non-head markers on its own.

@usirin
usirin added this pull request to the merge queue Jul 27, 2026
Merged via the queue into main with commit 6dcfc22 Jul 27, 2026
45 checks passed
@usirin
usirin deleted the umut-sirin/doctor-vocabulary-milestone-preflight-4843154D branch July 27, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

doctor's required-label set is narrower than what triage needs to home an issue

3 participants