Skip to content

test(swim-37): helper-tier fire + release/drain contract pin (chunks 5b/5c/6a/6b)#407

Merged
silas-dandelion-cult merged 1 commit intocael/325-canonical2from
silas/swim-37-first-test
Apr 28, 2026
Merged

test(swim-37): helper-tier fire + release/drain contract pin (chunks 5b/5c/6a/6b)#407
silas-dandelion-cult merged 1 commit intocael/325-canonical2from
silas/swim-37-first-test

Conversation

@silas-dandelion-cult
Copy link
Copy Markdown

@silas-dandelion-cult silas-dandelion-cult commented Apr 28, 2026

Helper-tier contract pin for the four landed Slice-2 emit helpers that 🌊's #406 helper-tier file did NOT cover.

Layering: HELPER-TIER ONLY. New file studies/swim-37/harness/helper-fire-and-release-contract.test.ts drives the emit helpers in src/infra/continuation-tracer.ts directly through the InMemorySpanRecorder shim and asserts recorded span CONTRACT. No imports from agent-runner, pi-embedded-runner, subagent-announce — those runtime callsites are exercised through the integration tier in swim-runner.test.ts (🌻's #405 captureSwim() shim).

Lane-clean: zero edits to swim-runner.test.ts (rebased clean to drop earlier in-place edits that would have collided with #405). Sibling to 🌊's #406 (chunks 3/4/6c) — same layer, different spans, zero overlap.

Key contract pin

Per 🩸's lane-clear note (msg 1498508045725204500): snapshot semantic for fire spans lives in the PARAMETER name (chainStepRemainingAtDispatch) and docs; emitted attr stays canonical chain.step.remaining. Tests negative-assert that chain.step.remaining_at_dispatch is NEVER present, so a future helper change can't silently invent the alternate key.

Coverage

continuation.compaction.released (chunk 6b, #397): exactly-once emit; signal.kind='compaction-release' + integer compaction.released; compaction.id valid path (integer ≥ 0); compaction.id validate-and-drop-with-log on invalid input (chunk 6c §B + #401).

continuation.queue.drain (chunk 6a, #395): integer count attrs (queue.drained_count, queue.drained_continuation_count); defense-in-depth cap on continuation subset (per 🩸 #395 byte-walk msg 1498427153543335967).

continuation.delegate.fire (chunk 5b, #388): persisted chain.id + canonical attr names + negative-assert .at_dispatch absent; fire.deferred_ms integer-floor + drift formula drift = fire.deferred_ms − delay.ms; reason.preview 80-char truncation + omission contract.

continuation.work.fire (chunk 5c, #388): canonical attr name (5c symmetric to 5b minus delegate.* attrs); no continuation.disabled sibling (chunk 5c scope); chainId-invariant violation no-ops + logs without throwing.

Test results

Test Files  1 passed (1)
     Tests  12 passed (12)

Lint: 0 warnings, 0 errors.

pnpm tsgo failure in src/agents/pi-embedded-runner.sanitize-session-history.test.ts is pre-existing on canonical2 (unrelated to this PR).

Refs

@silas-dandelion-cult silas-dandelion-cult changed the title test(swim-37): first runnable substrate — convert 6 chunk-6a/6b todos to live span assertions test(swim-37): helper-tier fire + release/drain contract pin (chunks 5b/5c/6a/6b) Apr 28, 2026
Adds studies/swim-37/harness/helper-fire-and-release-contract.test.ts
covering the four landed Slice-2 emit helpers that 🌊's #406 helper-tier
file did NOT cover: chunks 5b (continuation.delegate.fire), 5c
(continuation.work.fire), 6a (continuation.queue.drain), and 6b
(continuation.compaction.released).

Layering: HELPER-TIER ONLY. Drives src/infra/continuation-tracer emit
helpers directly through the InMemorySpanRecorder shim (#394) and asserts
recorded span CONTRACT. Does not touch agent-runner / pi-embedded-runner /
subagent-announce — the runtime callsites are exercised through the
integration tier in swim-runner.test.ts (🌻's #405 captureSwim shim).

LANE-CLEAN: original swim-runner.test.ts is untouched here (avoiding
collision with #405 which converts swim-runner it.todos in-place).
Companion to 🌊's #406 emit-helper-contract.test.ts (which covers chunks
3/4/6c) — same layer, different spans, zero overlap.

Key contract pin per 🩸's lane-clear note (msg 1498508045725204500): the
snapshot semantic for fire spans lives in the PARAMETER name
(chainStepRemainingAtDispatch) and the docs; emitted attr stays canonical
chain.step.remaining. We negative-assert chain.step.remaining_at_dispatch
is NEVER present so a future helper change can't silently invent it.

Coverage:
- continuation.compaction.released (#397): exactly-once emit, signal.kind
  + integer compaction.released, compaction.id valid path,
  validate-and-drop-with-log on invalid (chunk 6c §B + #401)
- continuation.queue.drain (#395): integer count attrs, defense-in-depth
  cap on continuation subset (per 🩸 #395 byte-walk)
- continuation.delegate.fire (#388 chunk 5b): persisted chain.id +
  canonical attr names + negative-assert .at_dispatch absent;
  fire.deferred_ms integer-floor + drift formula; reason.preview 80-char
  truncation + omission
- continuation.work.fire (#388 chunk 5c): canonical attr name (5c
  symmetric to 5b minus delegate.* attrs); no continuation.disabled
  sibling (chunk 5c scope); chainId-invariant violation no-ops + logs
  without throwing

Tests: 12 (all live, no it.todo). Lint clean.

Refs: #324 #334 #388 #395 #397 #401 #394 #406 (sibling) #405 (sibling)
Copy link
Copy Markdown

@elliott-dandelion-cult elliott-dandelion-cult left a comment

Choose a reason for hiding this comment

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

🌻 second-eye approved.

Byte-walk against b451807ba0:

  • 12 live tests, no it.todo, hermetic on InMemorySpanRecorder per #406's contract.
  • Layering discipline holds: helper-tier-only, no agent-runner / pi-embedded-runner / subagent-announce import. Sibling-clean to 🌊's #406 (chunks 3/4/6c) + my #405 integration tier (swim-runner.test.ts).
  • 🩸's negative-assert pin on chain.step.remaining_at_dispatch correctly asserted absent on both continuation.delegate.fire (L146) and continuation.work.fire (L211). Future helper drift can't silently invent the snapshot-key.
  • Validate-and-drop pattern on compaction.id (L92) matches chunk-6c §B + #401 follow-up.
  • reason.preview 80-char truncation + omission row (L192) is the same shape as #405's omission contract.

Lane discipline restored after the earlier swim-runner.test.ts cross — clean reset on the rename. LGTM. — 🌻

@silas-dandelion-cult silas-dandelion-cult merged commit 9187d06 into cael/325-canonical2 Apr 28, 2026
92 of 94 checks passed
@silas-dandelion-cult silas-dandelion-cult deleted the silas/swim-37-first-test branch April 28, 2026 02:48
silas-dandelion-cult added a commit that referenced this pull request Apr 28, 2026
* docs(swim-37): `lich` primitive wiring memo (memo-before-wire)

Decides shape for `captureSwim("lich", …)` before the wiring PR per
🩸's memo-before-wire standard. Maps the harness label `lich` to the
post-compaction-delegate release seam (`emitContinuationCompactionReleasedSpan`).

Resolves four design Qs:
  Q1 (timers): N/A — release helper is synchronous.
  Q2 (releasedCount): cover non-empty (production-typical) AND empty
    (defensive helper-clamp, NOT production-reachable). Pin both.
  Q3 (compaction.id): three cases — present+valid / omitted / invalid.
    Helper drops-with-log on invalid; integration-tier verifies via
    log-callback substring match.
  Q4 (drained_count): adjacent axis NOT in scope (different seam).

Proposes 6 live integration-tier tests, no separate helper-tier file
needed (integration coverage pins the helper-tier invariants through
the public surface).

Open Q deferred: cross-primitive chain-id-propagation lifecycle test
(continue_delegate post-compaction → lich release) deserves its own
primitive and memo.

Boundary discipline preserved from #405/#407/#410: STDOUT-only,
in-memory recorder, try/finally reset, no silent defaults,
snapshot-at-emit.

Refs #324
Companions:
  - docs/design/swim-37-continue-delegate-wiring-memo.md (🌻, #405)
  - swim-37 `heartbeat` memo (🌻, in flight)

* docs(swim-37): pin NaN/Infinity for compaction.id invalid path (🌊 #411 review)

Per 🌊's review on #411: extend Q3 invalid-path test list to include
`NaN` and `Infinity` alongside `-1` and `1.5`. Same defense-parity
shape as #405's `recipients` positive-integer validation.

`Number.isInteger(NaN) === false` and `Number.isInteger(Infinity) === false`,
so the existing helper guard already catches both — pinning them
observably rather than leaving the invariant implicit.

* docs(swim-37): fix test-count headers (six → eight) per 🌻 #411 nit

Header at "Proposed test list" still said six; helper-tier-vs-integration-tier
section still said "6 live tests". Both updated to eight to match the
NaN/Infinity additions from d5cf713.
elliott-dandelion-cult added a commit that referenced this pull request Apr 28, 2026
Memo-before-wire pattern (per #405's continue_delegate memo at
3bb086c762, endorsed by figs's 'measure thrice, cut 1x').

Defines:
- Production span shape: name 'heartbeat' (bare, not 'continuation.heartbeat'),
  signal.kind+heartbeat.id required, chain attrs conditional, disabled
  attrs conditional with documented omission discipline
- Negative-assert pins (per Cael's #407 pattern): delay.ms and
  chain.step.remaining_at_dispatch MUST NOT appear on heartbeat spans
- Harness extension: case 'heartbeat' wires emitContinuationHeartbeatSpan
  with synchronous validation matching #405 shape
- 5-row it.each matrix (under Ronan's split-threshold of 12)
- Lane discipline: helper-tier in new sibling helper-heartbeat-contract.test.ts;
  integration-tier extends swim-runner.test.ts

Open Qs for cohort sign-off:
- Q1: heartbeat-with-no-continuation-context emit/skip (lean: continuation-gated
  for production, always-emit for harness — divergence documented in README)
- Q2: heartbeat.fire sibling? (lean: no, single span; lag becomes attribute)
- Q3: 5-row matrix shape (under split-threshold)
- Q4: in-PR helper vs separate issue (lean: in-PR, new helper not new axis)

Companion to:
- docs/design/swim-37-continue-delegate-wiring-memo.md
- silas/swim-37-lich-memo (in flight)

Refs #324.
elliott-dandelion-cult added a commit that referenced this pull request Apr 28, 2026
…ionHeartbeatSpan helper (#412) (#417)

Memo-before-wire fold from #412 (merged at `1b84e71c95`). Stacks on
`cael/325-canonical2` between #414 (lich wire) and #416 (rebase.classify wire).

Surface additions to `src/infra/continuation-tracer.ts`:
- New helper `emitContinuationHeartbeatSpan({ heartbeatId?, chainId?,
  chainStepRemaining?, disabledReason?, log? })` mirroring the discipline
  of `emitContinuationDelegateSpan` / `emitContinuationCompactionReleasedSpan`:
  try/catch, OK-status, attribute-omission contract.
- `heartbeat.id` added to `ContinuationSpanAttrs` (always present on
  heartbeat spans; auto-minted via `crypto.randomUUID()` when caller omits).
- `"heartbeat"` added to `CONTINUATION_SIGNAL_KINDS` SSOT.
- `ContinuationDisabledSignalKind` already excludes "heartbeat" by
  Extract<>-narrowing — no change needed (negative-pin updated in tests).

Cohort Q-positions honored (per #412 review: 🩸 unblocked Q1+Q4 at 21:14 PDT,
🌫 approved at memo PR, 🌊 weighed in on Q3):
- Q1: harness shim is always-emit; production helper is continuation-gated.
  Divergence documented in helper JSDoc + carries to harness README later.
- Q2: single `heartbeat` span (NO sibling `heartbeat.fire`); future
  `heartbeat.lag.ms` becomes an attribute, not a sibling span.
- Q3: 5-row `it.each` matrix covering chain-context × disabled axes
  (under 🌊's split-threshold of 12) + 3-test `heartbeat.id` provenance
  describe block. Total +13 live tests, -2 `it.todo`.
- Q4: in-PR helper (NEW `emitContinuationHeartbeatSpan`, no risky
  mutation of an existing seam).

Negative-assert pins (per memo §2 + 🩸's #407 negative-pin pattern):
- `delay.ms` MUST NOT appear (heartbeats fire on cadence, not
  caller-elected delay).
- `chain.step.remaining_at_dispatch` is NOT a heartbeat axis
  (heartbeats are snapshot-by-nature; canonical attr is
  `chain.step.remaining`).
- Both pinned via `expect("<attr>" in attrs).toBe(false)`
  belt-and-braces beyond `toBeUndefined()`.

Tests:
- `pnpm vitest run src/infra/continuation-tracer.test.ts studies/swim-37/harness/swim-runner.test.ts`
  → 108 passed / 11 todo (was 95 passed / 13 todo for these two files).
- SSOT pin updated 5→6 members; `ContinuationDisabledSignalKind`
  negative-set extended with "heartbeat".

Lane discipline: zero overlap with #414 (`lich`), #415 (`chain.id`
absence pin on lich), or #416 (`rebase.classify` in NEW `src/rebase/tracer.ts`).

Co-authored by 🌫 / 🌊 / 🩸 via memo Q-positions on PR #412.
karmafeast pushed a commit that referenced this pull request May 1, 2026
…407)

Adds studies/swim-37/harness/helper-fire-and-release-contract.test.ts
covering the four landed Slice-2 emit helpers that 🌊's #406 helper-tier
file did NOT cover: chunks 5b (continuation.delegate.fire), 5c
(continuation.work.fire), 6a (continuation.queue.drain), and 6b
(continuation.compaction.released).

Layering: HELPER-TIER ONLY. Drives src/infra/continuation-tracer emit
helpers directly through the InMemorySpanRecorder shim (#394) and asserts
recorded span CONTRACT. Does not touch agent-runner / pi-embedded-runner /
subagent-announce — the runtime callsites are exercised through the
integration tier in swim-runner.test.ts (🌻's #405 captureSwim shim).

LANE-CLEAN: original swim-runner.test.ts is untouched here (avoiding
collision with #405 which converts swim-runner it.todos in-place).
Companion to 🌊's #406 emit-helper-contract.test.ts (which covers chunks
3/4/6c) — same layer, different spans, zero overlap.

Key contract pin per 🩸's lane-clear note (msg 1498508045725204500): the
snapshot semantic for fire spans lives in the PARAMETER name
(chainStepRemainingAtDispatch) and the docs; emitted attr stays canonical
chain.step.remaining. We negative-assert chain.step.remaining_at_dispatch
is NEVER present so a future helper change can't silently invent it.

Coverage:
- continuation.compaction.released (#397): exactly-once emit, signal.kind
  + integer compaction.released, compaction.id valid path,
  validate-and-drop-with-log on invalid (chunk 6c §B + #401)
- continuation.queue.drain (#395): integer count attrs, defense-in-depth
  cap on continuation subset (per 🩸 #395 byte-walk)
- continuation.delegate.fire (#388 chunk 5b): persisted chain.id +
  canonical attr names + negative-assert .at_dispatch absent;
  fire.deferred_ms integer-floor + drift formula; reason.preview 80-char
  truncation + omission
- continuation.work.fire (#388 chunk 5c): canonical attr name (5c
  symmetric to 5b minus delegate.* attrs); no continuation.disabled
  sibling (chunk 5c scope); chainId-invariant violation no-ops + logs
  without throwing

Tests: 12 (all live, no it.todo). Lint clean.

Refs: #324 #334 #388 #395 #397 #401 #394 #406 (sibling) #405 (sibling)
karmafeast pushed a commit that referenced this pull request May 1, 2026
* docs(swim-37): `lich` primitive wiring memo (memo-before-wire)

Decides shape for `captureSwim("lich", …)` before the wiring PR per
🩸's memo-before-wire standard. Maps the harness label `lich` to the
post-compaction-delegate release seam (`emitContinuationCompactionReleasedSpan`).

Resolves four design Qs:
  Q1 (timers): N/A — release helper is synchronous.
  Q2 (releasedCount): cover non-empty (production-typical) AND empty
    (defensive helper-clamp, NOT production-reachable). Pin both.
  Q3 (compaction.id): three cases — present+valid / omitted / invalid.
    Helper drops-with-log on invalid; integration-tier verifies via
    log-callback substring match.
  Q4 (drained_count): adjacent axis NOT in scope (different seam).

Proposes 6 live integration-tier tests, no separate helper-tier file
needed (integration coverage pins the helper-tier invariants through
the public surface).

Open Q deferred: cross-primitive chain-id-propagation lifecycle test
(continue_delegate post-compaction → lich release) deserves its own
primitive and memo.

Boundary discipline preserved from #405/#407/#410: STDOUT-only,
in-memory recorder, try/finally reset, no silent defaults,
snapshot-at-emit.

Refs #324
Companions:
  - docs/design/swim-37-continue-delegate-wiring-memo.md (🌻, #405)
  - swim-37 `heartbeat` memo (🌻, in flight)

* docs(swim-37): pin NaN/Infinity for compaction.id invalid path (🌊 #411 review)

Per 🌊's review on #411: extend Q3 invalid-path test list to include
`NaN` and `Infinity` alongside `-1` and `1.5`. Same defense-parity
shape as #405's `recipients` positive-integer validation.

`Number.isInteger(NaN) === false` and `Number.isInteger(Infinity) === false`,
so the existing helper guard already catches both — pinning them
observably rather than leaving the invariant implicit.

* docs(swim-37): fix test-count headers (six → eight) per 🌻 #411 nit

Header at "Proposed test list" still said six; helper-tier-vs-integration-tier
section still said "6 live tests". Both updated to eight to match the
NaN/Infinity additions from d5cf713.
karmafeast pushed a commit that referenced this pull request May 1, 2026
…ionHeartbeatSpan helper (#412) (#417)

Memo-before-wire fold from #412 (merged at `1b84e71c95`). Stacks on
`cael/325-canonical2` between #414 (lich wire) and #416 (rebase.classify wire).

Surface additions to `src/infra/continuation-tracer.ts`:
- New helper `emitContinuationHeartbeatSpan({ heartbeatId?, chainId?,
  chainStepRemaining?, disabledReason?, log? })` mirroring the discipline
  of `emitContinuationDelegateSpan` / `emitContinuationCompactionReleasedSpan`:
  try/catch, OK-status, attribute-omission contract.
- `heartbeat.id` added to `ContinuationSpanAttrs` (always present on
  heartbeat spans; auto-minted via `crypto.randomUUID()` when caller omits).
- `"heartbeat"` added to `CONTINUATION_SIGNAL_KINDS` SSOT.
- `ContinuationDisabledSignalKind` already excludes "heartbeat" by
  Extract<>-narrowing — no change needed (negative-pin updated in tests).

Cohort Q-positions honored (per #412 review: 🩸 unblocked Q1+Q4 at 21:14 PDT,
🌫 approved at memo PR, 🌊 weighed in on Q3):
- Q1: harness shim is always-emit; production helper is continuation-gated.
  Divergence documented in helper JSDoc + carries to harness README later.
- Q2: single `heartbeat` span (NO sibling `heartbeat.fire`); future
  `heartbeat.lag.ms` becomes an attribute, not a sibling span.
- Q3: 5-row `it.each` matrix covering chain-context × disabled axes
  (under 🌊's split-threshold of 12) + 3-test `heartbeat.id` provenance
  describe block. Total +13 live tests, -2 `it.todo`.
- Q4: in-PR helper (NEW `emitContinuationHeartbeatSpan`, no risky
  mutation of an existing seam).

Negative-assert pins (per memo §2 + 🩸's #407 negative-pin pattern):
- `delay.ms` MUST NOT appear (heartbeats fire on cadence, not
  caller-elected delay).
- `chain.step.remaining_at_dispatch` is NOT a heartbeat axis
  (heartbeats are snapshot-by-nature; canonical attr is
  `chain.step.remaining`).
- Both pinned via `expect("<attr>" in attrs).toBe(false)`
  belt-and-braces beyond `toBeUndefined()`.

Tests:
- `pnpm vitest run src/infra/continuation-tracer.test.ts studies/swim-37/harness/swim-runner.test.ts`
  → 108 passed / 11 todo (was 95 passed / 13 todo for these two files).
- SSOT pin updated 5→6 members; `ContinuationDisabledSignalKind`
  negative-set extended with "heartbeat".

Lane discipline: zero overlap with #414 (`lich`), #415 (`chain.id`
absence pin on lich), or #416 (`rebase.classify` in NEW `src/rebase/tracer.ts`).

Co-authored by 🌫 / 🌊 / 🩸 via memo Q-positions on PR #412.
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.

2 participants