[US-278] feat: bootstrap quick mode — a second resolution depth, guided stays the default - #408
Conversation
- 25 RED tests over dataset/.skills/process/bootstrap/** + root mirror - Cover selector/$mode + guided declared default (AC1/AC2) - Cover composition of the Guided/Quick Setup Convention, no bespoke resolution (AC3) - Cover per-decision defaultability doc, adoption-file sameness (AC4), edge cases - Cover guided-path anchors (no regression), mirror equality, timed CP + docs - Task: T1 — identify defaultable vs still-asked bootstrap decisions (RED) Refs: #278
- $mode selector, guided declared default, absent => guided unchanged (AC1/AC2) - composes the Guided/Quick Setup Convention cascade, no bespoke order (AC3) - quick-mode-defaults.md: per-decision defaultability + still-asked (PM tool, undetectable stack) - same adoption files/format as guided (AC4); no-TTY safety + HALT on unresolvable input - root mirror ported (SKILL.md + sibling)
- MT-CP901..905: empty project -> first workable story, stopwatch protocol, <10 min target - MT-CP903 asserts adoption files are normal (no quick-mode-only marker) - MT-CP904 guided-default regression, MT-CP905 no-TTY never hangs - registered in the suite index + maintenance checklist
- new getting-started page: depth comparison, the two still-asked questions, cascade tiers, no quick-mode-only output, CI/no-TTY behaviour - registered in getting-started/meta.json nav and CP5 page list - quickstart.mdx (CLI install) cross-links it; guided stays the default there
Records the #276 application: $mode selector, guided as bootstrap's declared default, no bespoke resolution order, no quick-mode-only output. Alternatives (separate skill / quick-as-default / third partial depth) rejected with reasons.
Adding the bootstrap-quick-mode URL without bumping the Getting Started count and the 60->61 total left CP5 self-contradictory.
Registering the page in meta.json alone leaves it outside the 200/title smoke list and the prev/next circularity sweep.
- GREEN: enumeration named only pair package + assess-* - bootstrap declares guided default, quick via $mode; delta stays in the skill - Both copies (root KB + dataset) kept identical - Task: T2 — quick-mode entry per the Guided/Quick Setup Convention Refs: #278
The file was committed before prettier ran on it, so it would have landed on main unformatted and added to the existing drift. Formatting only — no assertion changed. Two unrelated pair-cli test files that prettier also rewrote were deliberately left out: that drift pre-dates this story and belongs to #394 (pre-push gate should run the formatters in write-mode), not to a bootstrap PR. Refs #278 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verdict
PR: [#408] · Author: rucka · Reviewer: independent reviewer agent · Date: 2026-07-31 · Story: [US-278] · Type: feature (docs/skill-definition) Classification matrix — per dimension
Tier = max(assessed) = 🟡 yellow. Cost = highest detected signal = green. No drift note emitted on purpose. Story #278 carries no refinement-time classification and the PR carries neither a matrix nor a AssessmentsSecurity — Input validationVerdict: green — no input surface in the diff; the only executable file is a conformance test that reads repo files with Details
Security — Output handlingVerdict: green — no output encoding surface; the new MDX page renders static prose and fenced Details
Security — AuthenticationVerdict: green — no authentication path touched. Security — AuthorizationVerdict: green — no access-control path touched. Security — Introduced vulnerabilitiesVerdict: green — 0 introduced, 0 pre-existing on the touched surfaces. Details
No secrets, credentials, dependencies, or network calls added. Note the behavioural rule quick mode introduces: CostVerdict: Details
Architecture (Coupling)Verdict: green — balanced: one new documentation dependency from Details
DetailsFindings by severityCritical (must fix before merge)
Major (should fix before merge)
Minor (consider)
Questions
Positive feedback
Functionality & requirements (AC coverage)
Edge cases from the story: already-configured project ✅ (delegated to each composed capability's own detection, stated in both docs). A required decision with no safe default is still asked ✅ for the PM tool and the undetectable stack — ❌ for the PRD, which is the same class of decision and is not listed (Major 3). Testing & quality gates
Adoption compliance
Tech debt
Documentation
Performance & deployment
Independent review. Read only story #278, the PR (description + diff) and the branch code in a detached worktree pinned to |
Resolves every finding on PR #408. Major: - SKILL.md: quick-mode notes added to Step 2.2 (compose assess-* with Path A $choice, never plain — family default is guided) and Step 3.1 (no per-document approval round); Phase 1/3 HALT conditions marked guided-only. - KB asset: new `bootstrap-checklist.md` § Quick-Mode Per-Project-Type Defaults — the fallback tier now points at real per-type values for architecture/infra/observability/ux-ui/way-of-working. No stack, no PM tool row (project state or asked); worked examples ruled out as a default source. - PRD is a precondition, not a default: stated in SKILL.md, quick-mode-defaults.md and the docs page; CP9 gains MT-CP902 (PRD authored outside the stopwatch), timed test renumbered MT-CP903 with bootstrap/story splits. - meta.json: bootstrap-quick-mode moved after the quickstart trio, so Quickstart's footer next is Quickstart: Solo again (landing e2e stays meaningful); nav order pinned in conformance. Minor / questions: - cascade tiers disjoint (project state excludes decision-log/). - ADL softened to what the suite actually guards; suite now derives the interview-marker check per step section. - CP5 gains a Changelog; getting-started/index.mdx cross-links the page. - convention wording: adopters "do not agree on a default". - skill `version` 0.5.0 → 0.6.0 and the bump rule written down in contributing/writing-skills.mdx. risk:yellow · quality gates: PASS (22 + 12 turbo tasks, conformance 39/39) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Path A is $choice + a confirmation round; 8 composed assess-* skills would mean up to 8 questions inside a depth that claims none. Quick mode now suppresses that round, disclosed as a per-adopter deviation beside the explicit-guided no-op, asserted in conformance and in CP9 MT-CP903. Also: testing + AI sections of tech-stack.md get fallback rows (they are separate assess-* invocations); Step 2.3 list back to uniform bold; MT-CP906 gets its own project + PRD setup; interview markers now catch Step 4.3's own approval phrasing; ADL emphasis + checklist emphasis churn reverted to underscores (24 lines, both corpora). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Escalating to a human — round 3 does not convergeRound 3 re-reviewed the already-converged round-2 state ( Rounds so far (per the working log — full detail in
|
… ask Round 3's Major finding, and it is the SAME defect class round 2 fixed, in a surface round 2's guard structurally cannot see: Phase 3.5 composes /map-subdomains and /map-contexts, and BOTH end in an unconditional "Approve or adjust?". So "at most two questions" was false again, two questions further on. Why the round-2 guard missed it: that guard derives "question-bearing" steps from a step's OWN text — a blockquote question, an ask-N rule, an approval round. Phase 3.5's steps contain none of those; the questions live inside the skills it composes. A caller-side note cannot see the next composed skill that asks, which is exactly why the real fix is a non-interactive signal on the composed families — filed as #410, and referenced from both deviations. - SKILL.md Phase 3.5: quick-mode note, both corpora - quick-mode-defaults.md: disclosed deviations go from two to three; the Phase 3.5 cascade row no longer claims "never blocking" - ONE GATE KEPT DELIBERATELY: /map-contexts HALTs on an unbalanced + volatile relationship offered with neither mitigation nor acceptance. Quick mode does NOT suppress it — writing a domain model that records a coupling risk nobody judged is worse than one more question. Documented in the skill, the sibling, the docs page and CP9's MT-CP903, and pinned so a future "ask nothing at all" change cannot silently swallow it. - bootstrap-quick-mode.mdx: the rarer third case stated instead of "two" - CP9 MT-CP903: the map-* rounds added to the no-question assertion, with the HALT named as the one admissible exception Minor — quick-mode-defaults.md attributed gate-registry detection to /setup-gates, which bootstrap never composes (Step 3.2 does it). The Graceful Degradation bullet for missing assess-* skills was not depth-qualified, and read as if the manual path asks in quick mode too. NOT touched, deliberately: map-subdomains/SKILL.md and map-contexts/SKILL.md are modified by PR #387. Editing them would destroy this PR's zero-collision property, which is its main merit at the merge gate. The fix is caller-side, as round 2's was; #410 does it properly once #387 has merged. Both mirrors REGENERATED with the real transform rather than hand-ported: my hand-port drifted by one character (the pipeline prepends `./` to a same-dir link) and #352's mirror-equality guard caught it. The sibling was regenerated through applyKnownMirrorTransforms for the same reason. 44 conformance assertions, 98 with the mirror suite. `pnpm quality-gate` green. All new relative links verified to resolve on this branch. Refs #278 · #410 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Remediation report — PR #408 · story #278Synthesis across three review rounds. 28 findings total (6 Major · 18 Minor · 4 Questions) → 0 open actionable findings, with one item that is genuinely the human's call, stated at the end rather than resolved. Head at verification:
The finding that matters, and why it recurredRounds 2 and 3 found the same defect class in two different surfaces: a composed skill's own unconditional approval round leaking into a depth that claims to ask nothing.
Why round 2's guard could not see round 3's instance, which is the interesting part: that guard derives "question-bearing steps" from a step's own text — a blockquote question, an ask-N rule, an approval round — and then requires a quick-mode note on each. Phase 3.5's steps contain none of those. The questions live inside the skills it composes. A caller-side note structurally cannot see the next composed skill that asks. So the fix applied here is, honestly, another surface-specific patch: Phase 3.5 gets its note, deviation 3 is disclosed, and a new assertion pins it. That closes the known instance and nothing more. The real fix is a first-class non-interactive signal on the composed families — filed as #410, referenced from both deviations, and blocked on #387 (which owns both One gate kept, deliberately
Round 3 — the rest
Two things my own work got wrong, caught by the guards
Both are arguments for the guard this story ships against the author who ships it — which is the better kind of evidence. ⛔ Needs your call, not mine — AC1 is unmeasured at mergeRound 3's Question, and I am not resolving it by fiat:
Two honest options: run CP9 before merging (buys the headline number, costs a manual pass on an empty repo), or merge and run it after, accepting that the <10-minute claim is a design intent until someone times it. The second is defensible — nothing else in the PR depends on the number — but it should be a decision, not an omission. Verdict: everything actionable is resolved; TECH-DEBT rather than APPROVED is the honest label, carrying #410 (the structural fix) and the unmeasured KPI to the merge gate as named, accepted items. |
…es re-anchored, wrappers deduped Guard (pre-push-gate-composition.ts): - expansion tolerates runner flags and npm/yarn: `pnpm -s format`, `pnpm -w format`, `npm run format` all reached the write-mode formatter with a green guard, because the captured "script name" was the flag and the body was never scanned. - offender list made symmetric per tool: bin alias / .sh entrypoint / raw CLI write flag (`prettier-fix`, `markdownlint-fix`, `prettier --write`, `markdownlint --fix`) — the prettier `.sh` form used to walk straight past a list that named markdownlint's. - guard-present check requires RUNNING it (`referencesScript`), so `echo gate:composition` no longer satisfies it. - docstring: offenders come back in the offender list's order, not the gate's. Wrappers: - ignore assembly extracted per tool (`bin/_ignore-args.sh`, `bin/_ignore-file.sh`); check and fix now share one source of the invariant instead of four copies. - prettier args assembled positionally, so a repo path containing a space no longer word-splits into a bogus pattern (prettier exited 2 on every push for that contributor). - root .gitignore re-anchored to the cwd for markdownlint (`_reanchor-gitignore.awk`): it resolves patterns against the cwd, git against the ignore file's dir, so a path-anchored entry (`apps/website/gen/`) would have blocked every push from that package. - cwd/git-root de-dup compares canonical paths (`pwd -P`), same structure in both tools. Coverage + caching: - new smoke test `format-ignore-delegation.sh` (both tools, check and fix, gitignored vs not, plus a path with a space) — verified RED against the pre-fix wrappers; wired into the CI list. - turbo.json `globalDependencies`: the ignore sources are inputs of cacheable tasks, so a .gitignore edit no longer replays a stale PASS/FAIL. ADL: Context now cites the incidents actually observed (PRs #388, #408, #411 — three in two days, with story+branch each) and records the re-anchoring, the shared helpers, the smoke coverage and the globalDependencies. Refs: #394
…transform `main` went red the moment #387 and #406 were both on it, and neither PR was wrong. #387 (brainstorm's new `resume.md` / `parametrization.md` siblings) was green before #406 widened the mirror-equality guard beyond `SKILL.md`; #406 was green before those siblings existed. Merging them in EITHER order produces this failure, so no single PR's CI could have caught it. The cause is mine: I hand-ported those siblings to the root mirror in #387 instead of regenerating them through the real transform. - `parametrization.md` — a missing blank line before `## $domain-placed`. - `resume.md` — SUBSTANTIVE, not cosmetic. The hand-port applied the skill-reference rewrite to a FILE NAME, shipping the handoff key as `.pair/working/pair-process-brainstorm-<root-id | theme-slug>.md` where the dataset says `.pair/working/brainstorm-<root-id | theme-slug>.md`. The real transform does not rewrite it — it is a working-file name, not a skill reference — so the shipped mirror documented a different handoff key than its authoring source. A resume reading one and a write using the other never meet. - `SKILL.md` + the dataset twin — emphasis style. Surfaced only while fixing the above, and its cause is the defect #394 fixes: the gate's `mdlint:fix` runs in WRITE mode, so my own gate run rewrote the DATASET's emphasis markers, leaving the mirror behind. The manual gate passed because it was reformatting as it ran; the pre-push hook then compared the rewritten dataset against the untouched mirror. Kept the gate's formatting (it is this repo's authority) and realigned the mirror. Third time today a hand-ported mirror drifted from the transform (#408 by one `./`, #411 likewise). The lesson is applied on the open branches: regenerate, never hand-port. `pnpm quality-gate` green — knowledge-hub 715 tests, mirror guard 82. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Test-first: the guard was written and verified RED against the repo's own package.json before the gate changed. The gate ran `prettier:fix` and `mdlint:fix` REPO-WIDE in write mode, and the gate is the pre-push hook. The decisive problem is not noise, it is uselessness: at pre-push THE COMMITS ALREADY EXIST, so a write-mode formatter rewrites the working tree and cannot fix what is being pushed. Its output goes nowhere unless the author notices and amends — so the author either sweeps unrelated reformats into the next commit or pushes with `--no-verify`, and once bypassing is routine the hook asserts nothing. Observed three times in two days: #388 was pushed with --no-verify after the hook reformatted two unrelated pair-cli test files; the same two files were swept into #411 by a `git add -A` and had to be reverted; and they were excluded by hand from #408. - `format` — the explicit fix command (was the gate's write-mode step) - `format:check` — what the gate runs now - `gate:composition` — a tested module that reads the root package.json and fails if a write-mode formatter is ever put back. The regression is a one-word edit away and its symptom looks like author error rather than tooling behaviour, which is why a comment would not have been enough. - `**/.source/` prettier-ignored: generated by fumadocs-mdx at postinstall and already gitignored. In write mode the gate silently rewrote it on every push; in check mode it would have BLOCKED every push. A build artifact must not be able to do either. Includes the one-time sweep check mode requires: the two pair-cli version-check test files are formatted here. Sweeping unrelated files in the PR that forbids sweeping them is deliberate — the drift has to be cleared once for check mode to be viable, and after this the gate cannot produce such sweeps. Guard logic in a tested module under packages/dev-tools/src/quality-gates/ with a thin CLI entrypoint, per ADL 2026-07-13. The offender list is explicit rather than a `/:fix/` pattern: `lint:fix` is an eslint autofix, a different concern, and is asserted NOT to trip the guard. `pnpm quality-gate` green, and it now prints "✓ pre-push gate composition: check-mode only". Closes #394 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…es re-anchored, wrappers deduped Guard (pre-push-gate-composition.ts): - expansion tolerates runner flags and npm/yarn: `pnpm -s format`, `pnpm -w format`, `npm run format` all reached the write-mode formatter with a green guard, because the captured "script name" was the flag and the body was never scanned. - offender list made symmetric per tool: bin alias / .sh entrypoint / raw CLI write flag (`prettier-fix`, `markdownlint-fix`, `prettier --write`, `markdownlint --fix`) — the prettier `.sh` form used to walk straight past a list that named markdownlint's. - guard-present check requires RUNNING it (`referencesScript`), so `echo gate:composition` no longer satisfies it. - docstring: offenders come back in the offender list's order, not the gate's. Wrappers: - ignore assembly extracted per tool (`bin/_ignore-args.sh`, `bin/_ignore-file.sh`); check and fix now share one source of the invariant instead of four copies. - prettier args assembled positionally, so a repo path containing a space no longer word-splits into a bogus pattern (prettier exited 2 on every push for that contributor). - root .gitignore re-anchored to the cwd for markdownlint (`_reanchor-gitignore.awk`): it resolves patterns against the cwd, git against the ignore file's dir, so a path-anchored entry (`apps/website/gen/`) would have blocked every push from that package. - cwd/git-root de-dup compares canonical paths (`pwd -P`), same structure in both tools. Coverage + caching: - new smoke test `format-ignore-delegation.sh` (both tools, check and fix, gitignored vs not, plus a path with a space) — verified RED against the pre-fix wrappers; wired into the CI list. - turbo.json `globalDependencies`: the ignore sources are inputs of cacheable tasks, so a .gitignore edit no longer replays a stale PASS/FAIL. ADL: Context now cites the incidents actually observed (PRs #388, #408, #411 — three in two days, with story+branch each) and records the re-anchoring, the shared helpers, the smoke coverage and the globalDependencies. Refs: #394
…rs the repo's write scripts 11 findings (2 Major, 9 Minor), all resolved. Major: - Rebased onto current origin/main (twice — #389/#391, then #405/#408 landed mid-round) and cleared main's format baseline in its own commit, so `format:check` is green on the tree this actually lands on (AC3). The sync-version-in-docs.ts conflict with #391 keeps BOTH docstrings. - The advertised remedy was a trap: `pnpm format` fixes the dataset SKILL.md and cannot reach its generated .claude twin (not a workspace member), while skill-md-mirror asserts byte equality — so format:check-green became skills:conformance-red later in the SAME gate. Reproduced end-to-end. The two-step remedy is now stated in all three places that advertise it (DEVELOPMENT.md, the mdx twin, PRE_PUSH_REMEDY) and unit-tested; the structural fix is noted on #414. Minor: - Guard widened to the repo's real write scripts: `sync-version` (→ sync-version-in-docs.ts, writeFileSync across every .md/.mdx it walks; `--check` dry-run spared, bounded to the same command segment) and `test:perf` (→ benchmark-update-link.ts, no dry-run, banned outright). 6 tests, verified RED. The ADL + way-of-working now state that what is enforced is the explicit list, not the invariant in general. - `_reanchor-gitignore.awk`: `[!abc]` → `[^abc]` (ERE negates with ^, gitignore with !) — unfixed it matched a literal `!`, i.e. the inverse set, silently dropping the pattern. Pinned by a row in the table-driven smoke block (`apps/[!x]ebsite/build/`), verified RED. Known-approximation note extended to cover bracket expressions and the `[]abc]` leading-`]` case. - `_ignore-file.sh` "Effect:" now warns the EXIT trap REPLACES the caller's. - `format:check` aggregates instead of short-circuiting, so one run names both prettier AND markdownlint drift. Verified: the `&&` form hid the markdown violation entirely. - turbo.json `//` comment records the globalDependencies blast radius as a deliberate over-approximation, and why the per-task `inputs` option was passed over. - DEVELOPMENT.md and the mdx twin are now byte-identical modulo the link form (a `diff` of the two paragraphs is a one-line diff when in sync); command blocks mirrored both ways (`mdlint:check` added, `(prettier only)` added). The two remaining PR-description findings (a false "were removed" parenthetical and the stale #389/#391 merge-order section) are fixed in the PR body, not here. NOTE: `pnpm turbo test` is red on this base for TWO reasons that pre-date and have nothing to do with #394 — both reproduced on a pristine origin/main worktree: skill-md-mirror on process/bootstrap/quick-mode-defaults.md (#408 merged an unregenerated .claude mirror — the very coupling this round documents) and code-host-routing AC4 on assess-cost/SKILL.md:106 (#388 prose + #389 audit merge-order collision). main's own CI is failing.
… landing Third and fourth instance today of the same class: two PRs each green on their own branch, red once both are on main, because each PR's guard only ever saw its own branch. Neither PR was wrong either time. 1. **#388 + #389.** #389's AC4 audit forbids a skill doc from reading a PR "from the PM tool". #388's `assess-cost` report mode reads the window's merged PRs "from the PM tool / code host" — correctly routed, with a pointer to the resolution convention, so it is a FALSE POSITIVE of the guard: the pattern tempers itself against `code host` only in the 60 characters BEFORE "the PM tool", and here it comes after. Reordered to "from the code host / PM tool", which is also the more accurate reading — a PR is a code-host object, so naming that side first is right independently of the guard. Recorded for whoever tunes that pattern next: the temper is order-dependent, so `PRs … from the PM tool … (code host)` would still pass. Not widened here — the guard belongs to #236 and this is a main-fix, not a scope change. 2. **#408 + #406.** The bootstrap sibling's mirror shipped `[SKILL.md](SKILL.md)` where the real pipeline emits `[SKILL.md](./SKILL.md)` — it prepends `./` to a same-dir link when the file moves. #408's own sibling-parity test tolerates exactly that shape (it calls `neutralizeSameDirDotSlash` on both sides), while #406's widened mirror guard does not. So the escape hatch in one test is what let it reach main, where the other guard caught it. Both fixes are one line. What is not one line is the pattern: four times today a merge of two green PRs produced a red main. The common cause is that every guard runs against its own branch, so an interaction is only ever observable after the second merge — and nothing runs the full gate on the post-merge state before it is pushed. `pnpm quality-gate` green — 22 + 12 tasks.
Test-first: the guard was written and verified RED against the repo's own package.json before the gate changed. The gate ran `prettier:fix` and `mdlint:fix` REPO-WIDE in write mode, and the gate is the pre-push hook. The decisive problem is not noise, it is uselessness: at pre-push THE COMMITS ALREADY EXIST, so a write-mode formatter rewrites the working tree and cannot fix what is being pushed. Its output goes nowhere unless the author notices and amends — so the author either sweeps unrelated reformats into the next commit or pushes with `--no-verify`, and once bypassing is routine the hook asserts nothing. Observed three times in two days: #388 was pushed with --no-verify after the hook reformatted two unrelated pair-cli test files; the same two files were swept into #411 by a `git add -A` and had to be reverted; and they were excluded by hand from #408. - `format` — the explicit fix command (was the gate's write-mode step) - `format:check` — what the gate runs now - `gate:composition` — a tested module that reads the root package.json and fails if a write-mode formatter is ever put back. The regression is a one-word edit away and its symptom looks like author error rather than tooling behaviour, which is why a comment would not have been enough. - `**/.source/` prettier-ignored: generated by fumadocs-mdx at postinstall and already gitignored. In write mode the gate silently rewrote it on every push; in check mode it would have BLOCKED every push. A build artifact must not be able to do either. Includes the one-time sweep check mode requires: the two pair-cli version-check test files are formatted here. Sweeping unrelated files in the PR that forbids sweeping them is deliberate — the drift has to be cleared once for check mode to be viable, and after this the gate cannot produce such sweeps. Guard logic in a tested module under packages/dev-tools/src/quality-gates/ with a thin CLI entrypoint, per ADL 2026-07-13. The offender list is explicit rather than a `/:fix/` pattern: `lint:fix` is an eslint autofix, a different concern, and is asserted NOT to trip the guard. `pnpm quality-gate` green, and it now prints "✓ pre-push gate composition: check-mode only". Closes #394 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…es re-anchored, wrappers deduped Guard (pre-push-gate-composition.ts): - expansion tolerates runner flags and npm/yarn: `pnpm -s format`, `pnpm -w format`, `npm run format` all reached the write-mode formatter with a green guard, because the captured "script name" was the flag and the body was never scanned. - offender list made symmetric per tool: bin alias / .sh entrypoint / raw CLI write flag (`prettier-fix`, `markdownlint-fix`, `prettier --write`, `markdownlint --fix`) — the prettier `.sh` form used to walk straight past a list that named markdownlint's. - guard-present check requires RUNNING it (`referencesScript`), so `echo gate:composition` no longer satisfies it. - docstring: offenders come back in the offender list's order, not the gate's. Wrappers: - ignore assembly extracted per tool (`bin/_ignore-args.sh`, `bin/_ignore-file.sh`); check and fix now share one source of the invariant instead of four copies. - prettier args assembled positionally, so a repo path containing a space no longer word-splits into a bogus pattern (prettier exited 2 on every push for that contributor). - root .gitignore re-anchored to the cwd for markdownlint (`_reanchor-gitignore.awk`): it resolves patterns against the cwd, git against the ignore file's dir, so a path-anchored entry (`apps/website/gen/`) would have blocked every push from that package. - cwd/git-root de-dup compares canonical paths (`pwd -P`), same structure in both tools. Coverage + caching: - new smoke test `format-ignore-delegation.sh` (both tools, check and fix, gitignored vs not, plus a path with a space) — verified RED against the pre-fix wrappers; wired into the CI list. - turbo.json `globalDependencies`: the ignore sources are inputs of cacheable tasks, so a .gitignore edit no longer replays a stale PASS/FAIL. ADL: Context now cites the incidents actually observed (PRs #388, #408, #411 — three in two days, with story+branch each) and records the re-anchoring, the shared helpers, the smoke coverage and the globalDependencies. Refs: #394
…rs the repo's write scripts 11 findings (2 Major, 9 Minor), all resolved. Major: - Rebased onto current origin/main (twice — #389/#391, then #405/#408 landed mid-round) and cleared main's format baseline in its own commit, so `format:check` is green on the tree this actually lands on (AC3). The sync-version-in-docs.ts conflict with #391 keeps BOTH docstrings. - The advertised remedy was a trap: `pnpm format` fixes the dataset SKILL.md and cannot reach its generated .claude twin (not a workspace member), while skill-md-mirror asserts byte equality — so format:check-green became skills:conformance-red later in the SAME gate. Reproduced end-to-end. The two-step remedy is now stated in all three places that advertise it (DEVELOPMENT.md, the mdx twin, PRE_PUSH_REMEDY) and unit-tested; the structural fix is noted on #414. Minor: - Guard widened to the repo's real write scripts: `sync-version` (→ sync-version-in-docs.ts, writeFileSync across every .md/.mdx it walks; `--check` dry-run spared, bounded to the same command segment) and `test:perf` (→ benchmark-update-link.ts, no dry-run, banned outright). 6 tests, verified RED. The ADL + way-of-working now state that what is enforced is the explicit list, not the invariant in general. - `_reanchor-gitignore.awk`: `[!abc]` → `[^abc]` (ERE negates with ^, gitignore with !) — unfixed it matched a literal `!`, i.e. the inverse set, silently dropping the pattern. Pinned by a row in the table-driven smoke block (`apps/[!x]ebsite/build/`), verified RED. Known-approximation note extended to cover bracket expressions and the `[]abc]` leading-`]` case. - `_ignore-file.sh` "Effect:" now warns the EXIT trap REPLACES the caller's. - `format:check` aggregates instead of short-circuiting, so one run names both prettier AND markdownlint drift. Verified: the `&&` form hid the markdown violation entirely. - turbo.json `//` comment records the globalDependencies blast radius as a deliberate over-approximation, and why the per-task `inputs` option was passed over. - DEVELOPMENT.md and the mdx twin are now byte-identical modulo the link form (a `diff` of the two paragraphs is a one-line diff when in sync); command blocks mirrored both ways (`mdlint:check` added, `(prettier only)` added). The two remaining PR-description findings (a false "were removed" parenthetical and the stale #389/#391 merge-order section) are fixed in the PR body, not here. NOTE: `pnpm turbo test` is red on this base for TWO reasons that pre-date and have nothing to do with #394 — both reproduced on a pristine origin/main worktree: skill-md-mirror on process/bootstrap/quick-mode-defaults.md (#408 merged an unregenerated .claude mirror — the very coupling this round documents) and code-host-routing AC4 on assess-cost/SKILL.md:106 (#388 prose + #389 audit merge-order collision). main's own CI is failing.
Test-first: the guard was written and verified RED against the repo's own package.json before the gate changed. The gate ran `prettier:fix` and `mdlint:fix` REPO-WIDE in write mode, and the gate is the pre-push hook. The decisive problem is not noise, it is uselessness: at pre-push THE COMMITS ALREADY EXIST, so a write-mode formatter rewrites the working tree and cannot fix what is being pushed. Its output goes nowhere unless the author notices and amends — so the author either sweeps unrelated reformats into the next commit or pushes with `--no-verify`, and once bypassing is routine the hook asserts nothing. Observed three times in two days: #388 was pushed with --no-verify after the hook reformatted two unrelated pair-cli test files; the same two files were swept into #411 by a `git add -A` and had to be reverted; and they were excluded by hand from #408. - `format` — the explicit fix command (was the gate's write-mode step) - `format:check` — what the gate runs now - `gate:composition` — a tested module that reads the root package.json and fails if a write-mode formatter is ever put back. The regression is a one-word edit away and its symptom looks like author error rather than tooling behaviour, which is why a comment would not have been enough. - `**/.source/` prettier-ignored: generated by fumadocs-mdx at postinstall and already gitignored. In write mode the gate silently rewrote it on every push; in check mode it would have BLOCKED every push. A build artifact must not be able to do either. Includes the one-time sweep check mode requires: the two pair-cli version-check test files are formatted here. Sweeping unrelated files in the PR that forbids sweeping them is deliberate — the drift has to be cleared once for check mode to be viable, and after this the gate cannot produce such sweeps. Guard logic in a tested module under packages/dev-tools/src/quality-gates/ with a thin CLI entrypoint, per ADL 2026-07-13. The offender list is explicit rather than a `/:fix/` pattern: `lint:fix` is an eslint autofix, a different concern, and is asserted NOT to trip the guard. `pnpm quality-gate` green, and it now prints "✓ pre-push gate composition: check-mode only". Closes #394 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…es re-anchored, wrappers deduped Guard (pre-push-gate-composition.ts): - expansion tolerates runner flags and npm/yarn: `pnpm -s format`, `pnpm -w format`, `npm run format` all reached the write-mode formatter with a green guard, because the captured "script name" was the flag and the body was never scanned. - offender list made symmetric per tool: bin alias / .sh entrypoint / raw CLI write flag (`prettier-fix`, `markdownlint-fix`, `prettier --write`, `markdownlint --fix`) — the prettier `.sh` form used to walk straight past a list that named markdownlint's. - guard-present check requires RUNNING it (`referencesScript`), so `echo gate:composition` no longer satisfies it. - docstring: offenders come back in the offender list's order, not the gate's. Wrappers: - ignore assembly extracted per tool (`bin/_ignore-args.sh`, `bin/_ignore-file.sh`); check and fix now share one source of the invariant instead of four copies. - prettier args assembled positionally, so a repo path containing a space no longer word-splits into a bogus pattern (prettier exited 2 on every push for that contributor). - root .gitignore re-anchored to the cwd for markdownlint (`_reanchor-gitignore.awk`): it resolves patterns against the cwd, git against the ignore file's dir, so a path-anchored entry (`apps/website/gen/`) would have blocked every push from that package. - cwd/git-root de-dup compares canonical paths (`pwd -P`), same structure in both tools. Coverage + caching: - new smoke test `format-ignore-delegation.sh` (both tools, check and fix, gitignored vs not, plus a path with a space) — verified RED against the pre-fix wrappers; wired into the CI list. - turbo.json `globalDependencies`: the ignore sources are inputs of cacheable tasks, so a .gitignore edit no longer replays a stale PASS/FAIL. ADL: Context now cites the incidents actually observed (PRs #388, #408, #411 — three in two days, with story+branch each) and records the re-anchoring, the shared helpers, the smoke coverage and the globalDependencies. Refs: #394
…rs the repo's write scripts 11 findings (2 Major, 9 Minor), all resolved. Major: - Rebased onto current origin/main (twice — #389/#391, then #405/#408 landed mid-round) and cleared main's format baseline in its own commit, so `format:check` is green on the tree this actually lands on (AC3). The sync-version-in-docs.ts conflict with #391 keeps BOTH docstrings. - The advertised remedy was a trap: `pnpm format` fixes the dataset SKILL.md and cannot reach its generated .claude twin (not a workspace member), while skill-md-mirror asserts byte equality — so format:check-green became skills:conformance-red later in the SAME gate. Reproduced end-to-end. The two-step remedy is now stated in all three places that advertise it (DEVELOPMENT.md, the mdx twin, PRE_PUSH_REMEDY) and unit-tested; the structural fix is noted on #414. Minor: - Guard widened to the repo's real write scripts: `sync-version` (→ sync-version-in-docs.ts, writeFileSync across every .md/.mdx it walks; `--check` dry-run spared, bounded to the same command segment) and `test:perf` (→ benchmark-update-link.ts, no dry-run, banned outright). 6 tests, verified RED. The ADL + way-of-working now state that what is enforced is the explicit list, not the invariant in general. - `_reanchor-gitignore.awk`: `[!abc]` → `[^abc]` (ERE negates with ^, gitignore with !) — unfixed it matched a literal `!`, i.e. the inverse set, silently dropping the pattern. Pinned by a row in the table-driven smoke block (`apps/[!x]ebsite/build/`), verified RED. Known-approximation note extended to cover bracket expressions and the `[]abc]` leading-`]` case. - `_ignore-file.sh` "Effect:" now warns the EXIT trap REPLACES the caller's. - `format:check` aggregates instead of short-circuiting, so one run names both prettier AND markdownlint drift. Verified: the `&&` form hid the markdown violation entirely. - turbo.json `//` comment records the globalDependencies blast radius as a deliberate over-approximation, and why the per-task `inputs` option was passed over. - DEVELOPMENT.md and the mdx twin are now byte-identical modulo the link form (a `diff` of the two paragraphs is a one-line diff when in sync); command blocks mirrored both ways (`mdlint:check` added, `(prettier only)` added). The two remaining PR-description findings (a false "were removed" parenthetical and the stale #389/#391 merge-order section) are fixed in the PR body, not here. NOTE: `pnpm turbo test` is red on this base for TWO reasons that pre-date and have nothing to do with #394 — both reproduced on a pristine origin/main worktree: skill-md-mirror on process/bootstrap/quick-mode-defaults.md (#408 merged an unregenerated .claude mirror — the very coupling this round documents) and code-host-routing AC4 on assess-cost/SKILL.md:106 (#388 prose + #389 audit merge-order collision). main's own CI is failing.
PR Information
Story: #278 · Epic: #213 · Type: Feature · Priority: High (P0) · Assignee: @rucka
Classification
risk:yellow · cost:green — criticality 🟡 (KB default, no criticality table) · diff risk 🟡 (5 workspaces, shared KB asset) · business impact 🟡 (both touched subdomains Supporting) · security 🟢 · coupling 🟢 balanced. Tier = max(dimensions) = 🟡. Backfilled at review time (round 1): the refinement-time matrix was missing from both the story and this PR, so automation read it as red (fail-safe, quality-model §3.2).
Matrix
tech/risk-matrix.mddeclares no criticality table → KB default mediumGate set for 🟡: lint + type + build + unit — all green locally (
pnpm quality-gate, 22 + 12 turbo tasks).Summary
What Changed
/pair-process-bootstrapgains a second resolution depth, selected by$mode: quick— an opinionated default setup instead of the full Phase 0–4 interview. Guided stays the declared default: absent$mode, nothing changes.SKILL.md(+43/−8 dataset, +38/−3 mirror) — the quick entry, composing the Guided/Quick Setup Convention's cascade.quick-mode-defaults.md(new, +53, mirrored) — the disclosed per-adopter delta: which decision points are defaultable, which cascade tier fills each, and which are still asked.2026-07-31-bootstrap-quick-is-a-depth-not-a-skill.md.getting-started/bootstrap-quick-mode.mdx(+70), cross-linked fromquickstart.mdx, registered inmeta.json.CP9-quickstart-onboarding.md(+142) for the epic's own <10-minute KPI;CP5page count updated.Why This Change
The epic's KPI is time to first workable story on an empty repo, target <10 minutes. The guided interview is the right default for a team that wants to decide each point, and the wrong one for a team that wants to start.
Story Context
As a new team adopting pair I want a Quickstart path in bootstrap So that setup takes minutes instead of the full guided interview, while the complete guided bootstrap remains available.
AC1 <10 min, no interview · AC2 guided unchanged when not requested · AC3 follows the #276 convention exactly, no bespoke resolution · AC4 every default is a normal, editable adoption file.
Changes Made
Implementation Details
The shape was a real decision, and the convention did not settle it. #276 (merged, PR #349) fixes the selector direction, the four-tier cascade (
explicit argument > project state > saved preferences > hardcoded fallback) and the non-interactive safety rule, but explicitly leaves which mode is the default to each adopter — and its two shipped adopters declare opposite defaults (pair package→ quick, theassess-*family → guided). So bootstrap had to declare its own rather than inherit one. It declares guided.Three constraints follow, each asserted in conformance:
skills-catalog.mdxrow changed, keeping the PR off a file four parked PRs touch.)Two decisions stay asked in quick mode, because no KB value is safe: the PM tool (organisational, not technical) and the tech stack when the repo is genuinely empty. This is the story's own edge case — quick mode reduces questions to the genuinely-defaultable ones, it does not eliminate every question unconditionally.
Files Changed
quick-mode-defaults.md(×2 corpora, +68 each), the ADL (+53),bootstrap-quick-mode.mdx(+74),CP9-quickstart-onboarding.md(+185),bootstrap.test.ts(+502)bootstrap/SKILL.md(×2),.pair/knowledge/assets/bootstrap-checklist.md(×2 corpora — new § Quick-Mode Per-Project-Type Defaults, the fallback tier's KB anchor; the largest single change here),guided-quick-setup.md(×2 — bootstrap listed as a third adopter),contributing/writing-skills.mdx(the skillversionbump rule),getting-started/index.mdx(one bullet in "Choose your path"),quickstart.mdx,meta.json,docs.e2e.test.ts,CP5,qa/README.mdTesting
Test Coverage
bootstrap.test.ts— 42 assertions (26 at first push, +13 in review round 1, +3 in round 2), the original set written test-first and verified RED before any implementation existed, all green. They pin the three ADL constraints rather than the prose: one entry point, no bespoke cascade, no marker on quick-mode output.Test Results
pnpm quality-gategreen (exit 0) — 22 + 12 turbo tasks, re-run after each review round.@pair/knowledge-hubsuite 560 green..md/.mdxtarget resolved on this branch. Doing this explicitly becausepnpm quality-gatedoes not check markdown links — that check is an e2e test (ci.yml:120, inside thebuildjob), outside the local gate set, and a sibling PR shipped two dead links past a green local gate this week.meta.json(nav),docs.e2e.test.ts(page list),CP5(manual completeness).Quality Assurance
Review Areas
guidedthe right default for bootstrap? The convention permits either; this PR argues guided because bootstrap is the one skill whose output is the project's adopted decisions. Reversible, but it is a declared position, not an accident.quick-mode-defaults.md§ Disclosed deviations):$mode: guidedaccepted as a loud no-op, and — added in review round 2 — Path A's confirmation round suppressed on composedassess-*skills in quick mode. Without the second one, "asks no questions" is false the moment more than zero assess-* skills are installed. The alternative (a first-class non-interactive signal on the assess-* family) touches eight skills plus the cascade convention and is left to its own story.Notes for reviewers
AC1's <10-minute claim is validated by a manual timed scenario (CP9), not by an automated test. The story asked for exactly that, and it cannot be honestly asserted in CI — but it means the headline number rests on someone running CP9, not on this PR being green.
Dependencies & Related Work
getting-started/index.mdx:36(the "Choose your path" list), a file [US-230] feat: pair-process-brainstorm — 3 phases, parametrized ($root, orientation) #387 also touches. One added line in a bullet list — trivial conflict, resolvable either merge order. Noreference/*.mdxis touched.Closes #278
🤖 Generated with Claude Code