Skip to content

fix: route a kernel request on the target PolicyGate admitted - #1889

Merged
chaojhou merged 1 commit into
mainfrom
fix/chenyi/router-routes-the-admitted-target
Oct 17, 2026
Merged

chaojhou merged 1 commit into
mainfrom
fix/chenyi/router-routes-the-admitted-target

Conversation

@chennyiiis

Copy link
Copy Markdown
Contributor
  • Description: what and why

Follow-up to review feedback on #1881 (finding 4, description-claim). The reviewer found that #1881's description was wrong about unknown_target_agent being unreachable, and the reason it was wrong is a bug.

PolicyGate decides whether a request may be routed by its stripped target_agent (policy/gate.py: target = str(payload.get("target_agent", "")).strip()), and _handle_request then dispatched on the raw one. So a request naming " kernel_agent " passed admission and fell straight through to the unknown-target refusal - the agent it named was enabled, had a registered handler, and was allowed to serve it.

The router now reads the field the way the gate read it, so the two agree on the name.

The reply kind is deliberately left as sent. The requester awaits <kind>_done built from its own string, so normalising that would answer on a key nobody is listening to. A padded kind therefore still comes back unknown_kernel_kind; that half belongs at the boundary - the gate should refuse a name it has to normalise before it recognises it - and is not in this PR.

  • Linked issue(s): close/fix refs

Review feedback on #1881.

  • Tests: added/updated? commands run?

test_a_padded_target_agent_reaches_its_handler sends " kernel_agent " and asserts the request reaches the kernel-agent arm - refused for its kind, not for its target. It fails on main with unknown_target_agent and passes here.

Run locally: pytest over test_profile_and_kernel_handlers.py, test_policy_gate.py, test_agent_roles_and_policy.py, test_lifecycle_wiring.py, test_regression_locks.py - 257 passed; the one failure is a missing optional TraceLens import in the local environment and reproduces on main.

  • Size/complexity triggers crossed: split, or why the shape is right:

None. One line changes and every measured value for _handle_request and the module is unchanged.

  • If this simplifies or refactors: which mechanism was removed, which contract was preserved, and the tests that show it:

Not a refactor - a correctness fix. It removes a second reading of one value: the gate and the router now resolve target_agent the same way.

  • Observable effect:

A kernel request whose target_agent carries surrounding whitespace now runs its handler instead of coming back failed with unknown_target_agent. An operator previously saw the request refused, and recorded in the session's failure ledger, for naming an agent that does exist and was ready to serve it.

  • Breaking changes: no

  • PR addresses single concern: yes

  • Root cause is upstream: no

…dmitted

PolicyGate decides whether a request may be routed by its stripped
``target_agent`` (`policy/gate.py`), and the router then dispatched on the raw
one. A request naming `" kernel_agent"` therefore passed admission and fell
through to the unknown-target refusal: the agent it named was enabled, had a
handler and was allowed to serve it.

The router now reads the field the way the gate read it, so the two agree on
the name. The reply kind is deliberately left as sent: the requester awaits
``<kind>_done`` built from its own string, so normalising that would answer on
a key nobody is listening to.

Observable effect: a kernel request whose ``target_agent`` carries surrounding
whitespace now runs its handler instead of coming back failed with
``unknown_target_agent``. An operator saw the request refused and recorded in
the session's failure ledger for naming an agent that does exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chennyiiis
chennyiiis requested a review from a team as a code owner October 14, 2026 11:15
@github-actions

Copy link
Copy Markdown

Code metrics gate: PASSED

Judged: the 2 files this change touches. Files it does not touch never fail it; anything found there is listed under Outside this change for information.

Dimension Limit New Worse Baseline out of date Baseline entries vs base
Cyclomatic complexity fails > 20 0 0 0 73 +0
Cognitive complexity fails > 30 0 0 0 289 +0
Function length (lines) fails > 80 0 0 0 453 +0
Nested block depth fails > 5 0 0 0 27 +0
Module length (lines) warns > 800, fails > 1200 0 0 0 53 +0
Duplicated lines per file fails > 0 0 0 0 120 +0
Dead code (vulture) fails > 0 0 0 0 2 +0
Check Findings Effect
Comments 0
English only 0
Production code imports test code 0
Repeated literals 0
A1 Private name of another package 0
A8 Flag argument 0
A9 Tuple return 0
A10 Raw vocabulary comparison 0
A11 Hidden global write 0
A12 Pure forwarder 0
A12 Single-implementation abstraction 0

