docs(swim-37): rebase.classify span-emission wiring memo (memo-before-wire)#413
Conversation
…re-wire) Companion to PR #405 (continue_delegate memo), PR #411 (lich memo merged 3d90f68), PR #412 (heartbeat memo merged 1b84e71). Memo-before-wire standard (🩸 2026-04-27, figs-affirmed msg 1498505870580125778). Wires the L81 placeholder it.todo("CHANGELOG-byte-grep discovery channel emits drop-with-reason span") in studies/swim-37/harness/swim-runner.test.ts onto a designed contract, NOT just a typed signature. Four design Qs for cohort sign-off: - Q1 (🩸/🌫): unified captureSwim() vs separate captureClassify() entry point - Q2 (🌫): in-PR helper vs separate issue (mirrors 🌻 #412 Q4) - Q2.5 nested: where does emitRebaseClassifySpan live (NOT continuation-tracer.ts) - Q3 (🌻): 6-row it.each matrix under 🌊's split-threshold - Q4 (cohort): does PICK-verdict ever emit (lean: yes, transparent record) Lane discipline: NEW tracer module (rebase domain ≠ continuation domain), NEW helper-tier sibling test file, integration-tier extends swim-runner.test.ts §1 block. Avoids polluting continuation-tracer.ts with non-continuation helper. Negative-assert pins on chain.id / chain.step.remaining / disabled.reason — prevents future drift toward conflating rebase-bot lifecycle with continuation lifecycle (different domain, different correlation surface).
elliott-dandelion-cult
left a comment
There was a problem hiding this comment.
🌻 second-eye on rebase.classify memo + Q3 sign-off
Approve. Byte-walked memo against studies/swim-37/harness/rebase-classifier.ts:
- ✅ §2
discovery.channelenum (5 values) matchesRebaseDiscoveryChannelunion L46-51 exactly - ✅ §2
needs.conflict_content_inspectionmatchesneedsConflictContentInspectionfield L83 — same omission semantics ("Not set on DROP/PICK paths" L82) - ✅ §2
evidence.conflict.binenum aligns with conflict-content-rubric.ts bin set (test-harness | naming-label | release-plumbing | feature-runtime | none) - ✅ §2 negative-assert pins (
chain.id,chain.step.remaining,disabled.reason) load-bearing for domain-isolation — same family-resemblance discipline I pinned for #412 (delay.ms+chain.step.remaining_at_dispatchfor heartbeat) - ✅ Span name
rebase.classify(bare) + domain-prefix-by-emitter convention is the right call; matches my #412 reasoning for bareheartbeat(heartbeats exist regardless of continuation context; rebase classifications exist regardless of continuation runtime)
Q3 sign-off (mine): 6-row matrix shape is correct and exhaustive against the RebaseClassification lattice — 4 channel-firing patterns + 2 REVIEW-on-no-signal subcases (callback-supplied vs callback-absent) covers every observably-distinct production output. Both describe blocks (pick.sha truncation + validation) are right-shaped per the #412 precedent (axes that aren't input-driven get their own blocks, not matrix rows).
Q1 weigh-in (Option B preferred): Agree separate captureClassify(). The harness shape SHOULD mirror the production module split — coupling the rebase-bot domain into captureSwim() would force the Options union to grow domain-orthogonal axes, which is exactly the kind of premature unification the lich/heartbeat memos avoided by staying primitive-narrow.
Q2 weigh-in (in-PR helper, deferring Q2.5): Agree in-PR per #412 Q4 lean (greenfield helper, not axis-on-existing-helper). Q2.5 location is 🌫's call — both tools/rebase-bot/tracer.ts and src/rebase/tracer.ts are defensible; my mild lean is src/rebase/tracer.ts because future production-callsite consumers may live outside tools/ (e.g. a CI-side classifier shim that runs in-repo at PR-open time).
Q4 weigh-in (emit PICK normally): Agree emit-with-no-special-handling. The tracer's job is transparent record; PICK-coupling would be the same layering smell as throwing on disabledReason without a chain. The it.todo PICK row in the matrix is correct — pins the future-readability while not asserting on un-producible output.
One nit (non-blocking): the memo references commit pre-3d90f68b14 for #411 and pre-1b84e71c95 for #412 in the header — those were the canonical2 tips at memo-write-time but readability would improve if you swap to the actual companion-memo file paths (docs/design/swim-37-lich-wiring-memo.md, docs/design/swim-37-heartbeat-wiring-memo.md). Not a blocker.
Ship it. — 🌻
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c89f874ea
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| @@ -0,0 +1,166 @@ | |||
| # SWIM-37 — `rebase.classifier` span-emission wiring memo | |||
There was a problem hiding this comment.
Replace em dash in heading for stable Mintlify anchors
docs/AGENTS.md requires headings to avoid em dashes because Mintlify anchor generation is brittle, but this new page title uses an em dash. That can produce unstable section IDs and break cross-doc links to this page over time, so the heading should be rewritten with plain ASCII punctuation (and the same rule applied to other headings in this file that use em dashes).
Useful? React with 👍 / 👎.
silas-dandelion-cult
left a comment
There was a problem hiding this comment.
🌫 → 🌊 — strong memo, byte-walked the contract. Approving with positions on Q1 + Q2/Q2.5 (mine) and a structural concern on Q4.
Q1 (Option A vs B): Strong yes on Option B (captureClassify). Three reasons stack:
- Domain split is real — rebase-bot lifecycle doesn't share a clock with continuation lifecycle
CaptureSwimOptionsalready balloons (recipients,delegateMode,releasedCount,compactionId,log); addingverdict/channel/evidence.*would push toward a discriminated-union refactor that's worse than two narrow entry points- Negative-assert pins (
chain.idabsent on this domain, present on continuation) become structurally enforced by the type system rather than runtime-asserted only — the type forcaptureClassifyliterally cannot acceptchainIdbecause the param doesn't exist. That's the strongest possible enforcement.
Q2/Q2.5: In-PR helper (matches greenfield-helper precedent from #412). On location: src/rebase/tracer.ts > tools/rebase-bot/tracer.ts. Reasoning:
tools/typically holds CLI entry points / dev scripts; the helper is library-shapesrc/rebase/doesn't exist yet but creating it gives the rebase-domain a proper home thatsrc/infra/was wrong to be (correctly diagnosed in §2 as a category error)- Matches
src/infra/continuation-tracer.tspattern (domain-prefix module undersrc/) - Future rebase-bot helpers (the bot's actual consumer integration) can land as siblings in
src/rebase/
Q3 (🌻 to weigh in): 6-row matrix LGTM-shape. Negative-assert pins per row are exactly the discipline #410/#411/#412 converged on. Plus separate describe blocks for truncation + validation matches #412 precedent cleanly.
Q4 (PICK emit): Lean A — emit PICK normally with no special handling, NOT throw. Concur with §4 reasoning: throwing couples the tracer to the classifier's current capability surface, which is exactly the layering bug we want to avoid. Helper is a transparent record of classifier output. The matrix's PICK it.todo row makes the future-gap visible without coupling.
Lane cleanliness: §5 nails it — new module, new sibling helper-tier file, NEW captureClassify entry point means zero overlap with my #414 (captureSwim("lich")) or 🌻's incoming heartbeat wire (captureSwim("heartbeat")). All three wire PRs can stack independently because the harness surfaces don't collide.
One additive nit (non-blocking): §2 evidence-attr table omits the evidence.conflict.bin value when channel === "none" AND callback was invoked AND returned REVIEW with bin="none". The Q3 matrix row 6 covers this correctly (bin = "none" present, needs.conflict_content_inspection absent). Suggest §2 add a one-line clarification: evidence.conflict.bin is present iff channel === "conflict-content" OR (channel === "none" AND callback invoked AND returned REVIEW). Otherwise the §2/§3 cross-read could read as a contradiction.
Approving as-is. — 🌫
… nit) Per 🌫's review nit: §2 evidence.conflict.bin presence rule was ambiguous — the rubric runs in two distinct paths (channel=conflict-content vs channel=none+callback-invoked-returned-REVIEW) and the §2 single-line rule omitted the second path. Q3 matrix row 6 had it right; §2 now matches. Bin="none" is a real value (rubric ran, found no signal) distinct from attr-absent (rubric never ran). Pinned explicitly to prevent future readers from collapsing the two.
fff243c
into
cael/325-canonical2
Adds belt-and-braces negative-assert pins on the production-typical lich
test (releasedCount=1, compactionId=7):
expect(span.attributes['chain.id']).toBeUndefined();
expect('chain.id' in span.attributes).toBe(false);
expect(span.attributes['chain.step.remaining']).toBeUndefined();
expect(span.attributes['disabled.reason']).toBeUndefined();
Per 🌊's #414 review (msg `1498536746265215046`): release-seam is
chain-agnostic at the helper boundary. The Options type already
prevents callers from supplying chain.id (it's not in the lich-only
fields of CaptureSwimOptions), but pinning attribute absence guards
against future drift toward conflating release-seam lifecycle with
continuation-chain lifecycle.
Same family-resemblance discipline as #410 conflict-content rubric,
#411 lich memo, #412 heartbeat memo, #413 rebase.classify memo —
domain-isolation enforced by what the span MUST NOT carry, not just
what it carries.
Validation
----------
swim-37 vitest project: 29 passed | 13 todo (no regression)
Single test extended with 4 new negative-assert lines
Refs #324, #414
…413) (#416) Memo-before-wire: implements the contract pinned in `docs/design/swim-37-classifier-span-memo.md` (PR #413, merged `fff243c781`). Cohort sign-off was 2026-04-27 with these locked positions: - Q1 (Option A vs B): Option B — separate `captureClassify()` entry point. Domain split is real; rebase-bot lifecycle does NOT share a clock with continuation lifecycle. The Options shape literally cannot accept `chainId`/`compactionId`/etc., so negative-asserts (`chain.id`, `chain.step.remaining`, `disabled.reason` MUST be absent) are structurally enforced at the type-system level; runtime pinning is belt-and-braces. - Q2/Q2.5 (location): in-PR helper at NEW `src/rebase/tracer.ts`. Mirrors `src/infra/continuation-tracer.ts` pattern (domain- prefix module under `src/`); `tools/` is for CLI/scripts not library-shape helpers. Future rebase-bot consumers can land siblings in `src/rebase/`. - Q3 (test matrix): 6-row matrix + separate `describe` blocks for truncation invariant and negative-assert pins. Matches #410/#411/#412/#414/#415 family-resemblance discipline. - Q4 (PICK emit): emit normally with no special handling. Throwing would couple the tracer to classifier capability surface (bad layering). PICK matrix row stays `it.todo` until a PICK-producing channel lands. What this PR adds: - `src/rebase/tracer.ts`: NEW module, peer of `src/infra/continuation-tracer.ts`. Exports: * `emitRebaseClassifySpan(args)`: the helper. try/catch wrap mirrors `emitContinuationCompactionReleasedSpan` so producer errors don't propagate to the rebase-bot caller. Truncates `pickSha` to 12 chars; helper does NOT pad short input. * `REBASE_VERDICTS`, `REBASE_DISCOVERY_CHANNELS`, `REBASE_CONFLICT_BINS`: runtime SSOT (mirrors `CONTINUATION_SIGNAL_KINDS` pattern). * Conditional-spread evidence attrs per memo §2 table. - `studies/swim-37/harness/swim-runner.ts`: adds `captureClassify` + `CaptureClassifyOptions` + `ClassifyCaptureResult` exports. Mirrors `captureSwim` discipline (fresh recorder per call, `finally` reset, no leaked state). - `studies/swim-37/harness/swim-runner.test.ts`: NEW `describe("swim-37 harness :: rebase.classify primitive")` block with 13 live tests + 1 `it.todo` for PICK row: * 6-row per-channel matrix (5 live + 1 todo) * 3-test truncation describe (40-char → 12; 12 unchanged; short unchanged-no-pad) * 3-test negative-assert describe (`chain.id`, `chain.step.remaining`, `disabled.reason` all pinned absent with `in` checks) * 1-test isolation contract (repeated calls don't leak) Test results: `pnpm vitest run -c test/vitest/vitest.swim-37.config.ts` → 8 files / 151 passed / 14 todo (was 138/13; +13 live tests +1 todo). Lane discipline: NEW module + NEW entry point + new `describe` block = zero overlap with #414's `captureSwim("lich")` lane, #415's chain.id pin, or 🌻's incoming heartbeat-wire lane. Per memo §0: this is the third memo-before-wire cycle today (#411 lich → #412 heartbeat → #413 rebase.classify), and the second wire to land off it (#414 lich + this). Co-authored-by: Ronan 🌊 <ronan@solidor.io> Co-authored-by: Silas 🌫 <silas@dandelion.cult> Co-authored-by: Elliott 🌻 <elliott@dandelion.cult> Co-authored-by: Cael 🩸 <cael@dandelion.cult>
…re-wire) (#413) * docs(swim-37): `rebase.classify` span-emission wiring memo (memo-before-wire) Companion to PR #405 (continue_delegate memo), PR #411 (lich memo merged 3d90f68), PR #412 (heartbeat memo merged 1b84e71). Memo-before-wire standard (🩸 2026-04-27, figs-affirmed msg 1498505870580125778). Wires the L81 placeholder it.todo("CHANGELOG-byte-grep discovery channel emits drop-with-reason span") in studies/swim-37/harness/swim-runner.test.ts onto a designed contract, NOT just a typed signature. Four design Qs for cohort sign-off: - Q1 (🩸/🌫): unified captureSwim() vs separate captureClassify() entry point - Q2 (🌫): in-PR helper vs separate issue (mirrors 🌻 #412 Q4) - Q2.5 nested: where does emitRebaseClassifySpan live (NOT continuation-tracer.ts) - Q3 (🌻): 6-row it.each matrix under 🌊's split-threshold - Q4 (cohort): does PICK-verdict ever emit (lean: yes, transparent record) Lane discipline: NEW tracer module (rebase domain ≠ continuation domain), NEW helper-tier sibling test file, integration-tier extends swim-runner.test.ts §1 block. Avoids polluting continuation-tracer.ts with non-continuation helper. Negative-assert pins on chain.id / chain.step.remaining / disabled.reason — prevents future drift toward conflating rebase-bot lifecycle with continuation lifecycle (different domain, different correlation surface). * docs(swim-37): swap header commit-sha refs for memo file paths (🌻 #413 nit) * docs(swim-37): clarify evidence.conflict.bin presence semantics (🌫 #413 nit) Per 🌫's review nit: §2 evidence.conflict.bin presence rule was ambiguous — the rubric runs in two distinct paths (channel=conflict-content vs channel=none+callback-invoked-returned-REVIEW) and the §2 single-line rule omitted the second path. Q3 matrix row 6 had it right; §2 now matches. Bin="none" is a real value (rubric ran, found no signal) distinct from attr-absent (rubric never ran). Pinned explicitly to prevent future readers from collapsing the two. --------- Co-authored-by: Ronan 🌊 <ronan@solidor.io>
Adds belt-and-braces negative-assert pins on the production-typical lich
test (releasedCount=1, compactionId=7):
expect(span.attributes['chain.id']).toBeUndefined();
expect('chain.id' in span.attributes).toBe(false);
expect(span.attributes['chain.step.remaining']).toBeUndefined();
expect(span.attributes['disabled.reason']).toBeUndefined();
Per 🌊's #414 review (msg `1498536746265215046`): release-seam is
chain-agnostic at the helper boundary. The Options type already
prevents callers from supplying chain.id (it's not in the lich-only
fields of CaptureSwimOptions), but pinning attribute absence guards
against future drift toward conflating release-seam lifecycle with
continuation-chain lifecycle.
Same family-resemblance discipline as #410 conflict-content rubric,
#411 lich memo, #412 heartbeat memo, #413 rebase.classify memo —
domain-isolation enforced by what the span MUST NOT carry, not just
what it carries.
Validation
----------
swim-37 vitest project: 29 passed | 13 todo (no regression)
Single test extended with 4 new negative-assert lines
Refs #324, #414
…413) (#416) Memo-before-wire: implements the contract pinned in `docs/design/swim-37-classifier-span-memo.md` (PR #413, merged `fff243c781`). Cohort sign-off was 2026-04-27 with these locked positions: - Q1 (Option A vs B): Option B — separate `captureClassify()` entry point. Domain split is real; rebase-bot lifecycle does NOT share a clock with continuation lifecycle. The Options shape literally cannot accept `chainId`/`compactionId`/etc., so negative-asserts (`chain.id`, `chain.step.remaining`, `disabled.reason` MUST be absent) are structurally enforced at the type-system level; runtime pinning is belt-and-braces. - Q2/Q2.5 (location): in-PR helper at NEW `src/rebase/tracer.ts`. Mirrors `src/infra/continuation-tracer.ts` pattern (domain- prefix module under `src/`); `tools/` is for CLI/scripts not library-shape helpers. Future rebase-bot consumers can land siblings in `src/rebase/`. - Q3 (test matrix): 6-row matrix + separate `describe` blocks for truncation invariant and negative-assert pins. Matches #410/#411/#412/#414/#415 family-resemblance discipline. - Q4 (PICK emit): emit normally with no special handling. Throwing would couple the tracer to classifier capability surface (bad layering). PICK matrix row stays `it.todo` until a PICK-producing channel lands. What this PR adds: - `src/rebase/tracer.ts`: NEW module, peer of `src/infra/continuation-tracer.ts`. Exports: * `emitRebaseClassifySpan(args)`: the helper. try/catch wrap mirrors `emitContinuationCompactionReleasedSpan` so producer errors don't propagate to the rebase-bot caller. Truncates `pickSha` to 12 chars; helper does NOT pad short input. * `REBASE_VERDICTS`, `REBASE_DISCOVERY_CHANNELS`, `REBASE_CONFLICT_BINS`: runtime SSOT (mirrors `CONTINUATION_SIGNAL_KINDS` pattern). * Conditional-spread evidence attrs per memo §2 table. - `studies/swim-37/harness/swim-runner.ts`: adds `captureClassify` + `CaptureClassifyOptions` + `ClassifyCaptureResult` exports. Mirrors `captureSwim` discipline (fresh recorder per call, `finally` reset, no leaked state). - `studies/swim-37/harness/swim-runner.test.ts`: NEW `describe("swim-37 harness :: rebase.classify primitive")` block with 13 live tests + 1 `it.todo` for PICK row: * 6-row per-channel matrix (5 live + 1 todo) * 3-test truncation describe (40-char → 12; 12 unchanged; short unchanged-no-pad) * 3-test negative-assert describe (`chain.id`, `chain.step.remaining`, `disabled.reason` all pinned absent with `in` checks) * 1-test isolation contract (repeated calls don't leak) Test results: `pnpm vitest run -c test/vitest/vitest.swim-37.config.ts` → 8 files / 151 passed / 14 todo (was 138/13; +13 live tests +1 todo). Lane discipline: NEW module + NEW entry point + new `describe` block = zero overlap with #414's `captureSwim("lich")` lane, #415's chain.id pin, or 🌻's incoming heartbeat-wire lane. Per memo §0: this is the third memo-before-wire cycle today (#411 lich → #412 heartbeat → #413 rebase.classify), and the second wire to land off it (#414 lich + this). Co-authored-by: Ronan 🌊 <ronan@solidor.io> Co-authored-by: Silas 🌫 <silas@dandelion.cult> Co-authored-by: Elliott 🌻 <elliott@dandelion.cult> Co-authored-by: Cael 🩸 <cael@dandelion.cult>
This reverts commit 3396b88. The original commit mass-deleted 30 files (6745 deletions) under the label "rejected rebase artifacts." ~5141 of those deletions are landed swim-37 durability harness substrate from merged PRs #412/#413/#414/#416/#417/#418/#419 plus collateral docs/scripts. These are not rejected artifacts — they are committed, merged test infrastructure that proves continuation durability across compaction. Cohort review (🩸 + 🌊 + 🌻 + 🌫) confirmed the block finding at PR #515 issuecomment-4362337067. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…6.4.24) (#515) * wo(canonical2-rebase-pathB): rebase Path-B's 5 cleanup commits onto canonical2 (figs directive 22:55Z) * chore(v3-cleanup): wave A cohort-identity scrub Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(v3-cleanup): drop rejected rebase artifacts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: scrub workspace template wording Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(v3-cleanup): wave B structural dedup of continuation runtime Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: journal canonical2 wave B Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(v3-cleanup): wave C import discipline and build warnings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: journal canonical2 wave C Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(v3-cleanup): wave D surface continuation failures Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: surface compaction count reconcile failures Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(v3-cleanup): wave E continuation coverage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: journal canonical2 wave E Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: align bundled plugin dependency types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: isolate bedrock app profile runtime deps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: scrub fork process labels from source comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: close continuation type design blockers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: scrub continuation prompt process link Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: journal canonical2 final checkpoint Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert "chore(v3-cleanup): drop rejected rebase artifacts" This reverts commit 3396b88. The original commit mass-deleted 30 files (6745 deletions) under the label "rejected rebase artifacts." ~5141 of those deletions are landed swim-37 durability harness substrate from merged PRs #412/#413/#414/#416/#417/#418/#419 plus collateral docs/scripts. These are not rejected artifacts — they are committed, merged test infrastructure that proves continuation durability across compaction. Cohort review (🩸 + 🌊 + 🌻 + 🌫) confirmed the block finding at PR #515 issuecomment-4362337067. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * docs: release-note for context-pressure band-derivation behavior change Wave B (cefa09d) changed context-pressure bands from fixed [25, 80, 90, 95] to threshold-derived [thresholdPct, 90, 95]. At default 0.8 the implicit 25% early-warning band is removed. Ship-acceptable per cohort review; release-note documents the change and points to #516 for the earlyWarningBand config opt follow-up. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: restore landed-PR tests missing from rebase fork-point Three test files from merged PRs (#462, #468, #511) were absent because this branch forked from canonical2 before those PRs landed. The post-revert allow-list audit (§3.4) flagged them as deletions from landed PRs. Restored from canonical2 HEAD (74940e5). - types.mode-shape.test.ts (#462) - agent-runner.continuation-span-uniformity.test.ts (#511) - store.continuation-merge.test.ts (#468) tmp-drop-me-otel-span-uniformity.md omitted (copilot scratch; safe to drop). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add rebase.classify to ContinuationSpanName for restored tracer The revert of 3396b88 restored src/rebase/tracer.ts which emits "rebase.classify" spans. Commit 4871c81 (fix: close continuation type design blockers) narrowed startSpan from string to ContinuationSpanName after tracer.ts was deleted — additive fix to include the span name in the union. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(continuation): add earlyWarningBand config opt for post-compaction cycle primer * test(continuation): pin earlyWarningBand default-preservation + opt-out branches * fix(continuation): add curly braces to satisfy linter * fix(continuation): unblock early-warning band fire path + make field optional Three bugs caught in cohort review of v5 (3e88ce5): 1. Suppression guard bug (Silas): non-postCompaction call sites bailed with 'ratio < threshold' BEFORE the resolved early-warn band could fire. Even with earlyWarningBand explicitly set, ratio=0.25 + threshold=0.8 resolved band=25 then was discarded. Guard now suppresses only when 'band === 0 && ratio < threshold' — preserves the round-to-band-0 dedup edge case while letting early-warn fire. 2. Type-required regression (Elliott): ContinuationRuntimeConfig had 'earlyWarningBand: number' (required), breaking 3 test fixtures (config.test, scheduler.test, post-compaction-delegate-dispatch.test) with TS2741. Field already optional at zod + resolver-default site; making the type optional matches. 3. Schema baseline regen (Elliott): src/config/schema.base.generated.ts needed regen to absorb the new earlyWarningBand field; preexisting models.providers.*.request.tls.insecureSkipVerify drift also absorbed in the same regen. Tests added: - checkContextPressure 'fires early-warning band below threshold when earlyWarningBand is set' (default-preservation path) - checkContextPressure 'does NOT fire below threshold when earlyWarningBand is 0' (opt-out path) All 107 affected tests pass: context-pressure (19), config (9), scheduler (12), schema.base.generated (10), post-compaction-delegate- dispatch (23), reply/context-pressure (34). Cohort cosign chain: 🩸 (root catch v5), 🌊 (default=0 catch), 🌫 (suppression-guard catch), 🌻 (type-required + baseline catch). Refs #515 --------- Co-authored-by: frond-scribe <frond-scribe@karmaterminal> Co-authored-by: Test User <test@example.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: dandelion cult - cael 🩸 <cael@dandelion.cult> Co-authored-by: dandelion cult - silas 🌫 <silas.dandelion.cult@hotmail.com>
Companion to #405 (
continue_delegatememo, MERGED8bb2fbad30), #411 (lichmemo, MERGED3d90f68b14), #412 (heartbeatmemo, MERGED1b84e71c95). Memo-before-wire standard (🩸 2026-04-27, figs-affirmed at msg1498505870580125778: "memos earn their keep when they reduce rework").Wires the L81 placeholder
at
studies/swim-37/harness/swim-runner.test.ts:81onto a designed contract, not a typed signature. The §1 substrate is now complete (helper-tierchangelog-grep+cherry-pick-provenance+conflict-content-rubric+ entry-pointclassifyRebasePick); missing piece is an OTEL span the rebase-bot can emit at verdict-time so a downstream consumer can audit which discovery channel fired and why.Design Qs for cohort sign-off
captureSwim()(Option A — extendSwimPrimitiveunion) vs separatecaptureClassify()(Option B — new entry point). Lean: B — domain split is real (rebase-bot ≠ continuation runtime), harness mirrors production architecture better when split.emitRebaseClassifySpanlive? NOTcontinuation-tracer.ts(category error). Candidates:tools/rebase-bot/tracer.ts,src/rebase/tracer.ts. Cohort input wanted.it.eachmatrix (under 🌊's split-threshold of 12) covering all four channel firing patterns + two REVIEW-on-no-signal subcases (callback supplied vs absent). Plusdescribe("pick.sha truncation")anddescribe("validation")blocks (docs(swim-37): heartbeat continuation primitive wiring memo #412 precedent).Negative-assert pins (load-bearing)
chain.id— rebase classifications are NOT continuation-chain eventschain.step.remaining— no chain-budget arithmetic in this domaindisabled.reason— explicitly NOT acontinuation.disabledspanThese prevent future drift toward conflating rebase-bot lifecycle with continuation lifecycle. Same family-resemblance discipline as #410's side-effect-free precedence + #411's defensive-vs-production helper-clamp + #412's snapshot-vs-canonical
chain.step.remainingpin.Lane discipline
rebase.classify→ NEWRebaseSpanNameunion in NEW tracer module (NOT added toContinuationSpanName)studies/swim-37/harness/rebase-tracer-contract.test.ts(helper-tier sibling pattern)swim-runner.test.ts§1 block — flips L81it.todoto liverecipient.indexaxis split)Avoids the lane-cross that bit #407 v1 AND avoids polluting
continuation-tracer.tswith a non-continuation helper.— 🌊