feat(preflight): [ STACK WARNINGS ] — flag a check stack absent at the repo root (dogfood F2) - #89
Conversation
…t the repo root (dogfood F2) New check_stack_reality() preflight warns at configure time when a configured check command's (typecheck/lint/test) stack manifest is missing at the repo root — the exact condition that makes stop-run-checks.sh silently skip at runtime (skip rule 3). Maps each command's first binary via the shlex-guarded extract_first_binaries() to a stack manifest (new BINARY_TO_MANIFEST, mirroring manifest_for() in stop-run-checks.sh); names the subdir for monorepos (frontend/package.json). When a warned binary is also absent from the host PATH and a compose/Dockerfile is present, it notes the host hooks will no-op because the toolchain lives in the container — host-PATH-gated, so a monorepo whose compose file only backs services doesn't get a false warning. Also hardens the pre-existing extract_first_binaries: shlex.split is now guarded against ValueError (an unbalanced quote in a cmd_* field used to crash the configurator). Tests: test/cc-manifest/test-stack-reality-preflight.sh (8 cases incl. the host-PATH gate via an injected which) + a malformed-quote case in test-check-commands-extracted.sh. --check clean, 103/103 fixtures, 5 persona snapshots, module smoke. Split from the originally-bundled PR #87 per CONTRIBUTING.md (one logical change per PR); F1 (the SessionStart matcher fix) ships as #88. Incorporates review advisories A1 (host-PATH-gated container note) + A2 (reuse extract_first_binaries). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
VERDICT: COMMENT-ONLY PR adds BlockingNone. AdvisoryA1 —
|
…dant import; tighten migration test (review follow-ups) (#90) Three non-blocking advisories from the split dogfood PRs #88/#89: (1) check_stack_reality's container-note gate used shutil.which(b), which always returns None for a path-like binary like ./gradlew (a project-local wrapper, never on PATH) — so a Gradle-wrapper project with a Dockerfile and no root build.gradle got a spurious "toolchain in container" note. The gate now file-checks path-like binaries ((target_dir / b).exists()) and only consults shutil.which for bare names. (2) the inline `import shutil` inside check_stack_reality was redundant (shutil is imported at module top) and is removed. (3) test-sessionstart-matcher-migration.sh case 2 now asserts the marker-clear migrates OUT of a user's mixed matcherless group (exactly once, under startup|clear), not merely that the user hook survives — and the F1 CHANGELOG bullet's stale "subset" description is corrected to the shipped placement-set pre-pass. New ./gradlew case in test-stack-reality-preflight.sh. No behavior change for non-path stacks. --check clean, 105/105 fixtures. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
What
F2 from the container dogfood. A default Node/pnpm intake on a project whose manifest lives in a subdir or behind Docker produces check commands (
pnpm typecheck/lint/test) thatstop-run-checks.shsilently skips (skip rule 3: nopackage.jsonat root) — the whole Stop-loop self-disables with zero feedback.Change
New
check_stack_reality()preflight +BINARY_TO_MANIFEST(mirrorsmanifest_for()instop-run-checks.sh). It maps each configured check command's (typecheck/lint/test) first binary — through the shlex-guardedextract_first_binaries— to its stack manifest and warns when that manifest is missing at the repo root, naming the subdir for monorepos. Rendered as a[ STACK WARNINGS ]block alongside the existing preflights. Warning-only; silent when the stack matches root or no command maps to a known manifest.Container note is host-PATH-gated (review advisory A1): it fires only when a warned binary is absent from the host PATH (toolchain genuinely in the container). A monorepo whose
docker-compose.ymlonly backs services (hostpnpmpresent) gets the actionable subdir warning but not a false "hooks will no-op" note.Also hardens the pre-existing
extract_first_binaries:shlex.splitis now guarded againstValueError(an unbalanced quote in acmd_*field used to crash the configurator with a traceback).check_stack_realityreuses it rather than duplicating the extraction loop (review advisory A2).Tests
test/cc-manifest/test-stack-reality-preflight.sh— matched-silent, unmappable-silent, monorepo-names-subdir, container-note-when-toolchain-off-host, container-note-suppressed-when-on-host (via an injectedwhich), absent-everywhere, install-only-silent, malformed-quote-safe. Plus a malformed-quote case intest-check-commands-extracted.sh.configure.py --checkclean; 103/103 fixtures; 5/5 persona snapshots; module-combo smoke; dry-run repro of the[ STACK WARNINGS ]block.Scope
Split out of #87 per
CONTRIBUTING.md("one logical change per PR") — this is thefeat/minor half; F1 (SessionStart matcher) is #88. Notested_up_to/CC_VERSIONbump.🤖 Generated with Claude Code