feat(manifest): seed a first boot from a declared start_block - #381
Merged
Merged
Conversation
An event trigger opens at head when no cursor is stored, so a module whose state derives only from logs starts blind. History it never saw is history it can never rebuild: a contract event emitted before the daemon first ran is not recoverable from any later block. `resume` fixed the restart case by persisting a cursor, but the first boot has no cursor to resume from. `start_block` supplies that seed, normally the contract's deployment block, so a fresh daemon backfills the contract's whole history before it goes live. The seed applies only while no stored cursor exists. Once the first bulk chunk commits, the store wins for good, so this is a one-time floor rather than a rescan point. The manifest refuses `start_block` without `resume`, which would otherwise re-apply the seed on every open and rescan the whole range after each restart. No behaviour changes without the new key: an absent `start_block` still opens at head. The backfill path itself is untouched, since `initial_cursor` already drove chunked bulk fetches with a per-chunk durable frontier. `start_block_without_resume` joins the pinned error-kind label set. AI Assistance: Claude Code used for the manifest field, the cursor seeding and the tests.
mfw78
force-pushed
the
feat/event-trigger-start-block
branch
from
August 31, 2026 04:37
fc39572 to
beba849
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
An event trigger opens at head when no cursor is stored. A module whose state derives only from logs therefore starts blind, and stays blind about anything that happened before it first ran. History it never saw is history it can never rebuild, because a contract event emitted before the daemon's first boot is not recoverable from any later block.
resumefixed the restart case by persisting a cursor. It does not help the first boot, which has no cursor to resume from.The motivating case is shepherd's ComposableCoW keeper. A conditional order is registered by a
ConditionalOrderCreatedlog and can stay live for weeks. A TWAP created last month and halfway through execution is invisible to a daemon that starts at head, so it is never polled and never submitted.What changed
[[trigger]] on = "event"gains an optionalstart_block, normally the contract's deployment block.It seeds
initial_cursoronly while no stored cursor exists. Once the first bulk chunk commits its frontier, the store wins for good, so the seed is a one-time floor and not a rescan point.The manifest refuses
start_blockwithoutresume = true. Without a durable cursor the seed would apply on every open, turning a one-time backfill into a full rescan after every restart. That refusal is a typed variant with pinned operator wording, andstart_block_without_resumejoins the pinned error-kind label set.What did not change
The backfill path is untouched.
initial_cursoralready drove the chunked bulk phase with a per-chunk durable frontier, so a deep first backfill chunks at the operator-declared range, commits as it goes, and resumes at the last completed chunk if interrupted. This PR only supplies the seed that path already accepted.A trigger without
start_blockstill opens at head, so no existing manifest changes behaviour.max_lookbackstill bounds how far back a backfill reaches and composes with the seed unchanged.Verification
958 tests pass, fmt and clippy clean at
-D warnings.Three new tests cover the semantics rather than the plumbing: the seed reaches
initial_cursoron an empty store; a stored cursor outranks it, so a restart never rescans; and a resuming trigger without a seed still starts at head. The manifest test pins both the accepted shape and the refusal wording.AI Assistance: Claude Code used for the manifest field, the cursor seeding and the tests.