Skip to content

FE-879: Lazy per-slice cook worktrees and shared node_modules for brownfield#223

Open
kostandinang wants to merge 12 commits into
ka/fe-864-orchestrator-enhancementsfrom
ka/fe-879-lazy-cook-worktrees
Open

FE-879: Lazy per-slice cook worktrees and shared node_modules for brownfield#223
kostandinang wants to merge 12 commits into
ka/fe-864-orchestrator-enhancementsfrom
ka/fe-879-lazy-cook-worktrees

Conversation

@kostandinang

@kostandinang kostandinang commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Stack Context

Stacks on FE-864 (#212). Refines the brownfield per-slice worktree provisioning FE-755 introduced -- makes it lazy and shares node_modules -- without changing what cook produces. (brunch serve / FE-878 is what surfaced the startup cost.)

What?

  • Lazy provisioning -- slice-worktree creation moves out of the eager wireHandlers loop into resolveSliceCwd, via a new idempotent ensureSliceWorktree. A slice's worktree is materialized on first fire, so a run touching 2 of 8 slices pays for 2 worktrees, not 8. Rework re-fires are no-ops; provisioning is synchronous (execFileSync), so concurrent fires of distinct slices serialize on the JS thread -- no two git worktree add calls overlap under the parallel policy.
  • Shared node_modules -- each slice symlinks node_modules/ to the parent worktree's single copy instead of CoW-copying it per slice (SHAREABLE_TOP_LEVEL_ENTRIES). walkFiles already skips symlinks, so the shared tree is never re-walked during dependency seeding, merge, or promotion. Other gitignored dirs (dist/) still copy per slice.

Why?

In codebase mode the slice layout is always per-slice, and every slice's worktree was provisioned up front -- N git worktree add + N recursive node_modules CoW copies, paid synchronously before any slice fired (9 of each for an 8-slice plan). The per-slice node_modules copy dominates wall-clock.

Behavior / risk

Correctness-neutral: same worktrees on the same branches, just lazy; deps resolve through the symlink. Trade-off: build caches under node_modules (.cache, .vite) become shared across parallel slices -- fine for cook's transient runs; documented at the call site.

Tests

npm run verify green. New unit tests: slice node_modules is a symlink (not a copy), other gitignored content still copies, ensureSliceWorktree idempotent. Brownfield integration smoke unchanged.

kostandinang and others added 9 commits June 15, 2026 12:57
…ard queue

Co-authored-by: Claude <noreply@anthropic.com>
…t/deno profiles

Profiles are now data literals (path templates + argv template + conventions
prose) compiled into the unchanged Toolchain interface — adding a runtime is
one data entry. Registry invariants pinned enumerably across all profiles.

Co-authored-by: Claude <noreply@anthropic.com>
…d into plan.yaml

brunch plan gains --profile=<id> (validated via parseProfileId); the emitter
resolves the chain once and stamps the id on both the authored and fallback
plans, so cook always reads the profile the emitter used. resolveToolchain
now throws UnknownProfileError on a typo'd id instead of silently running
bun; absent stays lenient for hand-authored fixtures.

Co-authored-by: Claude <noreply@anthropic.com>
architectPlan's schema gains an optional profile enum (registry ids,
null when the spec is silent); the emitter chain becomes flag ≫ spec
profile ≫ architect-classified ≫ bun. A hallucinated profile fails the
schema parse and rides the existing deterministic fallback. D160-K
intact — classification reads projected spec prose only.

Queue exhausted: CARDS.md retired; PLAN frontier marked branch-complete.

Co-authored-by: Claude <noreply@anthropic.com>
Add the full-cook-orchestrator frontiers to memory/PLAN.md as a planning
baseline. Arc 1 (brunch-detect, harness-dep-install, app-runtime-probe,
integration-oracle, brownfield-promotion, brunch-ship + dogfood-spike) and
Arc 2 (interactive-recovery, intent-conformance-oracle, adaptive-replan),
plus the separate transformation-orchestrator line. Records the cook-time
grounding decision, the greenfield-protecting invariant, the kitchen-brigade
CLI surface, and the unpublished pi-thread coordination note.

Docs-only; downstream feature branches stack on this.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Categorize the pi harness as a dual-mode (elicit/execute) agent-extension
host: mode-neutral core + per-mode plugins. Cook capabilities are execute-mode
plugins; the existing interview is the elicit witness. Adds the
agent-extension-host frontier with the four abstracted-enough acceptance
criteria (mode-neutral core, two-consumer proof, open plugin seam, no
gold-plating), the execute-mode-plugin hooks on the dispatch-seam frontiers
(integration-oracle, interactive-recovery, adaptive-replan), and the Context
coordination note. It gates only the dispatch-seam frontiers; the
seam-independent infra is unaffected.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Move agent-extension-host from a parallel prerequisite track to the base
of the Arc-1 cook stack (2026-06-15 decision): every Arc-1 frontier now
stacks on it. Updated the arc-framing paragraph, the Next sequencing list
(promoted to step 1, renumbered 2-8), the frontier definition, and
brunch-detect's stacking note. Kept the honest framing that the logical
gate is still only integration-oracle, so basing the whole arc on it is a
deliberate stack-order coupling to the pi-harness-thread coordination.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Consultation against the cook harness surfaced two corrections, now folded
into the frontier definitions:

