Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions site/design/protocol.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ <h2 id="ordering">Call order and authentication</h2>
<li><strong><code>next_activity</code> moves; <code>get_activity</code> reads.</strong> The orchestrator advances the session and gets back only the new activity's id; the worker then loads the full definition. Later transitions come from the <code>transitions</code> field of the current activity, validated server-side against the definition.</li>
<li><strong>An active checkpoint locks the session.</strong> Between <code>yield_checkpoint</code> and <code>respond_checkpoint</code>, navigation <em>and</em> content reads (<code>next_activity</code>, <code>get_activity</code>, <code>get_technique</code>, <code>get_resource</code>, <code>get_trace</code>) are refused; only the checkpoint tools and <code>get_workflow_status</code> proceed. <code>respond_checkpoint</code> with a user choice is additionally rejected if it arrives less than three seconds after the yield — a response that fast did not involve a person.</li>
<li><strong>Replays are safe.</strong> Yielding a checkpoint that was already resolved returns the cached response instead of pausing again, so a worker resumed with stale context cannot double-ask.</li>
<li><strong><code>get_activity</code> requires <code>context_tokens</code>.</strong> The worker declares its own context window in tokens on every activity fetch. The server derives an eager step-technique bundling budget from it (availability headroom × a token→char factor, both server config) and inlines ungated step-bound techniques that fit. It is per-agent and per-call — never stored on the session, never defaulted. Omitting <code>context_tokens</code> is a validation error. See <a href="#bundling">eager bundling</a> and <a href="../specs/resource-resolution.html#bundling">Resolution</a>.</li>
</ul>

