diff --git a/Sources/Dev/2026-06-04-synthesis-layer-design-session-handoff-model-resolved.md b/Sources/Dev/2026-06-04-synthesis-layer-design-session-handoff-model-resolved.md new file mode 100644 index 0000000..0fb1b4c --- /dev/null +++ b/Sources/Dev/2026-06-04-synthesis-layer-design-session-handoff-model-resolved.md @@ -0,0 +1,54 @@ +--- +created: '2026-06-04' +path: Sources/Dev +project: synthesis-layer +tags: +- dispatch +- lovebug +- claude-code +- mcp +- automation +type: session-notes +--- + +Working session refining `synthesis-layer` from record-keeping draft toward a v3-executable plan (v3 of `petal-dispatch`). Goal: surface data-model and interface decisions now, since petal-dispatch's Phase 0 schema and read surface will be designed around them. These notes supersede parts of the original `synthesis-layer` draft; a full superseding project-plan is expected once the extraction contract (Open Item below) is settled. + +## Outcome + +Resolved the core handoff model. Five decisions locked; the extraction contract remains open and is the next work item. + +**1. Handoff is derived, not worker-emitted (Option B).** The worker stays dumb — one prompt, one response, exit. An *extractor* reads the worker's raw final output and produces a structured handoff. Rejected Option A (worker emits its own structured handoff event) as fragile: it makes journal correctness depend on a language model electing to emit well-formed output, the same "worker elects to signal" failure mode petal-dispatch Principle #5 rejects for completion. + +**2. This means there IS a per-step synthesizer in v1.** The original draft's "no synthesizer agent in Phase 1, synthesis layer is a pure read pattern" was only true under Option A. Under B, the extractor is a real (small, per-step) producer. The phase model splits cleanly: the per-step extractor exists from day one (one task's raw output → one structured handoff); the cumulative compression layer stays correctly deferred to Phase 2, still scale-triggered. "No synthesizer in v1" was a fiction that only held if the worker did the extractor's job for free. + +**3. One store, two tiers — not two stores.** Everything lives in the journal. Records carry a tier: `raw` (machine-emitted: stdout, spawns, exits, deltas — high-volume, never read in the hot path) vs `derived` (extractor-produced — the handoff, low-volume, what the harness actually reads). The handoff is the first `derived`-tier record type. The "report"/read surface is a query filtered to the `derived` tier. Kept as one store so derived records reconcile by construction (own `seq`, append-only, point back at the raw events they distilled) — avoids the second-source-of-truth / sync problem a separate store would create. + +**4. ID hierarchy, all `id` fields, never slugs.** Hard constraint: every identifier is an `id`. Hierarchy: `project_id` 1—