Renames the host-side plan and stream layer from subscription to source, because what the host opens, reconnects and backfills is not what a module reacts to, and the two are not interchangeable.
The guest-ABI rename has landed. This lands alone after it, because it touches no guest ABI and no manifest.
Source and trigger must not share a word, in both directions: one block stream per chain fans out to every module that declared a block trigger on it, and one trigger kind is fed by two transports, since blocks arrive by eth_subscribe(newHeads) on WebSocket and by polling on HTTP.
Renames
| Old, as it stands on main |
New |
Surface |
Breaking |
Supervisor::trigger_plan() |
source_plan() |
Rust, supervisor/triggers.rs:18 |
yes, public |
TriggerPlan |
SourcePlan |
Rust, triggers.rs |
yes, public |
TriggerPlan.event_triggers |
SourcePlan.event_sources |
Rust, triggers.rs:87 |
yes, public |
EventTrigger |
EventSource |
Rust, triggers.rs:55, re-exported supervisor/mod.rs:17 |
yes, public |
supervisor/triggers.rs |
supervisor/sources.rs |
filename |
internal |
ProviderPool::watch_chain_logs |
open_event_source |
Rust, host/provider_pool.rs |
yes, public |
ProviderPool::subscribe_blocks |
open_block_source |
Rust, host/provider_pool.rs |
yes, public |
enforce_subscriptions |
enforce_trigger_chains |
Rust, supervisor/prepass.rs, re-exported mod.rs |
internal |
LogSource |
LogChannel |
Rust, host/logs/mod.rs and ~20 uses in host/logs/stdio.rs |
yes, public |
Five of these are a second rename, and that is deliberate
The guest-ABI rename swept the retired subscription vocabulary out of the supervisor API and reached for trigger, which is the word this issue reserves for the other side of the fan-out. supervisor/triggers.rs, trigger_plan(), TriggerPlan, event_triggers and EventTrigger therefore need renaming again, to source.
The tell that this is right rather than churn: TriggerPlan.block_chains names the chains the host must open a stream on. That is a source concern wearing the trigger word, which is exactly the conflation this issue exists to remove. Everything here is pre-v1 and unpublished, and both downstream repos are already unbuildable, so the second rename costs diff churn and nothing else.
Already correct, no work needed
Viability::DeadHoldSubs already reads DeadHoldTriggers, and the demand-side field already reads demanded_extension_kinds on SourceContext. Both landed with the guest-ABI rename in the spelling this issue wanted.
Note the target spellings changed with that rename too: the chain-log trigger is now event, so the targets are event_sources and EventSource rather than chain_log_sources and ChainLogSource.
open_*_source rather than poll_chain_logs and follow_blocks. Both methods do one job, which is open a source, and naming them for it is honest about transport in neither direction. poll_ bakes the transport into the name and goes false the day the repo adds eth_subscribe("logs"). follow_blocks describes nothing and leaves pool.follow_blocks() calling provider.subscribe_blocks(). poll is also becoming overloaded: the keeper seam, poll_interval, and receipt status all use it.
LogChannel is the second half of reserving SOURCE. ChainLogSource sitting beside a LogSource that means guest stdout and stderr is the same collision that made "on log" unusable as an identifier, recreated one layer up with the new word. LogChannel is what the enum holds: Stdout, Stderr.
demanded_extension_kinds is one spelling shared with SourceContext, so the demand side reads the same at both layers.
Must land with it
Both call sites of enforce_subscriptions: boot_single and prepass::run.
The test name empty_pool_rejects_block_subscribe.
Every operator string on this layer, not four of them. event_loop.rs says "block subscription open / reopened / failed"; the same function also says "block stream ended (WebSocket dropped?)" and "block stream healthy - resetting backoff", and further down says "chain-log poller open" and "chain-log poller reopened". Leaving those produces an operator reading "block source open", then "block stream ended", then "chain-log poller reopened" for one reconnect.
Does not change
alloy's watch_blocks_from and watch_canonical_logs_from. Upstream API names this project does not own. After this issue these are the only two watch tokens left in nexum-runtime, and a grep guard should allowlist exactly those two lines.
BlockStream and CanonicalLogStream. A stream is the transport a source is delivered over, which is a real distinction and not drift.
The metric nexum_runtime_stream_reconnects_total and its labels. They move in the metrics issue, together, since renaming the label here while the name still says stream manufactures the disagreement this program exists to remove.
Done when
subscription and subscribe appear in crates/nexum-runtime/src only inside the two allowlisted alloy call sites and in eth_subscribe where it names the RPC method.
One reconnect reads as one vocabulary in the logs.
AI Assistance: Claude Opus 5 used for the audit and this issue.
Renames the host-side plan and stream layer from
subscriptiontosource, because what the host opens, reconnects and backfills is not what a module reacts to, and the two are not interchangeable.The guest-ABI rename has landed. This lands alone after it, because it touches no guest ABI and no manifest.
Source and trigger must not share a word, in both directions: one block stream per chain fans out to every module that declared a block trigger on it, and one trigger kind is fed by two transports, since blocks arrive by
eth_subscribe(newHeads)on WebSocket and by polling on HTTP.Renames
Supervisor::trigger_plan()source_plan()supervisor/triggers.rs:18TriggerPlanSourcePlantriggers.rsTriggerPlan.event_triggersSourcePlan.event_sourcestriggers.rs:87EventTriggerEventSourcetriggers.rs:55, re-exportedsupervisor/mod.rs:17supervisor/triggers.rssupervisor/sources.rsProviderPool::watch_chain_logsopen_event_sourcehost/provider_pool.rsProviderPool::subscribe_blocksopen_block_sourcehost/provider_pool.rsenforce_subscriptionsenforce_trigger_chainssupervisor/prepass.rs, re-exportedmod.rsLogSourceLogChannelhost/logs/mod.rsand ~20 uses inhost/logs/stdio.rsFive of these are a second rename, and that is deliberate
The guest-ABI rename swept the retired
subscriptionvocabulary out of the supervisor API and reached for trigger, which is the word this issue reserves for the other side of the fan-out.supervisor/triggers.rs,trigger_plan(),TriggerPlan,event_triggersandEventTriggertherefore need renaming again, to source.The tell that this is right rather than churn:
TriggerPlan.block_chainsnames the chains the host must open a stream on. That is a source concern wearing the trigger word, which is exactly the conflation this issue exists to remove. Everything here is pre-v1 and unpublished, and both downstream repos are already unbuildable, so the second rename costs diff churn and nothing else.Already correct, no work needed
Viability::DeadHoldSubsalready readsDeadHoldTriggers, and the demand-side field already readsdemanded_extension_kindsonSourceContext. Both landed with the guest-ABI rename in the spelling this issue wanted.Note the target spellings changed with that rename too: the chain-log trigger is now
event, so the targets areevent_sourcesandEventSourcerather thanchain_log_sourcesandChainLogSource.open_*_sourcerather thanpoll_chain_logsandfollow_blocks. Both methods do one job, which is open a source, and naming them for it is honest about transport in neither direction.poll_bakes the transport into the name and goes false the day the repo addseth_subscribe("logs").follow_blocksdescribes nothing and leavespool.follow_blocks()callingprovider.subscribe_blocks().pollis also becoming overloaded: the keeper seam,poll_interval, and receipt status all use it.LogChannelis the second half of reserving SOURCE.ChainLogSourcesitting beside aLogSourcethat means guest stdout and stderr is the same collision that made "on log" unusable as an identifier, recreated one layer up with the new word.LogChannelis what the enum holds: Stdout, Stderr.demanded_extension_kindsis one spelling shared withSourceContext, so the demand side reads the same at both layers.Must land with it
Both call sites of
enforce_subscriptions:boot_singleandprepass::run.The test name
empty_pool_rejects_block_subscribe.Every operator string on this layer, not four of them.
event_loop.rssays "block subscription open / reopened / failed"; the same function also says "block stream ended (WebSocket dropped?)" and "block stream healthy - resetting backoff", and further down says "chain-log poller open" and "chain-log poller reopened". Leaving those produces an operator reading "block source open", then "block stream ended", then "chain-log poller reopened" for one reconnect.Does not change
alloy's
watch_blocks_fromandwatch_canonical_logs_from. Upstream API names this project does not own. After this issue these are the only twowatchtokens left in nexum-runtime, and a grep guard should allowlist exactly those two lines.BlockStreamandCanonicalLogStream. A stream is the transport a source is delivered over, which is a real distinction and not drift.The metric
nexum_runtime_stream_reconnects_totaland its labels. They move in the metrics issue, together, since renaming the label here while the name still says stream manufactures the disagreement this program exists to remove.Done when
subscriptionandsubscribeappear incrates/nexum-runtime/srconly inside the two allowlisted alloy call sites and ineth_subscribewhere it names the RPC method.One reconnect reads as one vocabulary in the logs.
AI Assistance: Claude Opus 5 used for the audit and this issue.