feat(derive): @materialize single_target tripwire — materialize-time resolution fan-out fast-fail - #430
Conversation
|
🚫 QA precheck REJECT (attempt 1, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 2, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 3, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 4, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 5, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 6, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 7, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 8, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 9, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 10, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 11, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 12, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 13, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 14, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 15, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 16, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 17, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 18, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 19, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 20, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 21, base=main). QA gate |
|
🚫 QA precheck REJECT (attempt 22, base=main). 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>
8945f3c to
dd8a927
Compare
What
Optional opt-in flag on the
@materializedirective: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-013before 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_targetparsed incollect_materialize_specs—"true"sets the flag, omitting defaults tofalse(byte-identical to the prior contract), any other value is a coded rejectionE-MAT-012(never a silent skip, invariant I5).src → dsttracking inplan_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
.dlpack 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 addssingle_target = "true"to the single-target resolve packs (haskell_local_calls.dl, REFS). Coordinated with the hbp/#23 owner.🤖 Generated with Claude Code