<h2 id="errors">Errors: the call failed</h2>
Expand Down Expand Up @@ -107,7 +108,7 @@ <h2 id="warnings">Warnings: the call succeeded, and left evidence</h2>
<tbody>
<tr><td>Missing / unexpected steps in manifest</td><td>The reported <code>step_manifest</code> doesn't match the activity's declared steps — work was skipped, invented, or renamed.</td></tr>
<tr><td>Step order mismatch, empty step output</td><td>Steps reported out of declared order, or a step claimed complete with nothing to show.</td></tr>
<tr><td>Technique not fetched</td><td>A manifested technique step has no <code>technique_fetched</code> event — the step was summarized from memory, not executed from its definition.</td></tr>
<tr><td>Technique not fetched</td><td>A manifested technique step has no <code>technique_fetched</code> or <code>technique_bundled</code> event — the step was summarized from memory, not executed from its definition.</td></tr>
<tr><td>Workflow version drift</td><td>The definition changed on disk since <code>start_session</code>; the run continues under the new definition.</td></tr>
<tr><td>Parent chain depth</td><td>More than five levels of nested dispatch — usually a sign the dispatch topology has gone wrong.</td></tr>
</tbody>
Expand Down Expand Up @@ -138,7 +139,7 @@ <h2 id="delivery">Reference delivery</h2>
<text x="470" y="114" fill="var(--diagram-label)">hash already in the ledger?</text>
<text x="470" y="134" fill="var(--diagram-note)" font-size="12.5" font-weight="400">deliveredContent, per agent</text>
<rect x="670" y="30" width="270" height="64" rx="10" fill="var(--diagram-node-fill)" stroke="var(--diagram-node-stroke)" stroke-width="2"/>
<text x="805" y="56" fill="var(--diagram-label)" font-family="ui-monospace, Menlo, Consolas, monospace" font-size="13">{ unchanged: true,</text>
<text x="805" y="56" fill="var(--diagram-label)" font-family="ui-monospace, Menlo, Consolas, monospace" font-size="13">{ delivery: "unchanged",</text>
<text x="805" y="76" fill="var(--diagram-label)" font-family="ui-monospace, Menlo, Consolas, monospace" font-size="13">content_hash }</text>
<rect x="670" y="160" width="270" height="64" rx="10" fill="var(--diagram-node-fill)" stroke="var(--diagram-node-stroke)" stroke-width="2"/>
<text x="805" y="186" fill="var(--diagram-label)">full content delivered</text>
Expand All @@ -157,7 +158,16 @@ <h2 id="delivery">Reference delivery</h2>
<figcaption>Reference delivery in <code>persistent</code> mode. The ledger is keyed per agent and per channel (technique bundles, rules, individual techniques), so an orchestrator and a worker on the same session have independent delivery state. An agent that has lost its context can force re-delivery with <code>get_activity { bundle: "full" }</code> or <code>get_technique { full: true }</code>.</figcaption>
</figure>

<p>The marker is a contract, not a hint: <code>unchanged: true</code> asserts the content is byte-identical to what this agent already received, which the server can promise because payload composition is deterministic. If your context no longer contains the earlier copy, ask for full delivery rather than proceeding from a summary.</p>
<p>The marker is a contract, not a hint: <code>delivery: "unchanged"</code> asserts the content is byte-identical to what this agent already received, which the server can promise because payload composition is deterministic. If your context no longer contains the earlier copy, ask for full delivery rather than proceeding from a summary.</p>

<h2 id="bundling">Eager step-technique bundling</h2>
<p>Every <code>get_activity</code> call automatically inlines small, ungated step-bound techniques under a <code>step_techniques</code> map — there is no per-activity opt-in. The worker supplies <code>context_tokens</code>; the server computes a cumulative per-activity character budget:</p>
<p class="prose"><code>context_tokens × headroomFraction × charsPerToken</code> — defaults 0.80 and 4, overridable via <code>BUNDLE_HEADROOM_FRACTION</code> and <code>BUNDLE_CHARS_PER_TOKEN</code>. Ungated technique steps are inlined in document order until the next would overflow the budget; gated steps (<code>when</code>/<code>condition</code> on the step or an enclosing loop) and oversized techniques stay lazy via <code>get_technique { step_id }</code>. A per-activity <code>bundleTechniques.maxChars</code> caps any single technique; <code>maxChars: 0</code> opts the activity out entirely. Resources referenced by inlined techniques are never inlined — the worker still calls <code>get_resource</code> on demand.</p>
<p>Bundled entries share the <code>technique:&lt;resolvedId&gt;</code> ledger key with <code>get_technique</code>, so in persistent context mode a bundled delivery collapses a later step-bound refetch to an unchanged marker. Each bundled step is recorded as a <code>technique_bundled</code> event and counts toward manifest fidelity checks alongside <code>technique_fetched</code>.</p>

<h2 id="enforcement">Enforcement notes and provenance</h2>
<p>The server is a state ledger and payload composer, not an executor. Some constructs are agent-interpreted — step ordering, condition evaluation, <code>actions[]</code> verbs, protocol execution — and the server never checks them. Because a payload-only reader cannot see this classification, <code>get_activity</code> surfaces an <code>enforcement_notes</code> block (also in <code>_meta</code>) when the current activity contains agent-interpreted constructs: an <code>actions</code> note when a step is <code>kind:action</code> or carries an <code>actions[]</code> list; an <code>auto_advance</code> note when a checkpoint declares <code>autoAdvanceMs</code>. An activity without these constructs carries no block.</p>
<p>A step-bound <code>get_technique</code> fetch annotates the binding seam: each of the technique's own inputs carries a <code>source:</code> line stating where its value comes from (step-binding value, workflow variable, prior step output, declared default, or <code>UNRESOLVED</code>); remapped outputs carry a <code>destination:</code> line. Contract-inherited inputs are annotated only when the resolution says something the block note does not. Classification is purely static — same corpus and step always produce byte-identical annotations, which is what makes reference delivery safe.</p>

<h2 id="dispatch">Dispatch in practice</h2>
<p>A typical work package starts before any planning folder exists: the meta session created by <code>start_session</code> for workflow selection is <em>transient</em>, living in the system temp directory. The first <code>dispatch_child</code> that commits to real work does three things at once — promotes the transient session into <code>.engineering/artifacts/planning/&lt;slug&gt;/</code> (the slug from your request, or a dated fallback), creates the child session embedded in the parent's file, and returns the child's own <code>session_index</code> for the worker. From there:</p>
Expand Down
Loading
Loading