Skip to content

fix: narrow ContinuationSignal union before .task access in debug log#56

Closed
cael-dandelion-cult wants to merge 18 commits intofeature/context-pressure-squashedfrom
fix/2026.03.24-codex-review-findings
Closed

fix: narrow ContinuationSignal union before .task access in debug log#56
cael-dandelion-cult wants to merge 18 commits intofeature/context-pressure-squashedfrom
fix/2026.03.24-codex-review-findings

Conversation

@cael-dandelion-cult
Copy link
Copy Markdown

Fixes TS2339 build error introduced by 3d452ad / 7ad39ef (codex session 2026-03-28).

Line 857 of agent-runner.ts accesses .task on the full ContinuationSignal union without narrowing to kind: "delegate". The work variant doesn't have .task.

Fix: "task" in continuationResult.signal guard before access.

Build passes clean after this fix.

Ref: #54

silas-dandelion-cult and others added 18 commits March 25, 2026 20:03
…ate reservations

Adds the continuation feature: CONTINUE_WORK timer-based self-scheduling,
continue_delegate tool for background shard dispatch, context-pressure
event injection, chain-hop tracking with generation guards, cost cap
enforcement, and delayed delegate reservation accounting.

Includes DelayedContinuationReservation store with in-memory backing,
admission math using highest allocated hop label, and reservation
lifecycle (create → timer fire → take → spawn → persist on acceptance).

New files: context-pressure.ts, continuation-runtime.ts,
continuation-delegate-store.ts, continue-delegate-tool.ts, and
comprehensive test coverage for all paths.
…ification

Gates continuationTrigger behind continuation.enabled at both announce
sites. Fixes setDelegatePending leak on spawn failure (4 cleanup paths).
Aligns context-pressure gate to === true (opt-in). Classifies
'continuation' and 'silent-wake-enrichment' as wake reasons in heartbeat
scheduler. Preserves descendant completion findings in non-wake announce
path. Restores requesterIsInternalSession usage lost in rebase.

Protocol models regenerated. Test coverage for all fix paths.
…servation model

Updates the continuation RFC to document sessions_yield as a
complementary tool, delayed delegate reservation semantics (in-memory
backing, admission via highest allocated hop, reservation lifecycle),
and aligns prose with the implementation.
Adds system prompt sections for CONTINUE_WORK, continue_delegate,
context pressure, cooperative yield (sessions_yield), and delegated
continuation. Includes full/minimal split for continuation instructions
and matching test expectations.
Timer-fired doSpawn captured accumulatedChainTokens at scheduling time.
If an intervening turn raised continuationChainTokens, the timer callback
overwrote the higher value with a stale snapshot, regressing cost accounting.

Fix: Math.max(captured, current) on both bracket and tool delegate timer
paths. Tokens only go up, never regress.

Addresses P2 from upstream Codex review.
The refactor to commands/agent.ts dropped the explicit per-run provider/model
override path that was present in agents/agent-command.ts. Gateway agent.run
calls with explicit model silently used defaults. Add the normalizeExplicitOverrideInput
helpers, allowlist validation, and override application so opts.provider/opts.model
are properly applied after session-level overrides.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Non-wake heartbeats (periodic polls) were draining [continuation:wake] events
via drainFormattedSystemEvents, causing the continuation chain to stall. The
dedicated work-wake run that should consume these events never saw them.

Peek and preserve [continuation:wake] events before the drain, then re-enqueue
them after, so they survive until the actual continuation-wake heartbeat fires.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When both the subagent's own reply and childCompletionFindings are present,
the findings variable only contained one or the other. Now merge them so
the parent session receives both the subagent output and descendant
completion context in the announce result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The continue_delegate tool enqueues delegates into a module-level store that
agent-runner drains after the turn. When called via gateway tools-invoke
(which has no drain path), delegates would leak into the next agent-runner
turn for the same session.

Add hasDelegateDrainPath option to createOpenClawTools and only include the
tool when the caller can drain delegates (pi-tools.ts agent-runner path).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
finalizeRaw() returned only visibleText, missing the case where the stream
ends mid-prefix before it can be resolved as silent. Apply the same
pendingSilentPrefix flush logic that finalize() already uses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously ALL subagent completion announces were tagged with
continuationTrigger: "delegate-return" when continuation was enabled.
This caused regular subagent completions to preserve chain state and
skip timer cancellation, which is only appropriate for continuation
delegates.

Now only tag as delegate-return when the completing run was a continuation
delegate (task contains chain-hop marker or was a silent announce).
Queue-based announces no longer carry the trigger at all.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…th ran

