Skip to content

feat(missions): cross-campaign dependency edges, with an anti-cascade rule - #575

Merged
DrMurphyIsIn merged 1 commit into
mainfrom
feat/cross-campaign-edges
Sep 19, 2026
Merged

DrMurphyIsIn merged 1 commit into
mainfrom
feat/cross-campaign-edges

Conversation

@DrMurphyIsIn

Copy link
Copy Markdown
Owner

Remedies the structural finding from the 2026-09-18 registry audit (#574): there was no cross-campaign edge mechanism at all, so authors substituted same-campaign proxies while node titles named the real source. Five nodes ended up with edges the corpus does not support. The same audit found all 44 proof links are via = direct, so the reduction relation — the one that actually consumes dependency edges — had never been used once. The registry was recording a chain of reductions while holding a collection of independent direct proofs.

The mechanism

A depends_on entry is now either a bare slug (same campaign, unchanged and still the default) or a qualified <campaign-dir>:<NodeSlug>, e.g. rh:RH_rvm_unconditional. The campaign part is the directory name, because that is what --campaign takes and what a reference must resolve against.

Three deliberately separate layers:

  1. load_campaign validates internal refs exactly as before; an external ref is checked for syntax and file existence only, so there is no recursion or load-order coupling.
  2. load_universe resolves every external ref for real and asserts global acyclicity — a cycle like rh:A -> mm:B -> rh:A is invisible to any per-campaign check by construction.
  3. compute_universe_closures runs one global closure fixpoint keyed by (campaign, slug). verify_campaign auto-loads the sibling universe and falls back to None, which leaves external edges dirty.

The anti-cascade rule, which is the point

A cross-campaign edge is a new path for an unverified premise to reach a proved node, and the audit demonstrated that the gate could already be fooled by a stub. So:

An edge counts toward a clean closure only when its target genuinely resolves, has status proved, and is itself closure-clean under the global fixpoint. Everything else is dirty.

Two traps hit during implementation, both now tests. A missing universe yields dirty, never clean. And the first implementation fell back to the external target's stored closure_clean flag — test_transitive_dirt_propagates_across_campaigns caught that laundering transitive dirt across a campaign boundary, because a reduction node's stored flag can read true while its own chain is dirty. That fallback is gone.

Scope, stated honestly

This does not fix the five unsupported edges. Only one of them is a genuine cross-campaign case and it lives on an unmerged branch; the other four are dependency-correctness questions that need an author's judgement, not a syntax. No node status changes here, and nothing becomes proved.

Verification

19 new tests, most of them negative. Mission subset: 331 passed. All four real campaigns load as a universe and mission verify reports OK for each.

conjecture1_proved = False.

🤖 Generated with Claude Code

… rule

load_campaign rejected any depends_on target outside its own campaign, so authors
substituted same-campaign proxies while node titles named the real source. The
2026-09-18 audit found five nodes whose edges the corpus does not support, and that
all 44 proof links are via=direct -- the reduction relation, the one that consumes
edges, had never been used.

A depends_on entry is now a bare slug (same campaign, unchanged) or a qualified
'<campaign-dir>:<NodeSlug>'. Three layers: load_campaign validates external refs by
file existence only (no recursion); load_universe resolves them and asserts GLOBAL
acyclicity, which catches rh:A -> mm:B -> rh:A that no per-campaign check can see;
compute_universe_closures runs one global fixpoint. verify_campaign auto-loads the
sibling universe and falls back to None, which leaves external edges dirty.

THE ANTI-CASCADE RULE: an edge counts only when its target resolves, is proved, and
is itself closure-clean under the global fixpoint. Everything else is dirty. The
first implementation fell back to the target's STORED closure_clean flag when no
global pass was available; test_transitive_dirt_propagates_across_campaigns caught
that laundering transitive dirt across a boundary, and the fallback is gone.

19 new tests, most negative. Mission subset 331 passed; all four campaigns load as a
universe and verify OK. No node status changes. conjecture1_proved = False.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@DrMurphyIsIn
DrMurphyIsIn merged commit 6db78e0 into main Sep 19, 2026
105 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.

1 participant