Skip to content

fix: preserve post-compaction delegate arm age#488

Merged
ronan-dandelion-cult merged 1 commit intocael/325-canonical2from
frond-scribe/swim39-823-post-compaction-ttl-restart-load
May 1, 2026
Merged

fix: preserve post-compaction delegate arm age#488
ronan-dandelion-cult merged 1 commit intocael/325-canonical2from
frond-scribe/swim39-823-post-compaction-ttl-restart-load

Conversation

@karmafeast
Copy link
Copy Markdown

Summary

Fixes openclaw-bootstrap#823 by preserving stable post-compaction delegate arm age and dropping stale shards before they can be queued into the fresh session.

Root cause

The TaskFlow-backed post-compaction adapter preserved shard bodies, but the legacy compatibility wrapper converted consumed staged delegates back into SessionPostCompactionDelegate with createdAt: Date.now(). That erased the original arm time whenever a shard crossed the TaskFlow/restart/re-stage boundary, making stale 10-day-old tasks look freshly armed and preventing age/TTL filtering.

Fix

  • Add firstArmedAt to post-compaction delegate state and preserve it through TaskFlow state, session-store delegates, and queued delivery payloads.
  • Rehydrate wrapper-consumed staged delegates with createdAt/firstArmedAt from the original arm time instead of consume time.
  • Normalize legacy delegates by treating createdAt as firstArmedAt.
  • Drop post-compaction delegates older than 7 days by firstArmedAt, with an explicit stale-drop log containing age, TTL, and task preview.
  • Keep queue idempotency keyed to stable arm age so requeues do not mint fresh identity solely from rewrite time.

Validation

  • pnpm test src/auto-reply/continuation/delegate-store.test.ts src/auto-reply/continuation-delegate-store.post-compaction-substrate.test.ts src/auto-reply/reply/post-compaction-delegate-dispatch.test.ts src/infra/session-delivery-queue.storage.test.ts
  • pnpm tsgo:core
  • pnpm tsgo:core:test
  • pnpm lint

pnpm check:changed expands to all lanes from canonical baseline unknown .agents surfaces and fails in existing extension typecheck baselines (extensions/codex duplicate @mariozechner/pi-agent-core identities and extensions/qqbot zod v3/v4 mismatch), unrelated to this delegate persistence/TTL fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@cael-dandelion-cult cael-dandelion-cult force-pushed the frond-scribe/swim39-823-post-compaction-ttl-restart-load branch from c657fa9 to 0cd516a Compare May 1, 2026 13:47
silas-dandelion-cult added a commit that referenced this pull request May 1, 2026
…tion-registration to absorb cold module-load cost

The first test in src/agents/openclaw-tools.continuation-registration.test.ts
("registers no continuation tools when continuation.enabled is unset") pays
the cold module-load cost for createOpenClawTools and its transitive imports
(compaction-attribution, pi-embedded-*, plugins/tools, config/config) under
400+ concurrent test files in the agent project.

Quiet-box first-test duration: ~95s. CI noise pushes it past vitest's 120s
per-test default, producing a flaky timeout that has now been observed across
multiple unrelated PRs:

- #485 head (compaction-attribution scope) — first-test timeout
- #488 (downstream of #485 hypothesis) — first-test timeout
- #468 head (does NOT touch this file) — same first-test, same file, timeout

Test file content is byte-identical between base cael/325-canonical2 and #485
head; the timeout is not a regression introduced by any of those PRs. Tests
2-7 in this file reuse the warm cache (~360ms each) and are unaffected.

Cure: per-test timeout bump to 240s on the first test only, with a comment
documenting the cold-start mechanism so future readers know why this single
test has a non-default timeout.

Standalone fix, deliberately not folded into #485 to keep its compaction-
attribution scope clean. Unblocks #485, #488, #468, and any future PR that
randomly trips the same flake.

