router-synthetic-head-model-id-slash-rejected-fail-closed
Diagnosed and fixed. The solution is written to ~/SOLUTION.md (copy at /workspace/solution/SOLUTION.md), with runnable verification artifacts alongside it.
The router behaved correctly: with all preferred lanes gated, it selected the cheapest still-eligible lane, synthetic/hf:moonshotai/Kimi-K3. The bug is in the Hermes-DAGger bridge route parser — it splits provider/model on the first / and then fails closed because the model remainder still contains a /. A slash inside a model id is legal (hf:moonshotai/Kimi-K3), so every agent()/llm()/tool() node aborted in <100 ms. Because head is chosen from global gate state, one gated provider set makes the same bad head for every project → fleet-wide.
TRANSPORT_REJECTS_SLASH_IN_MODEL to coding-hermes/task-router/scripts/router_spawn.py and exclude slash-model lanes from head. The existing always-run fallback fires and resolves to the slash-free deepseek-foreman/deepseek-flash.gatewayRoute in Hermes-DAGger/<project>/src/bridge/hermes_api.go splits on the first / only and keeps the model remainder verbatim; fail closed solely on empty provider/model. Also flagged the latent strings.LastIndex truncation in direct_llm.go:57.dogfooding.ts and dagger-role-tick.sh pass provider and model separately instead of concatenating them into one string.I reproduced the incident against the real public task-router with a hermetic state dir:
<project> / helios / duckbrain → head=synthetic/hf:moonshotai/Kimi-K3 (all real lanes gated)
Applying Fix A flips them to deepseek-foreman/deepseek-flash with degraded_fallback=true.
Both parser suites pass:
- TypeScript: 11/11 (node --experimental-strip-types --test route.test.ts)
- Go (mirrors the bridge): 6/6 (go test -v ./...)
Artifacts: /workspace/solution/{SOLUTION.md, route.ts, route.test.ts, go/route.go, go/route_test.go}.
# Evidence - Problem class: router-synthetic-head-model-id-slash-rejected-fail-closed - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-16T01:40:18.372Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Dagger dogfood role-tick: every agent()/llm()/tool() node died in <100ms with 'DAGGER_TOOL_MODEL: explicit provider/model route required'. Root cause chain: (1) task-router registry head for ALL projects resolved to the synthetic placeholder lane synthetic/hf:moonshotai/Kimi-K3 because every real lane was gated at resolve time (neuralwatt health DOWN since 2026-09-16T01:00:17Z, commandcode quota GATED blocked, fireworks-ai keyless fail-closed). (2) The synthetic lane model id contains a slash (hf:moonshotai/Kimi-K3). (3) dagger-role-tick.sh exported DAGGER_TOOL_MODEL=synthetic/hf:moonshotai/Kimi-K3; the dogfooding.ts pipeline modelOpt likewise routerResolve-falls to the same head. (4) <project> bridge gatewayRoute (src/bridge/hermes_api.go:461-478) splits provider/model on FIRST slash then rejects fail-closed any model still containing a slash: splitModel yields provider=synthetic model=hf:moonshotai/Kimi-K3 which still contains a slash -> explicitGatewayRouteError. Net effect: every scheduled role-tick lane (dogfood/QA/sync) that resolves its model via routerResolve or DAGGER_TOOL_MODEL dies with 0 exercised whenever the router head is the synthetic lane \u2014 fleet-wide outage class, not per-project. Fix directions: seed the router P8/fallback chain with a slash-free real provider model; or make router seed exclude synthetic placeholder lanes from head eligibility when real lanes are gated (fail-closed to a hard error instead of silently routing to an unroutable lane); or normalize the synthetic model ids to be slash-free. Verified evidence: /tmp/dagger-role-dogfooding-2575285-1789521359808344056/run.jsonl write_findings node error; role.db judge/use_for_real UNKNOWN-VALUE; router_spawn.py <project>/helios/duckbrain/<project> all head=synthetic/hf:moonshotai/Kimi-K3 live at 2026-09-16T01:20Z.", "environment": "production", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "router-synthetic-head-model-id-slash-rejected-fail-closed", "provider": "openrouter", "solved_at": "2026-09-16T01:40:18.372Z", "version": ""}Diagnosed and fixed. The solution is written to ~/SOLUTION.md (copy at /workspace/solution/SOLUTION.md), with runnable verification artifacts alongside it.
The router behaved correctly: with all preferred lanes gated, it selected the cheapest still-eligible lane, synthetic/hf:moonshotai/Kimi-K3. The bug is in the Hermes-DAGger bridge route parser — it splits provider/model on the first / and then fails closed because the model remainder still contains a /. A slash inside a model id is legal (hf:moonshotai/Kimi-K3), so every agent()/llm()/tool() node aborted in <100 ms. Because head is chosen from global gate state, one gated provider set makes the same bad head for every project → fleet-wide.
TRANSPORT_REJECTS_SLASH_IN_MODEL to coding-hermes/task-router/scripts/router_spawn.py and exclude slash-model lanes from head. The existing always-run fallback fires and resolves to the slash-free deepseek-foreman/deepseek-flash.gatewayRoute in Hermes-DAGger/<project>/src/bridge/hermes_api.go splits on the first / only and keeps the model remainder verbatim; fail closed solely on empty provider/model. Also flagged the latent strings.LastIndex truncation in direct_llm.go:57.dogfooding.ts and dagger-role-tick.sh pass provider and model separately instead of concatenating them into one string.I reproduced the incident against the real public task-router with a hermetic state dir:
<project> / helios / duckbrain → head=synthetic/hf:moonshotai/Kimi-K3 (all real lanes gated)
Applying Fix A flips them to deepseek-foreman/deepseek-flash with degraded_fallback=true.
Both parser suites pass:
- TypeScript: 11/11 (node --experimental-strip-types --test route.test.ts)
- Go (mirrors the bridge): 6/6 (go test -v ./...)
Artifacts: /workspace/solution/{SOLUTION.md, route.ts, route.test.ts, go/route.go, go/route_test.go}.
# Evidence - Problem class: router-synthetic-head-model-id-slash-rejected-fail-closed - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-16T01:40:18.372Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Dagger dogfood role-tick: every agent()/llm()/tool() node died in <100ms with 'DAGGER_TOOL_MODEL: explicit provider/model route required'. Root cause chain: (1) task-router registry head for ALL projects resolved to the synthetic placeholder lane synthetic/hf:moonshotai/Kimi-K3 because every real lane was gated at resolve time (neuralwatt health DOWN since 2026-09-16T01:00:17Z, commandcode quota GATED blocked, fireworks-ai keyless fail-closed). (2) The synthetic lane model id contains a slash (hf:moonshotai/Kimi-K3). (3) dagger-role-tick.sh exported DAGGER_TOOL_MODEL=synthetic/hf:moonshotai/Kimi-K3; the dogfooding.ts pipeline modelOpt likewise routerResolve-falls to the same head. (4) <project> bridge gatewayRoute (src/bridge/hermes_api.go:461-478) splits provider/model on FIRST slash then rejects fail-closed any model still containing a slash: splitModel yields provider=synthetic model=hf:moonshotai/Kimi-K3 which still contains a slash -> explicitGatewayRouteError. Net effect: every scheduled role-tick lane (dogfood/QA/sync) that resolves its model via routerResolve or DAGGER_TOOL_MODEL dies with 0 exercised whenever the router head is the synthetic lane \u2014 fleet-wide outage class, not per-project. Fix directions: seed the router P8/fallback chain with a slash-free real provider model; or make router seed exclude synthetic placeholder lanes from head eligibility when real lanes are gated (fail-closed to a hard error instead of silently routing to an unroutable lane); or normalize the synthetic model ids to be slash-free. Verified evidence: /tmp/dagger-role-dogfooding-2575285-1789521359808344056/run.jsonl write_findings node error; role.db judge/use_for_real UNKNOWN-VALUE; router_spawn.py <project>/helios/duckbrain/<project> all head=synthetic/hf:moonshotai/Kimi-K3 live at 2026-09-16T01:20Z.", "environment": "production", "language": "typescript", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "router-synthetic-head-model-id-slash-rejected-fail-closed", "provider": "openrouter", "solved_at": "2026-09-16T01:40:18.372Z", "version": ""}