Already over at the base (backlog, not this change's): 3

Unit Dimension Base Now
src/hyperloom/orchestrator/loop/intent_router.py:858 IntentRouter.handle_delegate Cognitive complexity 41 41
src/hyperloom/orchestrator/loop/intent_router.py:858 IntentRouter.handle_delegate Function length (lines) 181 181
src/hyperloom/orchestrator/loop/intent_router.py:1 Module length (lines) 1596 1596
85 findings in files this change does not touch

Outside this change (informational): 85

Unit Dimension Baseline Now
src/hyperloom/orchestrator/enablement/recipe/projections.py project_launch_evidence Cognitive complexity absent 36
src/hyperloom/orchestrator/state/shared_state.py resolve_graded_comparison Cognitive complexity absent 34
src/hyperloom_kb/collect/mapping.py _experience Cognitive complexity absent 31
src/hyperloom_kb/schema.py FieldDeclaration.__post_init__ Cognitive complexity absent 32
src/kernelforge/cli/forge_loop_command.py _prepare_measurement_driver Cognitive complexity absent 36
src/kernelforge/cli/forge_loop_command.py _read_kb_warm_start Cognitive complexity absent 40
src/kernelforge/loop/runner.py IterationLoop._collect_session_candidate Cognitive complexity absent 44
src/kernelforge/loop/runner.py IterationLoop._rule_on_attempt Cognitive complexity absent 38
src/hyperloom_kb/tests/test_cli.py Duplicated lines per file absent 18
src/hyperloom_kb/tests/test_global_identity_and_pull.py Duplicated lines per file absent 13
src/hyperloom_kb/tests/test_local_state.py Duplicated lines per file absent 18
src/hyperloom/inference_optimizer/cli/__init__.py _reexport_session_environment Function length (lines) absent 112
src/hyperloom/inference_optimizer/cli/__init__.py _resolve_agent_lineup Function length (lines) absent 89
src/hyperloom/inference_optimizer/cli/__init__.py _resolve_run_topology Function length (lines) absent 92
src/hyperloom/inference_optimizer/cli/__init__.py _resume_session Function length (lines) absent 171
src/hyperloom/inference_optimizer/cli/__init__.py _seed_fresh_session Function length (lines) absent 183
src/hyperloom/inference_optimizer/multi_node/cli.py _restart_multinode Function length (lines) absent 107
src/hyperloom/inference_optimizer/multi_node/scripts/launch_multinode.py _build_parser Function length (lines) absent 84
src/hyperloom/inference_optimizer/multi_node/scripts/launch_multinode.py _spawn_rank_actors Function length (lines) absent 90
src/hyperloom_kb/http_service.py RequestHandler._dispatch Function length (lines) absent 91
src/hyperloom_kb/sync.py GlobalSync.pull Function length (lines) absent 86
src/kernelforge/cli/forge_loop_command.py _RunReporter.build_result Function length (lines) absent 91
src/kernelforge/cli/forge_loop_command.py _prepare_measurement_driver Function length (lines) absent 140
src/kernelforge/cli/forge_loop_command.py _read_kb_warm_start Function length (lines) absent 154
src/kernelforge/loop/knowledge_integration.py _measure_warmstart_field Function length (lines) absent 83

...and 60 more; the job log lists every row.

Verdict computed by the gate scripts in /home/runner/work/_temp/code-metrics-gate, not by this tree's copy.

Thresholds and sources: [tool.hyperloom.code_metrics] in pyproject.toml. Tools: complexipy 8.0.1, jscpd 5.4.1, ruff 0.16.2, vulture 2.16.

@chaojhou chaojhou left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #1889 -- fix: route a kernel request on the target PolicyGate admitted

What it does: PolicyGate admits a REQUEST on its whitespace-stripped target_agent, but IntentRouter._handle_request routed on the raw value, so a padded " kernel_agent " passed admission and was refused as unknown_target_agent. The router now strips the name the same way, so the gate, the dispatcher's sequence check and the router agree on the target.

Blocking issues: none

SKIPPED: V4 -- #1869, #1675 and #1276 change more than 100 files and only their first 100 were compared; overlap there is unchecked.

Checked: src/hyperloom/orchestrator/loop/intent_router.py _handle_request, handle_intent, _auto_reject; src/hyperloom/orchestrator/policy/gate.py _validate_request; src/hyperloom/orchestrator/loop/dispatcher.py sequence_denial_for_request; tree-wide sweep for every non-test reader of target_agent | Ran: git grep/git show at head and base; gh pr diff 1888 for overlap | Base: 190604f | Head: d9a01f6

LGTM

@chaojhou
chaojhou merged commit 7e57b1e into main Oct 17, 2026
40 checks passed
@chaojhou
chaojhou deleted the fix/chenyi/router-routes-the-admitted-target branch October 17, 2026 03:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants