Fix dossier-runtime `site` subcommand dispatch (isSub omits 'site')
task-runtime-site-dispatch-bug
Fix dossier-runtime site subcommand dispatch
A documented subcommand is dead. In packages/runtime/src/cli.ts, isSub() (the command-name type guard, ~lines 352–354) returns true only for provision | list | run | deprovision — it omits 'site', even though the Sub type (line 77), the switch (lines ~96–107), and the HELP text (line 37) all include site. Net effect: dossier-runtime site ... is rejected at line 86–89 with unknown command "site" (exit 2) before it can reach cmdSite. The same omission is present in the built packages/runtime/dist/cli.js (the minified isSub, function E, lists only the four names).
The fix
One line — add s === 'site' to isSub:
function isSub(s: string | undefined): s is Sub {
return s === 'provision' || s === 'list' || s === 'run' || s === 'site' || s === 'deprovision';
}
…then rebuild so dist/cli.js carries it. This is the runtime/platform layer owner's fix, not in /client-new's path: /client-new — a thin operator slash command over the control-plane CLI drives only provision/run, and the command file already notes the site caveat.
Severity
Low-but-real (p2). The feature is reachable another way today: dossier-runtime run --site builds the tenant site as part of the loop (cmdRun, the --site branch) and works correctly — so this is a dead standalone entry point, not a missing capability. Worth fixing because a documented, type-declared, HELP-advertised subcommand silently failing is a correctness/trust gap, and the guard should never have been able to drift from the Sub type it claims to narrow.
Provenance
Surfaced by the log-auditor while recording /client-new — a thin operator slash command over the control-plane CLI; the FDE confirmed the bug in both source and built dist. confidence: inferred (agent-surfaced). Board globbed before filing — no open task covered the site dispatch.
Closed 2026-06-17 — fixed at the root, not patched
Instead of the literal one-line s === 'site' (which could silently drift from the Sub union again — the very failure this records), the subcommand list was extracted into packages/runtime/src/subcommands.ts as a single SUBCOMMANDS array; both the Sub type and the isSub guard now derive from it. Adding a subcommand there forces the main() switch to handle it (TS exhaustiveness) and isSub accepts it automatically — the guard cannot omit a declared subcommand. cli.ts imports the shared guard (its local copy deleted). A 4-case regression test (test/subcommands.test.ts) pins the contract. Verified end-to-end through the built dist/cli.js: dossier-runtime site … now reaches cmdSite ("no provisioned tenant"), not the dispatcher's "unknown command". Typecheck clean; full runtime suite 64/64 green. Closed by the Principal Forward Deployed Engineer.