Skip to content

feat(route): route dynamic-predicate reads through the warm daemon (NRN-218)#106

Merged
dbtlr merged 5 commits into
mainfrom
nrn-218-daemon-field-gate
Jul 8, 2026
Merged

feat(route): route dynamic-predicate reads through the warm daemon (NRN-218)#106
dbtlr merged 5 commits into
mainfrom
nrn-218-daemon-field-gate

Conversation

@dbtlr

@dbtlr dbtlr commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Closes the perf cliff where the ergonomic dynamic-predicate spelling (norn find --type note) was systematically ~3× slower than canonical --eq type:note because it forced Direct execution. The field-universe gate now runs daemon-side: dynamic-predicate reads route as-is, the daemon validates against its warm cache with the exact gate code the direct path uses, and a refusal crosses back byte-identically. One round trip, no new public MCP surface.

Routed --type note: 17ms (≈ canonical's 15ms) vs 52ms direct on a real ~1.4k-doc vault.

Design

  • grammar::gate_dynamic_refusal composes the same field_universe + gate_dynamic_fields the direct path uses — one gate, two call sites, cannot drift.
  • Desugared field names cross as dynamic_keys#[serde(default)] #[schemars(skip)]: a private norn-CLI↔daemon channel, absent from published input/output schemas and tools/list (parity gate proves it; new negative schema-pin tests on both tools make removing a skip fail loudly).
  • A refusal returns as a schema-skipped dynamic_field_error sibling; the client re-emits it verbatim and exits with direct's exit code, committed to routing — no double execution. NRN-222's request-connection version gate guarantees daemon and client are the same build, so byte-identity is structural.
  • Direct path unchanged; operator-note forwarding (NRN-215) composes with the refusal path.

Verification

  • Quartet clean: check --locked / 2327 tests, 0 failed / clippy -D warnings / fmt; Cargo.lock untouched.
  • Byte-identity tests for known + unknown dynamic fields in both routing suites (stdout, stderr, exit).
  • Dogfood on the real vault: known + unknown dynamic predicates byte-identical routed vs direct; 11 served markers prove daemon service including the refusal path; supervised service restored after the test window.

Adversarial review

One round (all agents Opus): 8 candidates, 4 refuted by verifiers. Honest tally 3 findings — 2 fixed, 1 dismissed: the private-channel schema pins were missing on BOTH tools (a verifier wrongly refuted the find-side gap; the implementer's grep proved it real and covered both), and the foreign-client dynamic_keys injection surprise is dismissed on the record (out-of-contract input, deterministic self-describing refusal, no data risk).

Adversarial-Review: run engine=code-review tier=high findings=3 fixed=2 dismissed=1 deferred=0

dbtlr added 5 commits July 8, 2026 13:47
…N-218)

Add DynamicFieldRefusal + gate_dynamic_refusal to grammar (the daemon
variant of gate_dynamic_query, composing the same field_universe +
gate_dynamic_fields), and run it in vault.find/vault.count against the
warm cache. A refused dynamic key crosses back as a private
dynamic_field_error envelope sibling; carrier fields (dynamic_keys input,
dynamic_field_error output) are #[schemars(skip)] so they stay off the
published schemas and tools/list.
… (NRN-218)

Thread the desugared dynamic_keys onto the vault.find/vault.count wire
(to_mcp_arguments) and drop the client-side is_empty guard that forced
Direct. In route_read, a daemon-computed dynamic_field_error is re-emitted
byte-identically (exit 1) after forwarding operator notes, committing to
routing instead of falling back to a second direct execution.
E2E: known dynamic field routes byte-identically; unknown field is
refused daemon-side with byte-identical stderr + exit 1, served (proven
via the served-marker counter, and no 'using direct execution' under
--verbose). CHANGELOG [Unreleased] notes the fixed asymmetry + the private
wire addition; the v0.45.0 shipped note stays intact.
Negative schema assertions on both vault.find and vault.count: the
dynamic_keys input carrier and dynamic_field_error output carrier must be
absent from the tools/list inputSchema/outputSchema, with a positive
vacuity guard on a real field — removing a #[schemars(skip)] now fails a
test instead of leaking the private channel into the public catalog.
One review round + fix (engine=code-review, agents pinned to Opus):
8 candidates, heavy verifier refutation (4). Honest tally: 3 real
findings — 2 fixed (private-channel schema pins on BOTH vault.find
and vault.count; a verifier wrongly refuted the find-side gap, the
implementer's grep proved it real and covered it), 1 dismissed
(foreign-client dynamic_keys injection: out-of-contract input,
deterministic self-describing refusal, no data risk).

Adversarial-Review: run engine=code-review tier=high findings=3 fixed=2 dismissed=1 deferred=0
@dbtlr dbtlr merged commit 0e33eb3 into main Jul 8, 2026
7 checks passed
@dbtlr dbtlr deleted the nrn-218-daemon-field-gate branch July 8, 2026 18:09
@dbtlr dbtlr mentioned this pull request Jul 8, 2026
dbtlr added a commit that referenced this pull request Jul 8, 2026
Cuts v0.46.0 — the daemon-reads-complete release (Phase 1 exit).
Version 0.45.1 -> 0.46.0; CHANGELOG promoted with theme paragraph.
Shipped: #101 #102 #103 #104 #105 #106 #107.

Adversarial-Review: run engine=inline tier=low findings=0 fixed=0 dismissed=0 deferred=0
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.

1 participant