- brunch-detect: slice 1 (detectProfile / project-detect.ts) already landed
  as FE-871 — status updated from not-started; only slice 2 (wire `detected`
  into the emitter chain + greenfield-protection) remains. Restated as a
  plan-time profile-id resolver (not a language-detection engine) and added
  the D160-K boundary note: profile-id resolution is an input to authoring,
  not architect host-introspection, so no D160-K amendment is needed.

- harness-dep-install: the install *action* is agent-native (cook actions
  carry bash; FE-843 testConventions inject install prose per A98). Reframed
  from an "install verb" to dependency-delta capture + install/infra-vs-test
  failure classification — the two things bash install doesn't give for free.
  Dropped the now-redundant install criteria + install-verb unit tests.

- agent-extension-host: status updated to contract-landed (FE-867).
- interactive-recovery: noted the asking reuses the elicit/secondary-chat
  substrate (FE-716); the load-bearing work is resume from durable markings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…ames are phases

The kitchen-brigade naming (prep/recipe/taste/plate/serve) was an aspirational
command surface, but implementation revealed 4 of the 6 are internal pipeline
stages, not CLI verbs: detect runs inside `plan`; probe+oracle and promotion run
inside `cook`/`serve`. Only `serve` (FE-878) and the pre-existing `cook` adopted
brigade names; `plan` never became `recipe`. Reword the surface to: real commands
= plan/cook/serve; prep/recipe/taste/plate are phase labels.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

kostandinang commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@kostandinang kostandinang changed the base branch from ka/fe-878-brunch-serve to graphite-base/223 June 16, 2026 14:17
@kostandinang kostandinang changed the base branch from graphite-base/223 to ka/fe-878-brunch-serve June 16, 2026 14:19
@kostandinang kostandinang marked this pull request as ready for review June 16, 2026 15:00
@cursor

cursor Bot commented Jun 16, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Performance-focused brownfield cook hardening with tests and documented trade-off (shared tool caches under node_modules during parallel slices); same branches/worktrees, just lazier provisioning.

Overview
Lazy per-slice worktrees: Codebase mode no longer provisions every slice’s git worktree in wireHandlers. Provisioning moves to resolveSliceCwd via new ensureSliceWorktree (idempotent on rework; rejects slice ids that collide with existing parent paths that aren’t real cook worktrees).

Shared node_modules: After slice checkout, copyMissingTopLevelEntries can symlink named top-level dirs (today node_modules via SHAREABLE_TOP_LEVEL_ENTRIES) instead of CoW-copying; other gitignored dirs like dist/ still copy per slice.

Docs: memory/PLAN.md records cook-worktree-laziness (FE-879) as done and marks the prior over-copy / eager-seeding follow-on resolved.

Tests: Coverage for the node_modules symlink, non-node_modules CoW copy, and ensureSliceWorktree idempotency + collision errors.

Reviewed by Cursor Bugbot for commit 8c8b78b. Bugbot is set up for automated code reviews on this repo. Configure here.

kostandinang and others added 2 commits June 16, 2026 16:30
Brownfield cook provisioned every slice's git worktree eagerly in
wireHandlers — N `git worktree add` + N recursive node_modules CoW copies
paid synchronously at startup before any slice fired.

- Move slice-worktree creation into resolveSliceCwd via idempotent
  ensureSliceWorktree, so a slice's worktree is materialized on first fire.
  A run touching 2 of 8 slices pays for 2 worktrees, not 8. Synchronous
  provisioning serializes concurrent fires on the JS thread, so parallel-policy
  worktree adds never overlap.
- Symlink each slice's node_modules to the parent worktree's single copy
  instead of CoW-copying per slice (SHAREABLE_TOP_LEVEL_ENTRIES). walkFiles
  already skips symlinks, so the shared tree is never re-walked during dep
  seeding, merge, or promotion. Other gitignored dirs still copy per slice.

Correctness-neutral: same worktrees/branches, just lazy; deps resolve through
the symlink. npm run verify green; adds symlink + idempotency unit tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add the cook-worktree-laziness frontier definition (FE-879, done) and mark
the per-slice over-copy / eager-seeding optimization resolved — closing
cook-codebase-mode acceptance (8) and the sandcastle over-copy trigger.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@kostandinang kostandinang changed the base branch from ka/fe-878-brunch-serve to graphite-base/223 June 16, 2026 15:31
@kostandinang kostandinang force-pushed the ka/fe-879-lazy-cook-worktrees branch from 3c0fa64 to e35fa92 Compare June 16, 2026 15:31
@kostandinang kostandinang changed the base branch from graphite-base/223 to ka/fe-864-orchestrator-enhancements June 16, 2026 15:31

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e35fa92. Configure here.

Comment thread src/orchestrator/src/epic-sandbox-merge.ts
@kostandinang kostandinang changed the base branch from ka/fe-864-orchestrator-enhancements to graphite-base/223 June 16, 2026 23:44
ensureSliceWorktree early-returned on existsSync, bypassing the collision
guard in seedSliceFromParentWorktree. A slice id matching a tracked parent
path (e.g. `src`) resolved to the project source dir, which cook then adopted
as the slice sandbox — silently breaking per-slice isolation. Only treat an
existing path as provisioned when it is a real git worktree (own `.git`).

🍳 Built with brunch

Co-Authored-By: Opus 4.8 <noreply@anthropic.com>
@kostandinang kostandinang changed the base branch from graphite-base/223 to ka/fe-864-orchestrator-enhancements June 17, 2026 18:02
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.

1 participant