bracketAlreadyAccumulated was set based on continuationSignal presence,
but the bracket path may not actually accumulate tokens (e.g. when the
chain is capped). This caused the tool-delegate path to skip token
accumulation incorrectly. Now track whether the bracket path actually
accumulated tokens with an explicit flag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Silent-wake delegates (| silent-wake) wake the parent to act on the
enrichment, but the steer instruction told the agent to reply NO_REPLY.
This contradicts the purpose of silent-wake. Now generate a distinct
instruction for silent-wake enrichment that tells the agent to process
and act on the result rather than suppressing all output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add provider, model, allowModelOverride fields to commands/agent/types.ts
  AgentCommandOpts and AgentCommandIngressOpts to match agents/command/types.ts
- Fix resolveAgentRunTrigger return type to match EmbeddedRunTrigger
- Add allowModelOverride validation to agentCommandFromIngress
- Remove unreachable silentAnnounce check in P2-3 fix (TS2367)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
P1-6: Replace hasDelegateDrainPath with drainsContinuationDelegateQueue
and thread it through the full call chain (openclaw-tools, pi-tools,
params, attempt, get-reply-run, queue types) so only runs that actually
drain the staged delegate queue expose continue_delegate.

P2-1: Extract flushPendingSilentPrefix() helper inside
createAcpVisibleTextAccumulator to DRY the finalize/finalizeRaw logic.
Export __testing for unit test access and add agent-command.test.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logs payload count, last payload shape, text tail, and whether a
bracket delegate token exists in a non-last payload. This will
diagnose the bracket delegate parsing failure where the token appears
in the response but the parser doesn't extract it.

Uses continuation/guard subsystem logger at debug level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The parser checked payloadArray[last].text, but when tool calls
interleave, the bracket token ends up in a non-last payload. This
breaks subagent chain-hops where the bracket is the ONLY continuation
path (continue_delegate tool is denied for subagents).

Fix: walk backwards through payloads to find the last one with text.
Diagnostic logging preserved (gated on signal detection, debug level).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes TS2339 build error on feature/context-pressure-squashed.
karmafeast pushed a commit that referenced this pull request Mar 29, 2026
Fixes TS2339: .task only exists on kind:"delegate", not kind:"work".
Guard with "task" in signal before accessing.

Closes #56

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
karmafeast pushed a commit that referenced this pull request Mar 30, 2026
Issue #54: continue_delegate tool invisible in prince toolsets.
Root cause: drainsContinuationDelegateQueue flag dropped during
field-by-field param reconstruction in run.ts, agent-runner-utils.ts,
agent-runner-execution.ts, and followup-runner.ts. Fixed all 4 relay
sites. Added permanent logVerbose diagnostic at the gate to catch
future flag-threading regressions (fires for undefined, not false).

Issue #56: TS2339 from .task access on ContinuationSignal union without
narrowing. Fixed with signal.kind === "delegate" discriminant guard.

