The BDD conftest routes scenarios by scenario-tag string — which wired set a tag belongs to, and which xfail reason it gets. Nothing asserts those tag strings still exist in the feature files they refer to.
Problem
tests/bdd/conftest.py carries several tag-keyed collections:
_UC003_WIRED
_UC019_WIRED
_UC002_CREATE_WIRED
_UC003_UNWIRED_REASONS
The feature files these tags come from are generated (# DO NOT EDIT -- re-run: python scripts/compile_bdd.py --merge). If a regeneration renames a tag, or a key is simply mistyped, the failure is silent in both directions:
- A stale key in a
_WIRED set means the scenario quietly stops being wired — coverage is lost with nothing red.
- A stale key in
_UC003_UNWIRED_REASONS means the scenario quietly falls back to the generic "harness not yet wired" reason.
Neither shows up in counts, because an unwired scenario xfails either way. The aggregate is identical, so no test reddens and no reviewer sees a diff.
Why now
The _UC003_UNWIRED_REASONS case is concrete: the whole point of that map is to stop reporting a deliberate, tracked divergence as a wiring TODO. A key drift silently restores exactly the misreporting it exists to prevent, and the only signal is a human reading an xfail reason in a test report.
All four symbols are recent additions, so this is a good moment to pin them before more accumulate.
Fix
A unit-level guard (no DB needed) that parses tests/bdd/conftest.py and asserts every tag key in those collections appears as a tag in tests/bdd/features/**/*.feature. Precedent exists for reading the feature tree at unit-test time — test_architecture_bdd_feature_parse.py and test_architecture_bdd_obligation_sync.py already do it.
Worth considering as a second assertion: keys in _UC003_UNWIRED_REASONS should be disjoint from the wired sets, i.e. they actually reach the unwired branch. A tag in both places is a contradiction that currently resolves silently by branch order.
Context
Raised by two independent reviewers of #1544 while reviewing the xfail-reason routing. The scope is deliberately wider than that one map, since the _WIRED sets carry the higher consequence (silent coverage loss).
The BDD conftest routes scenarios by scenario-tag string — which wired set a tag belongs to, and which xfail reason it gets. Nothing asserts those tag strings still exist in the feature files they refer to.
Problem
tests/bdd/conftest.pycarries several tag-keyed collections:_UC003_WIRED_UC019_WIRED_UC002_CREATE_WIRED_UC003_UNWIRED_REASONSThe feature files these tags come from are generated (
# DO NOT EDIT -- re-run: python scripts/compile_bdd.py --merge). If a regeneration renames a tag, or a key is simply mistyped, the failure is silent in both directions:_WIREDset means the scenario quietly stops being wired — coverage is lost with nothing red._UC003_UNWIRED_REASONSmeans the scenario quietly falls back to the generic "harness not yet wired" reason.Neither shows up in counts, because an unwired scenario xfails either way. The aggregate is identical, so no test reddens and no reviewer sees a diff.
Why now
The
_UC003_UNWIRED_REASONScase is concrete: the whole point of that map is to stop reporting a deliberate, tracked divergence as a wiring TODO. A key drift silently restores exactly the misreporting it exists to prevent, and the only signal is a human reading an xfail reason in a test report.All four symbols are recent additions, so this is a good moment to pin them before more accumulate.
Fix
A unit-level guard (no DB needed) that parses
tests/bdd/conftest.pyand asserts every tag key in those collections appears as a tag intests/bdd/features/**/*.feature. Precedent exists for reading the feature tree at unit-test time —test_architecture_bdd_feature_parse.pyandtest_architecture_bdd_obligation_sync.pyalready do it.Worth considering as a second assertion: keys in
_UC003_UNWIRED_REASONSshould be disjoint from the wired sets, i.e. they actually reach the unwired branch. A tag in both places is a contradiction that currently resolves silently by branch order.Context
Raised by two independent reviewers of #1544 while reviewing the xfail-reason routing. The scope is deliberately wider than that one map, since the
_WIREDsets carry the higher consequence (silent coverage loss).