A reasonable draft is generated
Routing and proposal-writing appear to complete. The answer can look perfectly usable to a human reviewer.
Why submit_case_draft repeatedly rejects proposals during the workflow-to-agent migration—and how to fix the protocol instead of teaching the model to guess object shapes.
unknown. Strict validation happens only afterward, where every failure is collapsed into one generic error.Routing and proposal-writing appear to complete. The answer can look perfectly usable to a human reviewer.
Proposal writer returned an invalid reply result.
The message does not say which field or structural boundary failed.
It retries plain text, nested reply objects, textBody, wrappers, and other shapes. They all fail for the same hidden reason.
The proposal skill was invoked with the exact mode-specific schema. Flue returned validated data.
buildProposalResultSchema(...)
session.skill('proposal', { result: resultSchema })
const { data } = ...
const resultSchema = buildProposalResultSchema(generationMode, options)
const { data } = await session.skill('proposal', {
args: skillArgs,
result: resultSchema,
tools,
})
return data // already schema-valid
flue/src/proposal-core.ts:307-344
The coordinator sends prepared context to proposal-writer.
The subagent profile has instructions and tools, but no result schema.
submit_case_draft accepts result: unknown and forwards it unchanged.
"{\"generationMode\":\"reply\", ...}"
{ data: { generationMode: "reply", ... } }
```json
{ "generationMode": "reply", ... }
```
The raw proposal object itself, with all required and cross-validated fields.
{
generationMode: "reply",
body: "...",
reasoning: "...",
confidence: "medium",
proposalKind: "reply",
detectedLanguage: "en",
supportAction: "...",
isStaleClosureTemplate: false,
surfaceId: "...",
primaryJourneyId: "...",
relatedJourneyIds: []
}
flue/src/case-agent-profiles.ts:34-39 · flue/src/case-agent-agent-tools.ts:25-28, 111-118
const parsed = v.safeParse(
buildProposalResultSchema('reply', options),
result,
)
if (!parsed.success) {
throw new Error(
'Proposal writer returned an invalid reply result.',
)
}
flue/src/case-agent-reply-runtime.ts:261-280
Only this:
result did not satisfy the complete, mode-specific proposal schema.It does not establish that the customer-facing draft text itself was bad.
One failed trace is enough. Capture structure only—no customer text, proposal values, tokens, or tool results.
| Capture | Why it matters |
|---|---|
typeof result | A root string instead of object confirms the most likely mismatch. |
Array.isArray(result) | Rules out another root-shape mismatch. |
| Top-level keys only | Keys such as data, result, or output reveal a wrapper. |
| Valibot issue paths/types | Distinguishes root shape, missing fields, invalid enum, and routing failures. |
stage, workflowMode, generationMode | Detects reply/engineering and proposal-kind mismatches. |
| Structural hash across retries | Shows whether the coordinator resubmits the same invalid shape. |
{
resultType: typeof result,
resultIsArray: Array.isArray(result),
resultKeys: isRecord(result) ? Object.keys(result) : [],
validationIssues: parsed.issues.map(issue => ({
path: boundedIssuePath(issue),
type: issue.type,
})),
stage: runtime.stage,
workflowMode: runtime.workflowMode,
generationMode: runtime.generationMode,
}
Do not make the coordinator reverse-engineer an internal object contract. Move generation and submission behind one trusted tool boundary.
Load case context, mode, routing, and verified tool scope.
Invoke the proposal skill with result: buildProposalResultSchema(...).
Validate, canonicalize, and persist the returned data directly.
generate_and_submit_case_draft({
draftAttemptId,
routingSelection,
})
data.accepted or a bounded continue instruction.The customer-facing draft can be good while the machine-to-machine handoff is invalid.
The refactor changed the proposal boundary from “validated structured data” to “free-form subagent answer.” Restore that boundary in trusted code, and the repeated submit_case_draft failures should disappear without teaching the model any new schema-guessing behavior.