Skip to content

Commit 3890b32

Browse files
kostandinangclaude
andcommitted
FE-883: reconcile docs for the wired fold (TODO + SPEC I124-K)
- epic-sandbox-merge.ts: replace the now-resolved cook-artifact-lifecycle TODO with a note that brownfield folds (run-artifact.ts, wired) while mergeSlicesIntoEpicSandbox is the greenfield composer by design. - SPEC I124-K: amended to record the plan.mode fork β€” brownfield git merge-tree fold (verify == ship, fail-closed) vs greenfield file-copy union. - CARDS.md: 1b/1c done; 1d (retire dead promoteBrownfieldRun, blocked on the landCookBranch fixture rewrite) + a multi-slice end-to-end engine test remain. 🍳 Built with brunch Co-Authored-By: Opus 4.8 <noreply@anthropic.com>
1 parent a6241cf commit 3890b32

3 files changed

Lines changed: 24 additions & 23 deletions

File tree

β€Žmemory/CARDS.mdβ€Ž

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,22 @@ Status: **in progress.**
4141
composition path → the tree verified == the tree shipped; no verify≠ship gap on
4242
same-file edits. The worktree-checkout unknown is de-risked by materializeFoldedWorktree.
4343
44-
β—‹ 1b/1c INTEGRATION (remaining β€” engine wiring):
45-
- net-compiler.ts verify-epic (~870): for brownfield, replace mergeSlicesIntoEpicSandbox
46-
(file-copy) with commit-epic-slices (commitSliceWorktree, dep order + dep parents)
47-
+ materializeFoldedWorktree into __epic__/<epicId>/ + relink node_modules
48-
(linkSharedTopLevelEntries). Greenfield keeps the file-copy union. Fold conflict β†’
49-
fail the epic (first-class).
50-
- cook-cli.ts promotion (~567): brownfield branch calls harvestCookRun instead of
51-
promotionSourceDir + promoteBrownfieldRun; fold conflicts β†’ fatal run outcome
52-
(recordCookExitStatus(false)). I135-K preserved (all plumbing).
53-
- Needs an end-to-end runCook/engine integration test (none exists today for
54-
multi-slice brownfield promotion) β€” note this gap.
55-
56-
β—‹ 1d β€” delete the superseded file-copy composition (mergeSlicesIntoEpicSandbox /
57-
promoteBrownfieldRun once unused) + the stale epic-sandbox-merge.ts:226 TODO.
58-
Amends I124-K to fork on plan.mode (brownfield β†’ fold; greenfield β†’ file-copy union).
44+
βœ“ 1b/1c INTEGRATION (done, commit d92ce38b) β€” engine wired end-to-end:
45+
- net-compiler verify-epic: brownfield uses materializeEpicVerifyTree (commit
46+
slices dep-order β†’ fold β†’ detached worktree at __epic__/<epicId>/ β†’ relink
47+
node_modules); fold conflict β†’ fail the epic (passed:false report β†’ fail sibling).
48+
Greenfield keeps the file-copy union.
49+
- cook-cli promotion: brownfield calls harvestCookRun; fold conflicts β†’ fatal run
50+
outcome. I135-K preserved (all plumbing).
51+
- commitSliceWorktree made idempotent so promotion reuses the commits verify made.
52+
- Stale epic-sandbox-merge.ts TODO updated; SPEC I124-K amended (plan.mode fork).
53+
- Full orchestrator suite green (672). Single-slice brownfield-smoke exercises the
54+
engine plumbing; a *multi-slice* end-to-end engine test is still a gap to add.
55+
56+
β—‹ 1d (remaining) β€” retire the now-dead promoteBrownfieldRun + BrownfieldPromoteOptions.
57+
Blocked on rewriting the landCookBranch test fixture (repoWithPromotedCook uses
58+
promoteBrownfieldRun to build a promoted branch β€” rebuild it via harvestCookRun or
59+
a plain commit). mergeSlicesIntoEpicSandbox STAYS (it is the greenfield composer).
5960
```
6061

6162
### Acceptance Criteria (slice-level)

β€Žmemory/SPEC.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ Each invariant is a formalization candidate: the property is stated in human lan
269269
| I121-K | Both orchestrator engines (`proc` and `petri`) pass the same contract test suite with identical observable behavior. | contract tests with fake agents/runner | Requirements 46, 47; D155-K |
270270
| I122-K | Orchestrator event content lives in `reports.jsonl`; petri engine tokens carry only `{ reportId, sliceId, epicId }` pointers. Proc engine may pass data through normal function calls β€” the shared seam is inputs and outputs. | contract tests | Requirement 48; D156-K |
271271
| I123-K | Worktree isolation holds β€” fixture directory and source repo are never mutated by an orchestrator run; worktree is cwd-scoped at `<cwd>/.brunch/cook/runs/<runId>/worktree/`. Slice layout follows policy (D165-K): serial greenfield runs all slices in the single shared run tree (verify-epic in place, no `__epic__`); parallel greenfield and brownfield isolate per slice and merge into `__epic__/<epicId>/`. Brownfield clones the cwd repo and preserves the source repo's HEAD and tracked-file state byte-identically; greenfield never clones the source. | worktree.test.ts, brownfield-smoke.integration.test.ts, engine-contract.test.ts | Requirement 49; D159-K, D164-K, D165-K |
272-
| I124-K | Epic verification runs against a freshly-rebuilt `<parentSandboxDir>/__epic__/<epicId>/` dir holding the deterministic merge of its completed slices' worktrees (later slices in plan declaration order overwrite earlier ones on path collisions; collisions are reported via the `epic-sandbox-merged` event). Per-slice worktrees are not mutated by the merge. | epic-sandbox-merge.test.ts, engine-contract.test.ts | Requirement 49; D159-K |
272+
| I124-K | Epic verification runs against a freshly-rebuilt `<parentSandboxDir>/__epic__/<epicId>/` dir holding the merge of its completed slices' worktrees; per-slice worktrees are not mutated by the merge. **The composer forks on `plan.mode` (FE-883):** **brownfield** composes by a `git merge-tree` 3-way fold of committed per-slice branches in dependency order (slice commits carry their dependency commits as parents so dep-seeded files merge as edits, not add/add) β€” different-hunk edits to one file both survive, and a real conflict is **fail-closed** (the epic fails / promotion halts, not silent last-slice-wins). This is the *same* fold promotion ships, so the verified tree equals the shipped tree. **Greenfield** keeps the file-copy union (no common ancestor for a 3-way): later slices in declaration order win on path collisions, reported via the `epic-sandbox-merged` event. | epic-sandbox-merge.test.ts, run-artifact.test.ts, engine-contract.test.ts | Requirement 49; D159-K (FE-883) |
273273
| I125-K | Topology output-place candidates are fully declared in `HandlerDescriptor` via typed `Guard` predicates; `wireHandlers` introduces no new output places at fire time. Pure consumers can enumerate the reachable output-place set per transition from topology data alone via `enumerateCandidateOutputs(transition)`. Halt paths (budget exhaustion, verify-epic failure) and token transforms (reportId attach, retry/rework count propagation) remain runtime concerns and are explicitly not covered by this invariant. | topology.test.ts, engine-contract.test.ts | Requirements 46, 47, 48; D155-K (FE-747) |
274274
| I126-K | The cook evaluator observes, never produces: `evaluate-done` runs with read-only tools (`toolsForAction('evaluate-done') === 'read'`) so it cannot mutate the sandbox during evaluation, and per-slice `done` reflects real execution of the slice's verification targets β€” β‰₯1 target and every target passing via the shared `runVerification` seam (one `TestRunner`; `evaluate-done`, `verify-epic`, and the net `run-tests` path share it β€” FE-872 unification; `evaluateVerificationTargets` / private `runTest` deleted) β€” rather than an LLM verdict. | pi-actions.test.ts, engine-contract.test.ts, brownfield-smoke.integration.test.ts | Requirements 46–50; D161-K (FE-813) |
275275
| I127-K | Brunch's Petrinaut stream markings are count-only (`Marking = Record<PlaceId, number>`): the static reducer and the live bus produce per-place token counts in each firing's arc-scoped consume/produce delta (A99; `initialState` is the single full marking), with no `TokenColour[]` arm. The wire `NetDefinition` is plain-graph (no `colorId` or other SDCPN fields), so slice/colour identity has no wire carrier β€” identity fold only. The projected definition validates against the mirrored `brunchNetDefinitionSchema` under `.strict()`. | petrinaut-stream-export.test.ts (arc-scoped delta oracle + strict-schema validation), petrinaut-stream-bus.test.ts (replay-equivalence) | Requirement 48; D162-K, D163-K (FE-819) |

β€Žsrc/orchestrator/src/epic-sandbox-merge.tsβ€Ž

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,13 @@ function assertSliceWorktreePathAvailable(parentSandboxDir: string, sliceId: str
223223
* slice worktree β€” `git worktree add` would fail with "already exists." The
224224
* caller must remove the prior worktree first if re-seeding.
225225
*
226-
* TODO(cook-artifact-lifecycle follow-on, separate frontier): the slice branch
227-
* exists but is never committed to. After this lands, a future frontier should
228-
* add slice-completion commits, replace `mergeSlicesIntoEpicSandbox`'s file-copy
229-
* with a git merge of slice branches into an epic branch, and surface real
230-
* merge conflicts (today's file-copy is silent last-slice-wins). That work
231-
* earns the "discoverable cook artifact" criterion via `git merge brunch/run/<runId>`
232-
* promotion semantics.
226+
* Brownfield slice branches are now committed and folded by `run-artifact.ts`
227+
* (`commitSliceWorktree` + the `merge-tree` fold), wired into both verify-epic
228+
* and promotion (FE-883) β€” real conflicts surface fail-closed instead of the old
229+
* silent last-slice-wins. `mergeSlicesIntoEpicSandbox` below is the **greenfield**
230+
* composer only: greenfield slices share no common ancestor, so a 3-way merge has
231+
* no base to merge against and the file-copy union (declaration-order-wins,
232+
* collisions reported) is the right tool there.
233233
*/
234234
export function seedSliceFromParentWorktree(
235235
parentSandboxDir: string,

0 commit comments

Comments
Β (0)