You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
During a real /orchestrate run (orchestrate plugin v1.6.0), after freezing per-slice routing into run-state.json, writing the resolved-routing block for a non-premium slice (no route:* label, no model fallback) as:
caused validate_run_stateand all three render tools (render_dashboard, render_graph, render_report) to fail with:
run-state.json does not match the expected shape: slices.<N>.resolvedRouting.fallback: Expected object, received null
Why this is an easy trap
The SKILL spine describes freezing { model, variant, optional fallback }. "Optional" naturally reads as nullable — so writing "fallback": null for a slice with no fallback looks correct. But the schema is .optional(), which accepts an absent key yet rejects a literal null. The key must be omitted, not set to null, when there is no fallback.
Worse, the error only surfaces at the final render step — after the entire wave loop has run — rather than at the checkpoint write that introduced the bad shape. The whole run can complete and then fail to render.
Relationship to existing issues (read before deduping)
So this is a genuinely new surface, not a duplicate of #300/#315.
Suggested fix (options)
Relax the schema so resolvedRouting.fallback accepts null and treats it as absent (.nullish() / z.object(...).nullable().optional()), so both null and omitted validate. (Touches orchestrate-mcp/src + requires npm run build and a rebuilt committed dist/.)
Symptom
During a real
/orchestraterun (orchestrate plugin v1.6.0), after freezing per-slice routing intorun-state.json, writing the resolved-routing block for a non-premium slice (noroute:*label, no model fallback) as:caused
validate_run_stateand all three render tools (render_dashboard,render_graph,render_report) to fail with:Why this is an easy trap
The SKILL spine describes freezing
{ model, variant, optional fallback }. "Optional" naturally reads as nullable — so writing"fallback": nullfor a slice with no fallback looks correct. But the schema is.optional(), which accepts an absent key yet rejects a literalnull. The key must be omitted, not set tonull, when there is no fallback.Worse, the error only surfaces at the final render step — after the entire wave loop has run — rather than at the checkpoint write that introduced the bad shape. The whole run can complete and then fail to render.
Relationship to existing issues (read before deduping)
subState: nullrejected — "omit the key; an explicitnullis rejected"), but for a different, uncovered field:resolvedRouting.fallback. orchestrate: run-state.md subState wording — say 'omit the key' (an explicit null is rejected) #300 is CLOSED and its doc-only fix touched only thesubStatewording inreferences/run-state.md.resolvedRoutingblock was introduced by Persist resolved slice routing in run-state checkpoint #315 (Persist resolved slice routing in run-state checkpoint), whose AC says the fallback spec is present "when present" and the fields are "additive/optional at the schema level" — i.e. exactly the null-vs-absent ambiguity that bit this run. Persist resolved slice routing in run-state checkpoint #315 shipped without resolving the trap for its own field.So this is a genuinely new surface, not a duplicate of #300/#315.
Suggested fix (options)
resolvedRouting.fallbackacceptsnulland treats it as absent (.nullish()/z.object(...).nullable().optional()), so bothnulland omitted validate. (Touchesorchestrate-mcp/src+ requiresnpm run buildand a rebuilt committeddist/.)resolvedRouting.fallbackmust be OMITTED (notnull) for non-premium slices — and have the freeze/checkpoint guidance show the no-fallback shape so authors copy the correct form. (Doc-only, mirrors the orchestrate: run-state.md subState wording — say 'omit the key' (an explicit null is rejected) #300 fix.)Ideally do both: relax the schema AND show the no-fallback shape in the reference, so the trap is closed at the schema and the doc.
Environment
orchestrate plugin v1.6.0, observed during a real
/orchestraterun.