Skip to content

Bidirectional relation check is type-blind, so all 38 of its warnings are false positives #93

Description

@dieterbaier

Problem

The bidirectional-relation check in scripts/validate-metamodel.rb (around
lines 236–247) compares only artifact ids. It warns whenever A points at B
and B points at A, whatever the two relation types mean.

That makes every warning it currently emits a false positive, and it drowns the
real violations it exists to catch.

Evidence

Measured across all source front matter, excluding generated/:

Bidirectional pairs reported 38
Type combination, all 38 documents / refines
Pairs involving a depends_on or relates_to back-pointer 0
depends_on relations anywhere in the source 0

The 38 are the chapter pattern: a chapter documents its detail page and the
detail page refines the chapter. Two distinct semantic claims, each
legitimately outgoing. Nothing to remove.

The signal cost was observed directly while working on #86. A genuine
back-pointer was added temporarily to a risk whose ADR already declared
introduces_risk, exactly the relation relation-rules.md forbids. The
validator reported it as one more line among 38 identical-looking warnings,
then the probe was reverted. A reader scanning that output has no way to tell
the one that matters from the thirty-eight that do not.

The authoritative-outgoing-relations convention itself is fully held: there is
not one back-pointer in the repository. The check simply cannot show that.

What the check must distinguish

Not by relation type equality — that rule is wrong, and the repository already
contains the counterexample. The canonical case in
features/metamodel-validation.feature:88, bridged to
test/validate_metamodel_test.rb:430, is ADR addresses QS plus
QS depends_on ADR: two different types, and a violation. It must keep
warning.

Shape Example Verdict
Generic back-pointer mirroring a directional relation ADR introduces_risk R + R depends_on ADR warn — this is the forbidden reciprocal
Same relation type in both directions A refines B + B refines A warn — contradictory or duplicated
Two distinct, semantically active claims DOC documents DOC' + DOC' refines DOC silent — both are legitimate outgoing relations

relation-rules.md already names the discriminator: depends_on is for
"legitimate hierarchical or dependency relationships, not as a reciprocal for
other relation types
". The check needs to encode that distinction; the exact
classification is the work of this issue, not a foregone conclusion.

Decisions to make

  • Whether a confirmed back-pointer stays a warning or becomes an error. It is
    currently a warning, and ./build.sh validate passes with all 38 present.
  • Whether relates_to counts as a back-pointer alongside depends_on.
  • Whether the legitimate documents / refines pair is recognised structurally
    or by an explicit allowed-combination list.

Behaviour specification

This changes observable validator behaviour, so bdd-specification applies. The
existing scenario is kept and narrowed rather than deleted — it describes a case
that must still warn — and the silent case needs one of its own:

  • Bidirectional relation is detected stays, and its fixture stays the
    back-pointer shape.
  • A new scenario covers two distinct outgoing claims between the same pair and
    asserts that no warning is emitted.

Both bridge into test/validate_metamodel_test.rb under the existing naming
convention.

Acceptance criteria

  • A back-pointer mirroring a directional relation is still reported.
  • Two artifacts making distinct, semantically active claims about each other
    are not reported.
  • ./build.sh validate reports 0 bidirectional warnings for the current
    source tree, down from 38.
  • The existing scenario and its bridged test still pass, unchanged in intent.
  • A scenario covers the silent case, bridged to a test.
  • The rule the check encodes is not restated in the validator's comments as
    a second source; it references relation-rules.md and the metamodel.
  • The decisions above are recorded at proportionate size — apply Add an ADR proportionality gate to the architecture workflow #66 before
    reaching for an ADR.

Relationship to other work

Origin

Found on 2026-09-04 while answering whether the authoritative-outgoing-relations
convention still holds after #92. It does — but the only automated check
defending it cannot demonstrate that, because its output is entirely false
positives.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions