refactor(runtime-host): derive dispatcher operation groups from spec objects - #4402
Conversation
hqhq1025
left a comment
There was a problem hiding this comment.
I found one non-blocking correctness gap in the claimed compile-time ownership guarantee. The derived domain aliases match the current protocol, but split coordinators can still omit a newly declared operation without a type error; details are inline.
Validation completed on this exact head: clean install, npm run build:test, full repository typecheck, lint, format, git diff --check, focused dispatcher key-set probes, and a clean synthetic merge with current main. The full Runtime Host suite reported 1466 pass / 1 fail / 12 skip; the sole managed-sandbox failure reproduces on the exact merge base and is not attributable to this change. The hosted test check is still running.
Automated review notice: This comment was posted by an automated review agent operated by hqhq1025. It is not an independent human review and does not replace one.
6976844 to
bcf9e70
Compare
…objects The operation dispatcher declared each coordinator's operation grouping a second time by hand — as literal Extract/Exclude lists — even though the per-domain spec objects that compose HOST_OPERATION_SPECS already establish which operations belong together. Converge on the derived form the file's host-core groups already use. - Every group key type is now `keyof typeof <DOMAIN>_OPERATION_SPECS`. - Name the two groupings that already spanned/omitted spec objects: SessionContinuity = continuity + transcript; SessionCatalog = catalog + turns (previously reached its coordinator only via the subtraction sweep). - Delete the `Exclude` subtraction, so a spec object no coordinator claims is a compile error rather than a silent reassignment into Catalog. - Replace the hand-written unavailable access/collaboration handler map with a loop over its two spec objects, parameterised by message. - Drive both `HostCoreOperationKey` and the runtime host-core partition from a single `HOST_CORE_SPEC_OBJECTS` declaration. Protocol domain and coordinator ownership remain free to differ; the difference is now declared once, on the server side, by naming the spec objects each coordinator serves. Fixes apache#4395 Generated-by: Claude Code
…he spec The Turn spec object is served by three coordinators that each Pick a fixed subset of TurnOperationHandlerMap. Because domain composition seeds every domain operation with the operation_unavailable fallback, a Turn operation added to TURN_OPERATION_SPECS that no coordinator claims compiled and silently kept the fallback rather than failing. Add a `satisfies TurnOperationHandlerMap` completeness assertion where the three coordinators are already merged, so an unclaimed Turn operation is a typecheck error at the composition site. Verified: adding a probe key to TURN_OPERATION_SPECS now fails the Runtime Host typecheck (TS2741) instead of passing. Refs apache#4395 Generated-by: Claude Code
4318f87 to
d282588
Compare
hqhq1025
left a comment
There was a problem hiding this comment.
The previous Turn ownership finding is fixed on d282588c56a24883e745a9541fbee85eda9da359; I did not find any remaining P0-P3 issue in this revision.
The new completeness assertion covers the same three handler maps used by the production execution module. A temporary added Turn operation now fails the Runtime Host build with TS2741 at execution-composition.ts:1194, instead of silently retaining the unavailable fallback. I also checked the complete dispatcher-group refactor, unavailable-handler key partition, and the current-main synthetic merge.
Validation completed: clean install, npm run build:test, full repository typecheck, changed-file lint/format, ASF headers, git diff --check, focused dispatcher/host/execution composition tests (25/25), and a clean synthetic merge with current main. The full Runtime Host suite reported 1541 pass / 1 fail / 12 skip; the sole live-sandbox failure reproduces on the current-main synthetic merge and is not attributable to this PR. Hosted plan, heavy, and windows_recovery are green; the final hosted test job is still queued, so this review does not claim that merge gates are complete.
Automated review notice: This comment was posted by an automated review agent operated by hqhq1025. It is not an independent human review and does not replace one.
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks — reviewed d282588c. No findings.
@hqhq1025 already covered the split-Turn gap and confirmed the satisfies TurnOperationHandlerMap fix with a probe, so I checked the thing a type-level regrouping is most likely to get wrong silently: whether routing is preserved.
The old SessionCatalogOperationKey was a residue — all session.* minus five groups — and the new one is an explicit union of the catalog and turns spec objects. Those agree only if every session.* key lives in one of the seven named spec objects. It does: the keys are distributed across session-catalog (6), session-revision (3), session-retirement (3), session-transcript (2), session-continuity (2), session-turns (1), session-todo (1), session-effects (1), with nothing declared elsewhere. So the residue and the union are the same set and no operation changes coordinator. The description's claim that session-turns previously reached its coordinator only by being swept into the residue is accurate, and it now lands in the same place by name.
The 36 new imports are the honest price of deriving from the spec objects rather than restating them, and the file still comes out 78 lines lighter on a form the codebase already used in three places. Deleting the Exclude so an unclaimed spec object becomes a compile error rather than a silent reassignment into Catalog is the part that actually pays.
Evidence boundary: I read the dispatcher diff and enumerated the session.*/subscription.* key distribution across the protocol directory on this head. I did not re-run the suites or repeat @hqhq1025's Turn probe.
AI-assisted review: drafted with Maka; I verified the key distribution and the old/new set equivalence against the branch source myself.
Summary
HOST_OPERATION_SPECSis assembled by merging per-domain spec objects, so the domain of every operation is already established by which object declares it.operation-dispatcher.tsthen declared that same grouping a second time by hand, as literalExtract/Excludelists — while three host-core groups already derived their keys withkeyof typeof …_OPERATION_SPECS. This converges every group on that existing form.keyof typeof <DOMAIN>_OPERATION_SPECS.SessionContinuityOperationKey= continuity + transcript spec objects;SessionCatalogOperationKey= catalog + turns (session-turns previously reached its coordinator only because theExcludesubtraction swept it there — it had no group of its own).Excludesubtraction is deleted, so a spec object that no coordinator claims is now a compile error instead of a silent reassignment into Catalog.createUnavailableDomainOperationHandlers, including itsoperation_unavailableassertion).HostCoreOperationKey(type) and the runtime host-core partition are driven from a singleHOST_CORE_SPEC_OBJECTSdeclaration.Protocol domain and coordinator ownership remain free to differ permanently; the difference is now declared once, on the server side, by naming the spec objects each coordinator serves — never the reverse.
Split-group exhaustiveness (second commit)
For the ~33 groups served by a single coordinator, the derived group type is a total
OperationHandlerMap, so omitting a handler is already a compile error.Turnis the one group split across three coordinators (turn-control,interactive-turn,root-turn), eachPick-ing a fixed subset. BecausecomposeRuntimeHostDomainHandlersseeds every domain operation with theoperation_unavailablefallback, a Turn operation that none of the three claimed compiled and silently kept the fallback — the exact "coordinator serves only part of a spec object" case the issue's step 3 flags.The second commit closes that gap with a
satisfies TurnOperationHandlerMapcompleteness assertion where the three coordinators are already merged (execution-composition.ts). An unclaimed Turn operation is now a typecheck error at the composition site, so the issue's step‑5 guarantee ("removing its handler is a compile error") holds for the split group too.Fixes #4395
Verification
All run locally in
packages/runtime-host:npm run typecheck— pass (exit 0)npm run build— pass (exit 0)npx biome lint/biome formaton the changed files — cleannpm run test:dist— 1467 pass, 12 skipped, 0 fail (1479 tests)Followed the issue's suggested method: added temporary per-group
AssertEqual<oldForm, derivedForm>instantiations and typechecked to confirm each derived form is exactly equal to the hand-written one, then removed them. For the split-group fix I ran the reviewer's own probe — temporarily addingturn.review-probetoTURN_OPERATION_SPECS— and confirmed the Runtime Host typecheck now fails withTS2741("turn.review-probe"missing but required inTurnOperationHandlerMap) at the composition site, then reverted the probe.Review response
Addresses the P2 finding on the first revision (split Turn coordinators could omit a newly declared operation without a type error). The compile-time assertion is added in the second commit; the earlier over-claim in this description is corrected above.
Rebase & CI note
Rebased onto latest
main. The only code conflict was inoperation-dispatcher.ts:mainhad added a newplugin.*operation group in the region this PR rewrites — resolved by converging that group to the same derived form (keyof typeof PLUGIN_PLATFORM_OPERATION_SPECS). The two changed files areoperation-dispatcher.tsandexecution-composition.ts; no other files are touched.AI use
Select exactly one:
Tool(s) and scope: Claude Code — implemented the refactor (deriving the group types, removing the subtraction, the two loop/single-source collapses) and the split-group exhaustiveness assertion, and ran the verification above. Reviewed by me before submitting. Both commits carry a
Generated-by: Claude Codetrailer.Checklist
Does this PR entail a change in behavior?