fix(e2e): two anchors #2057 broke that 49 green checks did not see - #2123
Conversation
… for the same reason "6,244 anchors, zero unresolvable" was measured with a reimplementation of gate 46's resolver rather than the resolver. It was wrong in both directions. Mine ignored two things the real one does. The flat `openspec/specs/<cap>.md` spelling, which predates the directory form and which the helper explicitly normalises: that alone made it call 13 of planix's healthy anchors dangling. And fragment checking: the helper verifies a `#fragment` names a heading somebody wrote, and mine stopped at the file. Run properly, this repo has 28 unresolved `@e2e` anchors, every one of them "anchor not found" rather than a missing file. That is the opencatalogi#85 shape the gate was built for, surviving in the half of the corpus the gate does not read. Two of the 28 are this session's own. #2057 renumbered the kanban delta's scenarios from `DASH-V1-006d/e` to `006f/g` to clear a collision with two the spec already had, and left `kanban-board-keyboard-status-transition.spec.ts` citing the old ids. Every check passed, the tests kept running, and they kept reporting green while naming scenarios that no longer existed. Gate 46 never looked because they are `@e2e`. Both are repointed at the canonical `openspec/specs/dashboard/spec.md`, per the rule this change writes down, and each fragment was probed through the real helper before it was written. The other 26 are pre-existing and stay. Each needs a judgement about which scenario it meant, which is the work rather than the sed, and the gate fix filed upstream surfaces them on the next PR that touches those files. Upstream gaps filed with the fleet measurement, taken with the real helper across 21 apps: ConductionNL/.github#726 (gate 46's pattern excludes `@e2e`; 1,964 such anchors fleet-wide, 194 dangling, against 55,720 `@spec` anchors with 1) and #727 (`appinfo/` and `scripts/` never enumerated; 52 anchors unopened, and 8 of openregister's 9 in `routes.php` are dangling, two of them ending in a stray full stop that was never a path). The rule underneath all of it: stop reimplementing the instrument. Every wrong number here came from a hand-rolled resolver and every right one came from running `check_spec_anchors.py`.
Quality Report — ConductionNL/dossiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue3-compile | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 106/106 | |||
| npm | ✅ | ✅ 549/549 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ⏭️ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-09 11:36 UTC
Download the full PDF report from the workflow artifacts.
CI302 passed, 4 failed, 1 flaky. The 4 are identical to The flaky one is 47 checks, not 4: this branch is The two tests whose anchors this fixes both ran and passedWhich is the whole point. They were passing before too, while citing scenarios that had not existed Anchor state after this PR
The 26 are pre-existing, tracked as task 5.3 on the open |
Follow-up to #2116, which merged while this was being measured. Two things it got wrong.
#2057 broke two anchors and every check passed
#2057 renumbered the kanban delta's scenarios from
DASH-V1-006d/eto006f/g, to clear a collisionwith two scenarios the
dashboardspec already had. It did not update the two citations intests/e2e/spec-coverage/kanban-board-keyboard-status-transition.spec.ts, which still named006dand006e.The tests kept running. They kept reporting green. They cited scenarios that no longer existed. 49
checks passed, twice, across #2057 and #2066.
Nothing caught it because gate 46 does not read
@e2e. Under@specit would have failed the sameafternoon. This is the clearest example I have of the gap now filed as ConductionNL/.github#726, and it
is self-inflicted, which is why it is worth writing down rather than quietly fixing.
Both are repointed at the canonical
openspec/specs/dashboard/spec.md#scenario-dash-v1-006f-…and…006g-…, per the convention #2116 landed. Each fragment was probed through the real helper beforeit was written.
The measurement in #2116 was wrong, and wrong the way everything else here was wrong
#2116 claims "6,244 anchors, zero unresolvable". That was measured with a reimplementation of gate
46's resolver rather than the resolver, and it was wrong in both directions.
Mine missed two things the real one does:
openspec/specs/<cap>.mdspelling, which predates the directory form and which thehelper explicitly normalises. That alone made mine call 13 of planix's healthy anchors dangling.
#fragmentnames a heading somebody actuallywrote. Mine stopped at the file.
Run properly, dossiq has 28 unresolved
@e2eanchors, every one of themanchor not foundratherthan a missing file. That is exactly the opencatalogi#85 shape gate 46 was built for, surviving in the
half of the corpus the gate does not read.
@e2e@spec(real gate, real scope)The 26 that remain are pre-existing and stay. Each needs a judgement about which scenario it meant,
which is the work rather than the sed, and the gate fix filed upstream surfaces them on the next PR
touching those files. Tracked as task 5.3 on the still-open
spec-anchors-name-the-capabilitychange,which is why that change is not archived.
Upstream, filed with the fleet measurement
Taken with the real helper across all 21 fleet apps, by rewriting
@e2etags to@specin a probefile outside each repo and running
check_spec_anchors.pywith cwd set to the app:@spec\s+(openspec/...), so@e2eis neverread. 1,964 such anchors fleet-wide, 194 dangling, concentrated in 6 repos. Against 55,720
@specanchors with 1 dangling: the gate works, it just does not look at a fifth of the corpus.Recommended warning-only first, with a deadline rather than an open one.
appinfo/andscripts/are never enumerated. 52 anchorsunopened, and 8 of openregister's 9 in
appinfo/routes.phpare dangling, two of them ending ina stray full stop that was never a path.
The rule underneath all of it
Stop reimplementing the instrument. Every wrong number in this investigation came from a hand-rolled
resolver: 420, then 2,955, then "zero unresolvable". Every right one came from running
check_spec_anchors.py. It is the same failure three times, and the third time it was mine after I hadalready written up the first two.