Resolve once: a delivery reads each technique one time, and says what it cost - #440
Merged
Conversation
The producer scan reads every bound op in the workflow to learn its declared outputs, and its answer does not vary with the step being decorated — only the step's document-order position does. buildProducerIndex holds that scan for the lifetime of one request and provenanceContextFor reads each step's position out of it, so a delivery that inlines several steps resolves each unique technique once however many steps it carries. buildProvenanceContext stays as the single-step composition of the two, which is what a lazy technique fetch needs. The decoration output is unchanged: the new test asserts the contexts an index serves are field-for-field identical to a per-step scan's, and the walk snapshots are unmoved.
…hmark Two things ride along with every operation inside a container: rules declared on a root or group TECHNIQUE.md, and inherited I/O entries. Both are cross-cutting by design, so the reach figures describe what the corpus intends rather than faulting it, and nothing gates on them — they are reported warn-only so the fan-out is visible and a regression is arguable. On the default three-activity run of the main workflow: 16,504 characters of container rules over 72 entries, 8.3% naming the operation they arrive with, and 26,930 characters of inherited I/O over 215 items, 1.4% templated by the receiving protocol. The previous commit's delivery-cost lines report the resolve and character figures for a single call; these two are corpus-wide ratios over a walk.
Everything an orchestrator reads before its first decision is fixed content: the bootstrap text, the session-start response, and the operations bundle. The budget for it is stated in the bootstrap protocol, which is where the orchestrator reads it, and this test parses the figure from there rather than keeping a second copy free to drift. Measured on the corpus this points at: 100,273 of 110,000 characters, of which 94,323 is the operations bundle. The corpus pointer moves to the definitions that drop the schema read (#439), and the walk baseline is re-stamped for it; the walk snapshots themselves are unchanged.
This was referenced Aug 6, 2026
get_workflow hands over the largest fixed payload of a session — the same operations bundle every run, read before the first decision — so it reports on the same channel as the worker-facing deliveries rather than being the one delivery call that says nothing about itself.
discover hands over the first content of a session and the same characters every run, so it reports on the channel the other four delivery calls use. That makes the whole bootstrap window summable from the log without reading a session file.
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.
Summary
When the server hands a worker its next piece of work, it decorates each step with a note saying
where each input the step consumes comes from. Building that note means reading every technique the
workflow binds, to learn which outputs each one declares — and the answer does not depend on which
step is being decorated. Only the step's position in the workflow does. So the whole scan was being
repeated once per step the delivery inlines: one observed call walked the technique catalog three
times, over a catalog that currently holds 184 files.
The scan now happens once for the whole request, and every step reads its position out of that one
index. Each delivery also says what it cost, and the batch benchmark reports two fan-out ratios that
were measured during the SOLID review but had nowhere to be seen from.
Work items W1, W2, W6 and the budget half of W4 of the delivery-cost epic #404. Subsumes stages 1, 2
and 4 of #269.
Resolve each technique once — W1
buildProducerIndexwalks the workflow once and returns the producer list, the declared-variableset, and a map from each step to its document-order position.
provenanceContextForreads one step'sview out of that index.
buildProvenanceContextremains, as the single-step composition of the two,which is what a lazy
get_techniqueneeds.The decoration output is unchanged, and there are two independent checks that it is:
field-for-field identical to what a per-step scan produces for the same step.
A second new test counts the loader reads behind both shapes. Three steps served from one index cost
exactly the reads of the index; three steps served by a scan apiece cost three times that. That is
the figure that regresses if the scan ever moves back inside the per-step loop.
Say what each delivery cost — W2
One line per delivery call, on the info channel:
get_activity— the distinct techniques the producer scan resolved, the steps decorated from thatone scan, the steps and resources bundled and how many of each collapsed to a marker, the
characters drawn against the eager budget, and the response length.
get_technique— the resolve work behind one step's decoration, the composed size, and what theresponse carried after any shared block collapsed.
get_resource— the resource size and what the response carried.This extends the
technique_bundled/resource_fetchedevents #353 already writes, which reportper-item delivered and saved characters. What was missing was the per-request summary: how much
resolve work one call did, and what it spent against its budget.
Fan-out, reported and not gated — W6
Two things ride along with every operation inside a container. Rules declared on a root or group
TECHNIQUE.mdreach every operation in that container, and inherited I/O entries reach everyoperation that composes the contract.
npm run bench:batchnow reports both, warn-only:Nothing fails on either figure, and that is deliberate. A container rule is meant to apply to
operations that do not name it, so a threshold would fail the corpus on its intended design. The
8.3% here corroborates the 8.9% the review measured over a full work-package walk — this run covers
three activities rather than all of them.
The bootstrap budget — W4's enforceable half
The definitions half of W4 is #439, which drops the whole-workflow-schema read from the bootstrap and
states a budget of 110,000 characters for everything fixed the orchestrator reads before deciding.
This branch measures the three deliveries that make up that content and asserts the total is inside
the budget. The figure is parsed out of the protocol text, so the number an agent is told and the
number enforced cannot diverge.
Measured on the corpus this branch points at: 100,273 of 110,000 —
discover5,602,start_session348,get_workflow94,323. The operations bundle is 94% of what remains, and it iswhat a future trim has to reach.
Scope of change
src/utils/binding-provenance.ts— the index/position split.src/tools/workflow-tools.ts,src/tools/resource-tools.ts— build the index once per request;the three cost lines.
src/utils/fan-out.ts(new),scripts/run-batch-benchmark.ts— the two ratios.tests/provenance-resolve-once.test.ts,tests/bootstrap-budget.test.ts(new).No schema change. No response-payload change — the cost lines go to the log, not the wire.
Verification
npx tsc --noEmitclean.resolved by the re-stamp in this branch).
Non-goals
two calls is visible to the second without invalidation logic.
orchestrator behaviour and lands with the corpus guidance.
Investigation detail
engineering/artifacts/planning/2026-08-02-delivery-cost-epic
— the status check against main with hot-path locations, the captured #269 body, and this epic's
sequencing plan with its baselines.