Skip to content

feat(derive): @materialize single_target tripwire — materialize-time resolution fan-out fast-fail - #430

Merged
Disentinel merged 1 commit into
mainfrom
derive/materialize-resolution-tripwire
Jun 16, 2026
Merged

feat(derive): @materialize single_target tripwire — materialize-time resolution fan-out fast-fail#430
Disentinel merged 1 commit into
mainfrom
derive/materialize-resolution-tripwire

Conversation

@Disentinel

Copy link
Copy Markdown
Owner

What

Optional opt-in flag on the @materialize directive:

@materialize(edge_type = "CALLS", single_target = "true")
resolved(C, M) :- ...

asserts each source endpoint resolves to at most one distinct target. A pack head that yields two distinct dsts for one src aborts the run with coded E-MAT-013 before any commit — catching a resolver fan-out (the #423-class ×4.8 REFS explosion) at its producing pack, rather than after it has polluted the graph.

Why this, and why it is NOT the authoritative gate

resolution-is-a-function (≤1 target per source) is a property of the final merged graph, which has multiple producers — datalog packs + native resolvers + orchestrator-derived edges. A producer-local check therefore gives a false-green when a different producer violates the property. So this tripwire is deliberately scoped to one pack's own output and is an optional early signal in the derive zone.

The authoritative resolution-is-a-function gate is the orchestrator's post-analyze whole-graph check (group-by (source, resolvedVia) → distinct ≤ 1), which sees every producer (coordinated with the fleet; tracked separately). This PR is the cheap producer-side complement, not a replacement.

Mechanism

  • single_target parsed in collect_materialize_specs"true" sets the flag, omitting defaults to false (byte-identical to the prior contract), any other value is a coded rejection E-MAT-012 (never a silent skip, invariant I5).
  • per-spec src → dst tracking in plan_writeback; a second distinct dst for the same src is the fan-out (E-MAT-013). A duplicate (src, dst) fact is not a fan-out (dedup stays downstream on (src, dst, edge_type)).

Tests

3 new unit tests (parse + bad-value reject + fan-out abort + clean single-target/dup pass); full derive:: suite green (312 passed / 0 failed).

Adoption (follow-up, sequenced)

No .dl pack is changed here — the mechanism ships independently so it does not couple any pack to this PR's mergeability. Once merged, a trivial one-line follow-up adds single_target = "true" to the single-target resolve packs (haskell_local_calls.dl, REFS). Coordinated with the hbp/#23 owner.

🤖 Generated with Claude Code

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 1, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 2, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 3, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 4, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 5, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 6, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 7, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 8, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 9, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 10, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 11, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 12, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 13, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 14, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 15, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 16, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 17, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 18, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 19, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 20, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Disentinel

Copy link
Copy Markdown
Owner Author

🚫 QA precheck REJECT (attempt 21, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

@Grafema-AI-Ops

Copy link
Copy Markdown
Collaborator

🚫 QA precheck REJECT (attempt 22, base=main).

REJECT[zone]: diff touches engine zone (tier 3, Vadim/feat/datalog):
packages/rfdb-server/src/derive/materialize.rs
packages/rfdb-server/src/derive/pin_sidecar.rs
FLAG[rust]: .rs touched but no cargo on VM — compile gated by CI (REG-1177), QA agent must scrutinize

QA gate

…resolution fan-out fast-fail

Optional opt-in flag: @materialize(edge_type="T", single_target="true")
asserts each source endpoint resolves to AT MOST ONE distinct target. A pack
head that yields two distinct dsts for one src aborts the run (E-MAT-013)
BEFORE any commit — catching a resolver fan-out (the #423-class ×4.8 REFS
explosion) at its producing pack rather than after it pollutes the graph.

This is an OPTIONAL early signal scoped to ONE pack's own output. The
AUTHORITATIVE resolution-is-a-function gate remains the orchestrator's
post-analyze whole-graph check, which sees every producer (packs + native
resolvers + orchestrator-derived edges) — a producer-local check gives a
false-green when a different producer violates the property.

- single_target parsed in collect_materialize_specs (E-MAT-012 on bad value)
- per-spec src->dst tracking in plan_writeback (E-MAT-013 on fan-out; a
  duplicate (src,dst) fact is not a fan-out)
- 3 tests; full derive suite green (312/0)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Disentinel
Disentinel force-pushed the derive/materialize-resolution-tripwire branch from 8945f3c to dd8a927 Compare June 16, 2026 15:43
@Disentinel
Disentinel merged commit 76e5996 into main Jun 16, 2026
13 checks passed
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