Verified by silas-pr485-fixup-v2 subagent (2026-05-01 07:29 UTC):
- Local on base a3dcc2a: first test 95023ms, passed (25s margin to 120s)
- CI on #485 head 9f25f91: first test >120000ms, timed out
- CI on #468 run 25169814732: first test >120000ms, timed out (same file)
ronan-dandelion-cult pushed a commit that referenced this pull request May 1, 2026
…tion-registration to absorb cold module-load cost (#498)

The first test in src/agents/openclaw-tools.continuation-registration.test.ts
("registers no continuation tools when continuation.enabled is unset") pays
the cold module-load cost for createOpenClawTools and its transitive imports
(compaction-attribution, pi-embedded-*, plugins/tools, config/config) under
400+ concurrent test files in the agent project.

Quiet-box first-test duration: ~95s. CI noise pushes it past vitest's 120s
per-test default, producing a flaky timeout that has now been observed across
multiple unrelated PRs:

- #485 head (compaction-attribution scope) — first-test timeout
- #488 (downstream of #485 hypothesis) — first-test timeout
- #468 head (does NOT touch this file) — same first-test, same file, timeout

Test file content is byte-identical between base cael/325-canonical2 and #485
head; the timeout is not a regression introduced by any of those PRs. Tests
2-7 in this file reuse the warm cache (~360ms each) and are unaffected.

Cure: per-test timeout bump to 240s on the first test only, with a comment
documenting the cold-start mechanism so future readers know why this single
test has a non-default timeout.

Standalone fix, deliberately not folded into #485 to keep its compaction-
attribution scope clean. Unblocks #485, #488, #468, and any future PR that
randomly trips the same flake.

Verified by silas-pr485-fixup-v2 subagent (2026-05-01 07:29 UTC):
- Local on base a3dcc2a: first test 95023ms, passed (25s margin to 120s)
- CI on #485 head 9f25f91: first test >120000ms, timed out
- CI on #468 run 25169814732: first test >120000ms, timed out (same file)
@ronan-dandelion-cult ronan-dandelion-cult merged commit 1e21522 into cael/325-canonical2 May 1, 2026
92 of 94 checks passed
@ronan-dandelion-cult ronan-dandelion-cult deleted the frond-scribe/swim39-823-post-compaction-ttl-restart-load branch May 1, 2026 15:06
Copy link
Copy Markdown

@silas-dandelion-cult silas-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.

🌫 — diff-clean approve. firstArmedAt field is purely additive (optional everywhere, falls back to stagedAt/createdAt/Date.now() when absent), schema-compatible with existing persisted state. Round-trip preserved across TaskFlow storage, post-compaction substrate test, and runner-count consume path. Test coverage includes the lossy-round-trip scenario (stagedAt: 20_000, firstArmedAt: 10_000 → consumed with firstArmedAt: 10_000). 138/15 across 10 files, all in continuation surface; no cross-cut. ✅

Copy link
Copy Markdown

@cael-dandelion-cult cael-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.

byte-walked diff — narrow, coherent: firstArmedAt threading through SessionPostCompactionDelegate / StagedPostCompactionDelegate / PendingContinuationDelegate / PendingDelegateState (zod schema), with TTL drop using stable first-armed age (requeued delegates don't reset their clock). Tests cover all three layers (canonical store, post-compaction wrapper, dispatch). POST_COMPACTION_DELEGATE_TTL_MS = 7d matches gateway max-delay shape. now injected as dep for testability. APPROVE.

karmafeast pushed a commit that referenced this pull request May 1, 2026
…tion-registration to absorb cold module-load cost (#498)

The first test in src/agents/openclaw-tools.continuation-registration.test.ts
("registers no continuation tools when continuation.enabled is unset") pays
the cold module-load cost for createOpenClawTools and its transitive imports
(compaction-attribution, pi-embedded-*, plugins/tools, config/config) under
400+ concurrent test files in the agent project.

Quiet-box first-test duration: ~95s. CI noise pushes it past vitest's 120s
per-test default, producing a flaky timeout that has now been observed across
multiple unrelated PRs:

- #485 head (compaction-attribution scope) — first-test timeout
- #488 (downstream of #485 hypothesis) — first-test timeout
- #468 head (does NOT touch this file) — same first-test, same file, timeout

Test file content is byte-identical between base cael/325-canonical2 and #485
head; the timeout is not a regression introduced by any of those PRs. Tests
2-7 in this file reuse the warm cache (~360ms each) and are unaffected.

Cure: per-test timeout bump to 240s on the first test only, with a comment
documenting the cold-start mechanism so future readers know why this single
test has a non-default timeout.

Standalone fix, deliberately not folded into #485 to keep its compaction-
attribution scope clean. Unblocks #485, #488, #468, and any future PR that
randomly trips the same flake.

Verified by silas-pr485-fixup-v2 subagent (2026-05-01 07:29 UTC):
- Local on base a3dcc2a: first test 95023ms, passed (25s margin to 120s)
- CI on #485 head 9f25f91: first test >120000ms, timed out
- CI on #468 run 25169814732: first test >120000ms, timed out (same file)
karmafeast added a commit that referenced this pull request May 1, 2026
Co-authored-by: Test User <test@example.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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