From fd2c682477798c7198a2ab70cbe45d5e25d792c5 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 9 Jul 2026 16:42:26 +0800 Subject: [PATCH] docs(subagent): state the re-assert placement guarantee precisely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewer-agent C1 on the audit delta: "byte-identical" overstated the untampered-path guarantee — a 190-order section registered AFTER the structured runtime sorts before the instruction in the registry's stable sort but after it in the re-assert's band insertion. Intra-band section order carries no contract, so the behavior is right and unchanged; the module doc and both in-code comments now say exactly that instead of claiming byte identity. --- .../subagent-inprocess/src/structured.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/subagent/subagent-inprocess/src/structured.ts b/packages/subagent/subagent-inprocess/src/structured.ts index 5107897c68..def740ec25 100644 --- a/packages/subagent/subagent-inprocess/src/structured.ts +++ b/packages/subagent/subagent-inprocess/src/structured.ts @@ -21,9 +21,10 @@ * always carries its capture tool and the trailing instruction section. The * registry already contributes both; this outermost wrapper preserves the * guarantee against a (global) listener that strips or replaces the - * assembly — placement-preserving, so an untampered assembly reaches the - * model byte-identical (tools replaced in place, the section re-inserted at - * its ascending-order position). The loop logs the rendered assembly as the + * assembly — placement-preserving: tools are replaced in place, the section + * re-inserted at its ascending-order position, so the untampered path keeps + * the registry's ordering (identical output, up to intra-band section order + * — which carries no contract). The loop logs the rendered assembly as the * request header, so the demand is reconstructable log state, never a * wire-only mutation. * - `agent/turn-continuation` (prepend, scoped): stop the child's turn once @@ -148,10 +149,12 @@ export function attachStructuredRuntime(childCtx: Context, schema: StructuredOut // mutated or injected a same-named entry with the WRONG schema/text, and // the model-visible demand must be exactly this run's own — the same // schema validateStructuredValue enforces. Placement-preserving on both - // arrays: the untampered path must reach the model byte-identical to the - // registry's output (tool order is the `toolOrder`/lexicographic - // contract, section order is the ascending contract `renderPrompt` - // trusts), so this never reorders what it only re-asserts. + // arrays: the untampered path keeps the registry's ordering (tool order + // is the `toolOrder`/lexicographic contract, section order the ascending + // contract `renderPrompt` trusts), so this never reorders what it only + // re-asserts — up to intra-band section order, which carries no contract + // (a 190-order section registered AFTER this runtime sorts before the + // instruction in the registry but after it here). const freshTool: ToolSchema = { ...schemaEntry, parameters: structuredClone(schemaEntry.parameters) } // Tools: replace the first same-named entry IN PLACE (its position is the // chain's product; a tool's list position carries no semantic band to @@ -173,8 +176,8 @@ export function attachStructuredRuntime(childCtx: Context, schema: StructuredOut // DO carry an order contract, and the renderer reads array order, so a // stripped-or-moved instruction is restored to its band, not appended // after unrelated higher-order sections. On the untampered path this - // lands exactly where the registry's stable sort put it (last of the 190 - // band — the scoped section registers after every load-time 190). + // lands at the end of the 190 band — where the registry's stable sort + // put it too, unless another 190-order section registered later. const sectionName = `tool:${STRUCTURED_OUTPUT_TOOL}` const sections = final.sections.filter(section => section.name !== sectionName) const insertAt = sections.findIndex(section => section.order > 190)