FE-871: Brunch toolchain detection — detect + plan-emitter wiring#214
FE-871: Brunch toolchain detection — detect + plan-emitter wiring#214kostandinang wants to merge 7 commits into
Conversation
0a176f5 to
bcccd55
Compare
c949e53 to
a1afc98
Compare
PR SummaryMedium Risk Overview The emitter inserts detection as Slice verification paths for brownfield co-locate with the host repo: Unit coverage spans Reviewed by Cursor Bugbot for commit a5eb05c. Bugbot is set up for automated code reviews on this repo. Configure here. |
bcccd55 to
86df4fc
Compare
625b1b5 to
f0c931a
Compare
86df4fc to
4cac54a
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f0c931a. Configure here.
Add detectProfile(repoDir): a pure, evidence-first detector that maps a real
repo's manifests/lockfiles to a registry ProfileId — the brownfield front of
the FE-843 selection chain. Bun lockfile → bun; deno config/lock → deno;
package.json vitest/jest/none → node-vitest/node-jest/node-test (lockfile
evidence wins over package.json deps).
Fails loudly instead of defaulting: known-but-unsupported stacks (Python via
pyproject.toml/setup.py, Go via go.mod) and unrecognized dirs return
{detected:false, reason} with an actionable message and the valid profile
list — a wrong-but-silent toolchain produces unrunnable tests, the failure
this closes. A malformed package.json is treated as a Node project (node-test).
Pure detector only; wiring into the plan-emitter chain + the greenfield no-op
and greenfield-protecting check are slice 2.
Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a
Co-authored-by: Amp <amp@ampcode.com>
Insert brunch-detect as the brownfield front of the FE-843 selection chain via resolveEmittedProfile: flag >> detected (brownfield) >> spec >> architect-classified >> bun. A loud detection failure throws rather than silently defaulting to bun (falling through to an explicit spec/architect choice first). Greenfield (or brownfield without a repoDir) keeps the unchanged chain. Thread repoDir from the CLI launch cwd through runPlan into emitPlanFromSnapshot; expose an injectable detect seam for hermetic emitter tests. Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a Co-authored-by: Amp <amp@ampcode.com>
… verification Fold the agent-native action vs harness-owned verification distinction into both frontier definitions: the value is the independent, deterministic, unshortcuttable check (the FE-800 orphan problem is unsolvable by agent self-report — same read-only discipline as evaluate-done at pi-actions.ts:70), not the boot/wiring action, which is agent-native via bash. Boot mechanics may lean on agent bash rather than a bespoke per-stack boot engine. Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a Co-authored-by: Amp <amp@ampcode.com>
…nches Review fix (oracle-confirmed): detectProfile silently resolved ambiguous evidence by check-order — a package.json declaring both vitest and jest picked vitest, violating the fail-loud-not-silent-default invariant (acceptance #4). It now returns a loud {detected:false} reason and defers to --profile. Also trims the pyproject.toml/setup.py/go.mod special-casing (+ the 'unsupported' helper): those only renamed an error the catch-all already produces actionably, which is the 'language-detection framework' the design explicitly rejects. Any repo with no JS/TS evidence now falls to one actionable catch-all. Behavior for non-JS repos is unchanged (still a loud, actionable failure); only the per-stack naming is gone. PLAN.md brunch-detect definition updated to match. Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019ecb9a-9a08-733b-833d-76885fc8243a Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
f0c931a to
a5eb05c
Compare
4cac54a to
7ae1e4f
Compare


Stack Context
Stacks on FE-867 (#213). Second Arc-1 frontier -- closes the
brunch detectgap FE-843 deferred. Slices 1 + 2 both land here.What?
Resolve a real repo's toolchain to a registry
ProfileIdat plan time, and use it as the brownfield front of the FE-843 chain.detectProfile,project-detect.ts): pure, evidence-first -- the cheap "which lockfile/manifest is present" check, not a language-detection engine. Bun lockfile ->bun; deno config ->deno;package.jsondeps -> vitest/jest/none ->node-vitest/node-jest/node-test. One clear supported signal resolves; anything else fails loud ({detected:false, reason}), never a silent default; maps only to registry ids.resolveEmittedProfile,plan-emitter.ts):detectedbecomes the brownfield front of the chain --repoDirthreads CLI cwd ->runPlan->emitPlanFromSnapshot; injectabledetectseam keeps tests hermetic. A loud failure throws rather than silently falling to bun. Greenfield (norepoDir) keeps the unchanged FE-843 chain.Why?
Per-slice verification runs one target at a time, and that command is runner-specific (
bun testvsnpx vitest runvsnpx jestvsdeno test). The toolchain must be known at plan time -- the deterministic runner reads the stampedplan.profilewith no agent in the loop, so a wrong default runs the wrong command with no diagnostic. For an existing repo the manifest is the authoritative source; every other source is a guess or a manual step.D160-K-clean: profile-id resolution is an input to authoring, not architect host-introspection -- no amendment needed.
Tests
detectProfile: bun lockfile ->bun, deno config ->deno,package.jsondeps -> vitest/jest/none -> the matching node profile; ambiguous evidence (vitest and jest) and non-JS/unknown repos fail loud with a reason -- never a silent default.resolveEmittedProfile:detectedfronts the brownfield chain (over spec/architect/bun),--profilestill overrides, a loud detection failure throws rather than falling to bun, and greenfield (norepoDir) keeps the unchanged FE-843 chain. Injectabledetectseam keeps it hermetic.Review fixes (this revision)
package.jsondeclaring bothvitestandjestsilently picked vitest, violating the fail-loud-not-silent-default invariant (acceptance Dolt #4). It now returns a loud{detected:false}reason and defers to--profile.pyproject.toml/setup.py/go.modspecial-cases (+ theunsupportedhelper): they only renamed an error the catch-all already produces actionably -- the "language-detection framework" the design explicitly rejects. Non-JS repos still fail loudly via one actionable catch-all; only the per-stack naming is gone.Co-authored-by: Amp amp@ampcode.com