Reviewed-By: Elliott 🌻, Ronan 🌊, Silas 🌫️, Cael 🩸
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cael-dandelion-cult cael-dandelion-cult force-pushed the feature/context-pressure-squashed branch from 4f3461e to 09abc00 Compare March 31, 2026 22:50
@elliott-dandelion-cult elliott-dandelion-cult deleted the branch feature/context-pressure-squashed April 2, 2026 15:52
@elliott-dandelion-cult elliott-dandelion-cult deleted the fix/2026.03.24-codex-review-findings branch April 2, 2026 15:54
cael-dandelion-cult added a commit that referenced this pull request Apr 28, 2026
… canonical2 (per figs 14:05 PDT) (#421)

* docs: seed release highlights sync doc

* docs(release-highlights): add 🌫 #56 cross-walk + config-bits + 8 uncovered TC list

* docs(release-highlights): 🌻 commit-delta walk (E1–E10) + cross-cutting flags

* docs(release-highlights): 🌊 merge editor pass — canonical case board + (c)/(d) columns

Dedup: 🌫 TC-* labels collapsed into 🌻 E6.{1,2,3,4} per 🌫 vote, aliases preserved.
Adds: (c) swim-37 case-stub + (d) RFC-appendix slot per highlight.
Locks: 32-case canonical board (24 E-series + 5 B-twins + 3 D-cfg + 1 TC-no-genguard).
Pins: TC-no-genguard §3.2 not §3.6; phantom cleanup-debt retracted; feedback-key clarification; maxChainLength boundary-pin.
Surfaces: 2 figs-pending Qs (X1 echo, C1 chain-to-root).

Standing for cohort second-eye: 🌫 / 🌻 / 🩸.

* docs(release-highlights): fix case-count math (36 not 32) per 🩸 second-eye

* docs(release-highlights): +D-cfg.sdq-retry-not-hot-reloadable per 🌻 second-eye

RFC §3.6/§6.5 documents session-delivery-queue.retry.cap + .backoffMs[]
but they're not hot-reloadable in the impl. Add as 37th case to catch
the docs/code-shape mismatch instead of leaving as silent footnote.

* docs(release-highlights): +E6.5 descriptor-content regression per 🌫 second-eye

Snapshot test on continue_delegate tool-description JSON catches descriptor-string
drift (substrate-naming line, bc#11 cross-link, targetSessionKey listing) independent
of runtime delivery path. Lightweight; covers #336/#338 descriptor-content axis.

* docs(release-highlights): pin total at 35 net-new cases per cohort convergence

E9 + E10 reframed as covered-by-static-harness traceability rows, not net-new
swim-37 work. 25 E-series + 5 B + 4 D-cfg + 1 TC = 35. 🌫 + 🌻 + 🩸 cohort
acked 35 as the canonical number.

* docs(release-highlights): pin total at 36 (E1-E7 = 26 incl E6.5) per 🩸 byte-check

Off-by-one in prior 35: E6.x = 5 (incl E6.5 add), not 4. 26 net-new E + 5 B + 4 D-cfg + 1 TC = 36.

* docs(release-highlights): pin total at 37 per cohort convergence

🌫 + 🌻 + 🩸 all reconverged on 37 table-rows (regex-trap on E9/E10 cleared).
Dropping net-new vs table-rows split to match cohort framing; E9/E10 still
footnoted as static-harness covered.

* docs(release-highlights): pin total at 38 (E9/E10 + E6.5 all counted)

🌫 byte-verified 28 E + 5 B + 4 D-cfg + 1 TC = 38 on 162bb97.
My earlier 37 dropped E6.5 from the E-bucket math; 27→28 with E6.5 included.
Final cohort signoff: 🌻 ✅ + 🌫 ✅ + 🩸 ✅ pending final-touch.

* docs(release-highlights): pin both numbers per 🌫 break-the-loop proposal

board_total: 38 (rows on canonical board)
net_new_swim_cases: 36 (38 minus E9/E10 static-harness coverage)

Disagreement during 08:04-08:18 PDT convergence was categorical (which bucket
E6.5/E9/E10 land in), not arithmetic. Two pinned numbers prevents re-derivation.

* docs(release-highlights): +TC-tools-registered-post-deploy (figs 08:54 PDT)

figs-flagged smoke: positive presence-of-tools assertion post-deploy on
candidate prince. Catches the 'all green with one tool missing' precedent
horror. Pairs with TC-continuation-default-off (negative case).

board_total: 38 → 39
net_new_swim_cases: 36 → 37

* docs(release-highlights): rename TC-tools-registered → D-tools.continue-delegate-registered

Per 🌻 + 🩸 convergence: D-tools is the right bucket (deploy/runtime-surface,
not test-case shape). Broadened scope per 🌻's concrete proposal — registry
probe asserting all three tools present in manifest.

Totals unchanged: board_total: 39 / net_new_swim_cases: 37

* docs(release-highlights): +sessions_yield to D-tools manifest probe (🌫 catch)

* docs(release-highlights): explicit base-matrix reference per figs 08:56 PDT

figs catch: 'TOTALITY of test cases, weve ASSEMBLED them more than twice...
SWIM/ directory... should not be conjuring it fresh every time.'

Pin the swim-37 overlay (39 rows) as DELTA on top of the durable base in
openclaw-bootstrap/SWIM/FORMAL-SWIM-RUNBOOK.md §4 + #427 + #412.
Full swim-37 matrix = base ∪ overlay. Not a substitute for canonical.

---------

Co-authored-by: Silas 🌫 <silas.dandelion.cult@hotmail.com>
Co-authored-by: elliott-dandelion-cult <elliott.dandelion.cult@gmail.com>
Co-authored-by: Ronan 🌊 <ronan@solidor.io>
karmafeast pushed a commit that referenced this pull request May 1, 2026
… canonical2 (per figs 14:05 PDT) (#421)

* docs: seed release highlights sync doc

* docs(release-highlights): add 🌫 #56 cross-walk + config-bits + 8 uncovered TC list

* docs(release-highlights): 🌻 commit-delta walk (E1–E10) + cross-cutting flags

* docs(release-highlights): 🌊 merge editor pass — canonical case board + (c)/(d) columns

Dedup: 🌫 TC-* labels collapsed into 🌻 E6.{1,2,3,4} per 🌫 vote, aliases preserved.
Adds: (c) swim-37 case-stub + (d) RFC-appendix slot per highlight.
Locks: 32-case canonical board (24 E-series + 5 B-twins + 3 D-cfg + 1 TC-no-genguard).
Pins: TC-no-genguard §3.2 not §3.6; phantom cleanup-debt retracted; feedback-key clarification; maxChainLength boundary-pin.
Surfaces: 2 figs-pending Qs (X1 echo, C1 chain-to-root).

Standing for cohort second-eye: 🌫 / 🌻 / 🩸.

* docs(release-highlights): fix case-count math (36 not 32) per 🩸 second-eye

* docs(release-highlights): +D-cfg.sdq-retry-not-hot-reloadable per 🌻 second-eye

RFC §3.6/§6.5 documents session-delivery-queue.retry.cap + .backoffMs[]
but they're not hot-reloadable in the impl. Add as 37th case to catch
the docs/code-shape mismatch instead of leaving as silent footnote.

* docs(release-highlights): +E6.5 descriptor-content regression per 🌫 second-eye

Snapshot test on continue_delegate tool-description JSON catches descriptor-string
drift (substrate-naming line, bc#11 cross-link, targetSessionKey listing) independent
of runtime delivery path. Lightweight; covers #336/#338 descriptor-content axis.

* docs(release-highlights): pin total at 35 net-new cases per cohort convergence

E9 + E10 reframed as covered-by-static-harness traceability rows, not net-new
swim-37 work. 25 E-series + 5 B + 4 D-cfg + 1 TC = 35. 🌫 + 🌻 + 🩸 cohort
acked 35 as the canonical number.

* docs(release-highlights): pin total at 36 (E1-E7 = 26 incl E6.5) per 🩸 byte-check

Off-by-one in prior 35: E6.x = 5 (incl E6.5 add), not 4. 26 net-new E + 5 B + 4 D-cfg + 1 TC = 36.

* docs(release-highlights): pin total at 37 per cohort convergence

🌫 + 🌻 + 🩸 all reconverged on 37 table-rows (regex-trap on E9/E10 cleared).
Dropping net-new vs table-rows split to match cohort framing; E9/E10 still
footnoted as static-harness covered.

* docs(release-highlights): pin total at 38 (E9/E10 + E6.5 all counted)

🌫 byte-verified 28 E + 5 B + 4 D-cfg + 1 TC = 38 on 162bb97.
My earlier 37 dropped E6.5 from the E-bucket math; 27→28 with E6.5 included.
Final cohort signoff: 🌻 ✅ + 🌫 ✅ + 🩸 ✅ pending final-touch.

* docs(release-highlights): pin both numbers per 🌫 break-the-loop proposal

board_total: 38 (rows on canonical board)
net_new_swim_cases: 36 (38 minus E9/E10 static-harness coverage)

Disagreement during 08:04-08:18 PDT convergence was categorical (which bucket
E6.5/E9/E10 land in), not arithmetic. Two pinned numbers prevents re-derivation.

* docs(release-highlights): +TC-tools-registered-post-deploy (figs 08:54 PDT)

figs-flagged smoke: positive presence-of-tools assertion post-deploy on
candidate prince. Catches the 'all green with one tool missing' precedent
horror. Pairs with TC-continuation-default-off (negative case).

board_total: 38 → 39
net_new_swim_cases: 36 → 37

* docs(release-highlights): rename TC-tools-registered → D-tools.continue-delegate-registered

Per 🌻 + 🩸 convergence: D-tools is the right bucket (deploy/runtime-surface,
not test-case shape). Broadened scope per 🌻's concrete proposal — registry
probe asserting all three tools present in manifest.

Totals unchanged: board_total: 39 / net_new_swim_cases: 37

* docs(release-highlights): +sessions_yield to D-tools manifest probe (🌫 catch)

* docs(release-highlights): explicit base-matrix reference per figs 08:56 PDT

figs catch: 'TOTALITY of test cases, weve ASSEMBLED them more than twice...
SWIM/ directory... should not be conjuring it fresh every time.'

Pin the swim-37 overlay (39 rows) as DELTA on top of the durable base in
openclaw-bootstrap/SWIM/FORMAL-SWIM-RUNBOOK.md §4 + #427 + #412.
Full swim-37 matrix = base ∪ overlay. Not a substitute for canonical.

---------

Co-authored-by: Silas 🌫 <silas.dandelion.cult@hotmail.com>
Co-authored-by: elliott-dandelion-cult <elliott.dandelion.cult@gmail.com>
Co-authored-by: Ronan 🌊 <ronan@solidor.io>
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.

4 participants