Refs #17791 · sibling of #17916 and neo-agent-brain#250
Context
c623b2f63c — "feat(engine): remove received Brain implementation (#17791) (#17806)", 2026-08-27 00:28:01 +0200 — deleted 804 unit spec files from this repository. test/playwright/unit/** went from 1098 spec files to 302 in that single commit. The overwhelming majority of that is correct: those specs covered ai/** sources that legitimately left for neomjs/neo-agent-brain.
The commit carried a retirement account, and it is the account that is wrong:
spec-retired: Brain-owned specs leave Engine with Agent OS; retained Fleet and
Neural Link coverage now binds an explicit external Brain runtime.
For 27 of the deleted specs, the implementation did not leave. It is still in neomjs/neo at buildScripts/** today, it is still invoked by workflows, husky hooks and package.json scripts, and it now has zero unit coverage anywhere in the repository.
Live latest-open sweep: checked the latest 20 open issues at 2026-08-31T08:00:02Z; no equivalent found. A2A claim sweep over the last 30 messages (all read-states) at the same time: no [lane-claim]/[lane-intent] on Engine spec-coverage restoration.
The Problem
This is the fourth load-bearing mechanism removed as #17791 collateral and discovered only by its silence, and the third traced to this exact commit:
#17920 — five days of a green pipeline over a frozen corpus
buildScripts unit coverage
c623b2f63c
here — 27 guards still running, none of them covered
Same commit, same shape: the removal set was censused for what moved, never for what stayed.
Why the guard that exists did not stop it
buildScripts/util/check-spec-retirement.mjs exists precisely for this failure. It was added by efba884dcb (2026-08-15, #17151 via #17161) — twelve days before the deletion — its SPEC_PATH_PATTERN is ^test\/playwright\/unit\/.+\.spec\.mjs, which covers every one of the 804 deleted paths, and .github/workflows/spec-retirement-lint.ymlruns it ondevPRs touchingtest/playwright/unit/**`.
It did not fail, and it was not bypassed. It passed correctly, by its own documented contract:
This guard asks for an ACCOUNT, never a veto. […] The guard checks that an account exists, never that it is true — a guard that graded the prose would be a rule nobody could satisfy mechanically.
That reasoning is sound and this ticket does not challenge it. But it means the guard's protection is exactly as strong as the account's honesty, and here a single sentence accounted for 804 deletions of which at least 27 it mis-describes. A per-commit prose account does not scale to a bulk repo split, which is the one event where deletions arrive in the hundreds.
Two independent reasons it also could not have blocked the merge even had it gone red, both recorded in the workflow's own header: the job is "a loud, non-blocking signal" — the live dev ruleset (19087298) requires exactly one status context, integration-parity — and #17171 owns that gap for the whole 19-workflow *-lint.yml family.
What is uncovered right now
All 27 measured at dev@9d2d23d12f; the last five rows were added 2026-08-31 by the correction below and measured at dev@1a0dd8f108. Line counts are the deleted spec's own length at c623b2f63c^; "callers" is an exact search across .github/workflows/, .husky/ and package.json.
7,962 lines of deleted spec, against implementations that all still run here.
check-branch-discipline.spec.mjs is the sharpest row: the guard it covers is executed by .husky/pre-pushand named in spec-retirement-lint.yml — the very workflow whose guard let this deletion through. check-spec-retirement's own spec survived only because it lives at test/playwright/unit/buildScripts/checkSpecRetirement.spec.mjs, outside the ai/ subtree that was swept.
The consequence is the one the guard's header names: "a suite that stops existing takes its own assertions with it, so the run goes green with less coverage behind the same number." Every green unit run since 2026-08-27 has certified 302 spec files while reading as the same signal that used to certify 1098.
Census correction — the surviving-subject set is 27, not 22
This ticket's original census selected by exact implementation-path survival and mis-counted its own population by five. The child (#17924 / PR #17925) surfaced five more surviving subjects during restoration: two index specs it could restore verbatim, and three whose subject survives but whose assertions encode post-split topology. Raised by @neo-gpt-emmy on PR #17925; reproduced independently before folding. Derivation: issuecomment-5476427652.
27 = 21 restored (PR #17925) + 6 retained here. The six residuals are this ticket's remaining operative scope:
deferred spec
cause
disposition
DataSyncPipeline.spec.mjs
reds on the missing syncGithubWorkflow.mjs --emit-only emission stage — the #17920 defect, witnessed
belongs to #17920, where the fix makes it green
util/check-theme-surfaces.spec.mjs
fixtures drive --fm-* tokens; collectShellSeamFailures and the Fleet Manager surface left in 07704934c3 (#17805)
rewrite against current topology, not a restoration
docs/RebuildContentIndexesAndSeo.spec.mjs
asserts against ai/services/github-workflow/SyncService.mjs, which departed
decide rewrite vs retire
release/PublishReleaseNoteOrphan.spec.mjs
subject buildScripts/release/publish.mjs survives; one assertion expects ai/scripts/lifecycle/postReleaseSync.mjs, which departed
decide rewrite vs retire
util/WorkflowConcurrency.spec.mjs
asserts ai/services/memory-core/MemoryService.mjs trips the parity lane; that path is no longer here
decide rewrite vs retire
util/WorkflowScopeClassifier.spec.mjs
expects run_integration / run_components admissions the classifier no longer makes post-split
assertions encode pre-split behaviour
✅ Correction, 2026-09-01 — two of the six residuals were already delivered
Measured at dev@40edf8abfa while picking up the next chunk. Two rows in the table above read as owed and are not:
AC-4 (the check-spec-retirement narrowing) is DONE.f189cc6ffa — "test(build): a deleted spec must account for a subject that stayed (#17964)" — shipped deriveSubjectSuffix, findSurvivingSubjects and unaccountedSurvivors; #17964 is CLOSED. The AC-4 checkbox below is stale, not outstanding.
DataSyncPipeline.spec.mjs is RESTORED, by f809d86e29 (#17920 / #17927). It lives at test/playwright/unit/buildScripts/dataSyncPipeline.spec.mjs. The table defers it to #17920, and #17920 delivered it.
The owed residual set is 5, not 6:check-theme-surfaces, RebuildContentIndexesAndSeo, PublishReleaseNoteOrphan, WorkflowConcurrency, WorkflowScopeClassifier.
WorkflowScopeClassifier is now owned by #18052. The rows are corrected here rather than deleted, because this ticket's whole argument is that a stale account is what let 804 deletions pass — leaving two closed rows reading as owed would be the same failure at this ticket's own scale, and it already mis-counted its population once (see below).
✅ Correction, 2026-09-03 — the owed residual set is 4, and one of those is in flight
Full re-census of all 27 rows at dev@3b19d7dca7, by git ls-tree + git log --diff-filter=A per path — existence and the commit that added it, so a pre-existing sibling at the same name could not read as a restoration.
util/WorkflowScopeClassifier.spec.mjs is RESTORED.8c86f4478f — "test(build): restore the workflow scope classifier's unit coverage (#17922) (#18053)", 2026-09-02, 399 lines. The row above defers it to #18052, and #18052/#18053 delivered it.
23 of 27 are present at dev, every one of them added afterc623b2f63c by a named restoration commit — 21 by 361f6fe36b (#17924/#17925, the two index specs among them), 1 by f809d86e29 (#17920/#17927), 1 by 8c86f4478f (#18053).
The owed set is 4:check-theme-surfaces(in flight — PR #18163, CI-green, awaiting review), RebuildContentIndexesAndSeo, PublishReleaseNoteOrphan, WorkflowConcurrency. All four subjects verified still present at dev: check-theme-surfaces.mjs (217), rebuildContentIndexesAndSeo.mjs (111), release/publish.mjs (281), and test.yml's inline jobs.changes script.
WorkflowConcurrency is the sharpest of the three that remain unclaimed — its subject runs on every PR, which no other owed row does.
Scope note: this measures that a spec exists and was added by a restoration commit. It does not grade coverage equivalence, and restored length diverges from deleted length in both directions — dataSyncPipeline 364 vs 915, check-chore-sync 297 vs 224, WorkflowScopeClassifier 399 vs 237. Line count is not coverage; AC-2's mutation bar is what grades these, and this census does not stand in for it.
✅ Correction, 2026-09-03 (later) — the owed set is 3, and one of those is now a filed leaf
Re-measured at dev@f6c7a0c360. The row above reads check-theme-surfaces as "in flight — PR #18163, CI-green, awaiting review". That PR merged at 09:29Z today.check-theme-surfaces.spec.mjs is present at test/playwright/unit/buildScripts/util/, added by dcf8597fdd (#18162 / #18163) — verified by git log --diff-filter=A on the path, so a pre-existing sibling at the same name could not read as a restoration.
24 of 27 are present at dev. The owed set is RebuildContentIndexesAndSeo, PublishReleaseNoteOrphan, WorkflowConcurrency — and PublishReleaseNoteOrphan now has its own leaf, #18209, mirroring #17924 and #18052, because this parent cannot be the close target of a PR that delivers one of three rows.
WorkflowConcurrency remains the sharpest unclaimed row: 675 lines, 17 clean arms plus the 2 the parity lane's departure retires, and its subject runs on every PR.
The same discipline as the correction above applies to why this is stated rather than edited away: leaving a delivered row reading as owed is how a stale account invites two seats to do one piece of work — one order smaller than the 804-deletion account this ticket is about.
Four share one shape: the subject survives, but the assertions encode an ai/** artifact that correctly departed. Restoring them verbatim would be a rewrite dressed as a restoration — which Fix step 1 above forbids.
The three of the 30 with a genuinely departed subject are util/check-aiconfig-antipatterns, util/check-aiconfig-test-mutation and util/check-atomic-write-shape; all three implementations are absent at HEAD, verified by file probe. 30 − 3 = 27.
The symmetry is stated rather than quietly corrected, because this ticket is about exactly this failure: its argument is that one sentence mis-described 804 deletions, and its own census then mis-described its population by five. Same failure mode, one order smaller. That is the argument for the ticket, not against it.
The Architectural Reality
test/playwright/unit/ai/ held 783 specs at c623b2f63c^ and holds 1 at HEAD. The ai/-prefixed subtree was swept as a unit, on path, and the sweep was right for 782 of them.
git diff --diff-filter=R c623b2f63c^ c623b2f63c -- test/playwright/unit/ is empty: no spec was relocated out of ai/ into the surviving tree. These are deletions, not moves — which is why nothing turned red.
The 27 subjects are Engine-owned by ADR 0040 §2.3 ("the Engine never imports from the extracted repository"). Note the ADR is not in this repository — it lives at neo-agent-brain:learn/agentos/decisions/0040-agentos-extraction-topology.md; grepping learn/agentos/decisions/ here finds nothing and that absence is not evidence.
Placement precedent for the restored specs is the surviving sibling tree test/playwright/unit/buildScripts/ (17 specs at HEAD, e.g. checkSpecRetirement.spec.mjs, checkPackageContents.spec.mjs). The restored files belong there, not at their old unit/ai/buildScripts/ paths — the ai/ prefix is what marked them as Brain substrate in the first place.
neomjs/neo CI runs unit and components only, so the unit project is the surface that must regain these.
The Fix
Restore the 27 specs from c623b2f63c^ into test/playwright/unit/buildScripts/**, mirroring the surviving sibling tree's layout rather than the deleted ai/ one. Import paths shorten by one segment. 21 of the 27 recover verbatim and are delivered by #17924 / PR #17925 — 28 depth-encoding specifiers re-expressed, 26 whitespace-only lines, 0 content changes. The remaining six do not, and are tabled under Census correction with a named cause each rather than trimmed into silence.
Reconcile each restored spec against its implementation at HEAD. Four days of dev separate them; any spec that no longer matches its subject is evidence of drift and is repaired, never deleted to make the suite green.
Re-account the deletion. The spec-retired: prose on c623b2f63c is immutable history, so the correction lands as the restoring commit's own account naming what the original mis-described.
Close the class, not just the instance. A prose account cannot be graded, but "the subject of this deleted spec still exists in this repository" is mechanical. Extend check-spec-retirement.mjs so a deletion whose subject is still resolvable in-tree requires the account to say so explicitly — turning the 27-row case from unobservable into a named exception.
carries the 27 restored specs against Engine-resident buildScripts/**
none — an Engine-run guard without a spec is the defect
spec headers
unit project spec-file count rises by 27 (+21 in PR #17925, +6 with the residuals); each restored spec red against a seeded mutation of its subject
check-spec-retirement.mjs deletion contract
#17151; this ticket
a deleted spec whose subject still resolves in-tree needs an explicit account of that fact
account remains free prose for subjects that genuinely left
script JSDoc
negative control: replay c623b2f63c's 30 ai/buildScripts deletions with its exact account; the guard must red
spec-retired: account truth
#17151
unchanged for the 782 correct deletions — this narrows, never widens, what the marker must assert
n/a
script JSDoc
positive control: a genuine Brain-mover deletion with the same account still greens
Decision Record impact
aligned-with ADR 0040 — restoring Engine-owned coverage to the Engine is what §2.3 already prescribes; the ADR is not amended. Verified at neo-agent-brain:learn/agentos/decisions/0040-agentos-extraction-topology.md:80-86.
Acceptance Criteria
RESTATED 2026-09-04 — the close condition is 26 + 1, not 27. 26 specs exist under test/playwright/unit/buildScripts/** and pass against their HEAD implementations; the 27th (WorkflowConcurrency.spec.mjs) is dispositioned to neo-agent-skills#41, not restored here — re-implementing a CI/governance guard in the engine because its old spec lived here is the placement error that cost #18228 a Drop+Supersede. 21 are delivered by #17924 / PR #17925.
⚠️ The disposition covers one third of what that spec guarded, and closing this ticket must not be read as covering the rest.neo-agent-skills#41 scopes three mechanisms — rerun isolation (concurrency), the head gate, and the mergeability controller — and all three of its ACs are open as of 2026-09-04. Only the concurrency third has a script (scripts/check-workflow-concurrency.mjs, skills PR #42); the reusable baseline still offers none of them. So this row is relocated and still owed there, not discharged.
Each restored spec is shown red against a seeded mutation of its own subject — a restored spec that cannot fail is not restored coverage.
Any spec that could not be restored verbatim names the drift it found in its subject, and the drift is repaired or filed — no spec is trimmed to make the suite green.
check-spec-retirement.mjs reds when replayed over c623b2f63c's 30 ai/buildScripts deletions carrying that commit's exact account, and stays green for a deletion whose subject genuinely left. Shown failing against the current implementation first.
RESTATED 2026-09-04 — target moves 27 → 26. The unit project's collected spec-file count is asserted to have risen by 26 across this ticket and its child, measured by count and not by a green run — +21 in PR #17925, +5 when the residuals land. The instrument (collected spec-file count, never run colour) is unaffected by the supersede; only the target number moves, because the 27th row leaves this repository rather than landing in it.
The restoring commit's own spec-retired:-adjacent account names what c623b2f63c mis-described.
Out of Scope
The other 774 deletions. This ticket censused test/playwright/unit/ai/buildScripts/** only — 30 specs, 27 with surviving subjects. The remaining 774 deleted specs are not censused by that instrument and this ticket makes no claim about them; most covered ai/** sources that genuinely left. A general "does this deleted spec's subject still exist in the Engine?" sweep is worth doing and is not this.
Making spec-retirement-lint.yml blocking.#17171 owns required-context binding for all 19 *-lint.yml workflows; adding this one alone would leave eighteen false headers standing beside one true one.
Guards with no caller — #17783 (R2/R3) owns enforcement/callers and explicitly excludes guard logic. This ticket is about coverage of guards that do run.
Changing what any of the 27 implementations does. Restoration is not the moment to fix the subject.
Brain-side spec selection — neo-agent-brain#201 owns unselected/failing specs in that repo; different repository, different population.
Avoided Traps
Restoring to the old ai/ paths. The ai/ prefix is exactly what made the bulk sweep classify them as Brain substrate. Putting them back there re-arms the same deletion at the next boundary change.
Grading the account's prose.#17151 rejected this deliberately and was right — it is a rule nobody can satisfy mechanically. The mechanical half is subject resolvability, which is why AC-4 tests that and not truthfulness.
Reading this as a check-spec-retirement defect. The guard is the only reason the deletion left an auditable account at all, and it honoured its documented contract exactly. The failure is that a single prose sentence was allowed to account for 804 deletions.
Trimming a restored spec to make it pass. A four-day-old spec failing against its subject is a finding about the subject. Deleting the assertion reproduces this ticket in miniature.
Treating a green unit run as evidence. The entire finding is that green survived the loss of 804 specs. Any AC phrased against run colour re-creates the blind spot; the collected spec-file count is the honest instrument.
Related
#17791 / c623b2f63c — the split commit that deleted the specs; #17806 was its PR
#17916 — sibling casualty: the PR-body lint gate (91ae3604b4)
#17920 — sibling casualty from this same commit: GitHub corpus emission
neo-agent-brain#250 — sibling casualty from this same commit: the seat lifecycle hooks
#17151 / efba884dcb — the guard whose contract this narrows
#17171 — required-context binding for the *-lint.yml family
#17783 — guards with no caller (enforcement axis, not coverage)
#17913 — closed sibling: a lint gate with no spec in the repo that owns it
✅ Correction, 2026-09-03 (later still) — the owed set is 2, and both remaining rows now have a disposition
Re-measured at dev@5baddd0e1c by git ls-tree -r --name-only origin/dev test/playwright/unit/. The correction above reads PublishReleaseNoteOrphan as owed with a filed leaf; it is delivered. release/PublishReleaseNoteOrphan.spec.mjs is present, by #18209 / PR #18210, merged today.
25 of 27 are present at dev. The owed set is:
row
disposition
util/WorkflowConcurrency.spec.mjs
#18226 / PR #18228 — claimed and delivered, awaiting review
docs/RebuildContentIndexesAndSeo.spec.mjs
unclaimed and free. Its deleted assertions target ai/services/github-workflow/SyncService.mjs, which departed — a rewrite-vs-retire decision, not a restoration
After #18228 merges this is 26 of 27, and the single remaining row is the only one of the original 27 that was never a restoration question.
Stated rather than edited away, for the reason the two corrections above give: a delivered row reading as owed is how two seats do one piece of work, and this ticket's whole argument is that one stale account mis-described 804 deletions.
Scope note carried forward: this measures that a spec exists and was added by a named restoration commit. It does not grade coverage equivalence — AC-2's mutation bar is what grades these, and no census stands in for it.
Handoff Retrieval Hints
Retrieval Hint: "spec-retired account mis-describes Engine buildScripts specs as Brain-owned"
Retrieval Hint: Commit range c623b2f63c^..c623b2f63c — 804 unit spec deletions, 30 under test/playwright/unit/ai/buildScripts/
Reproduce the census: git diff --name-only --diff-filter=D c623b2f63c^ c623b2f63c -- test/playwright/unit/ai/buildScripts/, then for each, git ls-tree -r --name-only HEAD -- buildScripts/ | grep -i "/<basename>.mjs$".
✅ Correction, 2026-09-04 — the previous correction is stale on both of its two owed rows
Re-measured at dev@4425422926 by basename match over git ls-tree -r --name-only origin/dev test/playwright/unit/buildScripts/, plus git log --diff-filter=A per hit — existence and the commit that added it, so a pre-existing sibling could not read as a restoration. 25 of 27 present, 2 absent — the same counts as the correction above, but the two rows' dispositions have both changed, and neither is what that block says.
row
that block says
actually
util/WorkflowConcurrency.spec.mjs
"#18226 / PR #18228 — claimed and delivered, awaiting review"
Drop + Supersede, same day, 19:47Z.#18226 closed NOT_PLANNED, PR #18228 closed unmerged. Wrong repository: rerun isolation, the head gate and the mergeability controller are PR governance, and neo-agent-skills Epic #14 owns them. Successor neomjs/neo-agent-skills#41 (OPEN), which carries the salvage map. Source-coordinate falsifier: neo-agent-skills/.github/workflows/reusable-pr-baseline.yml carries no concurrency: block and no head-gate output, so every consuming repo re-implements them — Engine-local tests would cement the ownership #14 is unwinding.
docs/RebuildContentIndexesAndSeo.spec.mjs
"unclaimed and free"
Claimed and in flight — PR #18261 (agent/17922-restore-rebuild-spec), +158 lines at that exact path, CI-green, awaiting review.
So this ticket owes one row, not two, and that row is already written. When #18261 merges the Engine-side count is 26 of 27, and the 27th is the one row that was never an Engine restoration question — it left for the shared baseline by ruling, not by omission.
Two of the three corrections above were needed because a delivered row still read as owed. This one is the mirror: a row read as owed here that had been ruled out of this repository seven hours earlier, and a row read as free that a peer could have picked up beside the open PR already doing it. Both directions cost the same thing — two seats on one piece of work — which is why the row is corrected in place rather than deleted.
AC-1 and AC-5 are the ones to read against this, and both need restating rather than ticking: their "+27" / "six residuals" arithmetic predates the supersede. The honest close condition is 26 restored in this repository + 1 dispositioned to neo-agent-skills#41, not 27 restored here. AC-5's instrument (collected spec-file count, never run colour) is unaffected; only its target number moves.
Scope note, carried forward unchanged: this measures that a spec exists and was added by a named restoration commit. It does not grade coverage equivalence — AC-2's mutation bar grades these, and no census stands in for it.
tobiu cross-referenced by PR #17927 on Aug 31, 2026, 12:49 PM
tobiu referenced in commit 3a47e99 - "test(engine): restore the buildScripts unit coverage swept by the split (#17924) on Aug 31, 2026, 3:14 PM
tobiu referenced in commit 361f6fe - "test(engine): restore the buildScripts unit coverage swept by the split (#17924) (#17925) on Aug 31, 2026, 3:27 PM
tobiu referenced in commit 30de097 - "test(build): a deleted spec must account for a subject that stayed (#17964) on Aug 31, 2026, 7:51 PM
tobiu referenced in commit 64ce9dd - "test(build): a deleted spec must account for a subject that stayed (#17964) on Aug 31, 2026, 8:30 PM
tobiu referenced in commit f189cc6 - "test(build): a deleted spec must account for a subject that stayed (#17964) (#17965) on Aug 31, 2026, 8:53 PM
tobiu unassigned from @neo-opus-grace on Sep 1, 2026, 10:07 AM
tobiu referenced in commit 8c86f44 - "test(build): restore the workflow scope classifier's unit coverage (#17922) (#18053) on Sep 2, 2026, 9:34 AM
tobiu referenced in commit 9b34b72 - "test(build): the Workstation theme guard states its own contract (#18162) on Sep 3, 2026, 8:57 AM
Refs #17791 · sibling of #17916 and
neo-agent-brain#250Context
c623b2f63c— "feat(engine): remove received Brain implementation (#17791) (#17806)", 2026-08-27 00:28:01 +0200 — deleted 804 unit spec files from this repository.test/playwright/unit/**went from 1098 spec files to 302 in that single commit. The overwhelming majority of that is correct: those specs coveredai/**sources that legitimately left forneomjs/neo-agent-brain.The commit carried a retirement account, and it is the account that is wrong:
For 27 of the deleted specs, the implementation did not leave. It is still in
neomjs/neoatbuildScripts/**today, it is still invoked by workflows, husky hooks andpackage.jsonscripts, and it now has zero unit coverage anywhere in the repository.Live latest-open sweep: checked the latest 20 open issues at 2026-08-31T08:00:02Z; no equivalent found. A2A claim sweep over the last 30 messages (all read-states) at the same time: no
[lane-claim]/[lane-intent]on Engine spec-coverage restoration.The Problem
This is the fourth load-bearing mechanism removed as
#17791collateral and discovered only by its silence, and the third traced to this exact commit:agent-pr-body-lint.yml91ae3604b4devc623b2f63cneo-agent-brain#250— Stop gate exiting 1, non-blocking, silentc623b2f63cbuildScriptsunit coveragec623b2f63cSame commit, same shape: the removal set was censused for what moved, never for what stayed.
Why the guard that exists did not stop it
buildScripts/util/check-spec-retirement.mjsexists precisely for this failure. It was added byefba884dcb(2026-08-15, #17151 via #17161) — twelve days before the deletion — itsSPEC_PATH_PATTERNis^test\/playwright\/unit\/.+\.spec\.mjs, which covers every one of the 804 deleted paths, and.github/workflows/spec-retirement-lint.ymlruns it ondevPRs touchingtest/playwright/unit/**`.It did not fail, and it was not bypassed. It passed correctly, by its own documented contract:
That reasoning is sound and this ticket does not challenge it. But it means the guard's protection is exactly as strong as the account's honesty, and here a single sentence accounted for 804 deletions of which at least 27 it mis-describes. A per-commit prose account does not scale to a bulk repo split, which is the one event where deletions arrive in the hundreds.
Two independent reasons it also could not have blocked the merge even had it gone red, both recorded in the workflow's own header: the job is "a loud, non-blocking signal" — the live
devruleset (19087298) requires exactly one status context,integration-parity— and#17171owns that gap for the whole 19-workflow*-lint.ymlfamily.What is uncovered right now
All 27 measured at
dev@9d2d23d12f; the last five rows were added 2026-08-31 by the correction below and measured atdev@1a0dd8f108. Line counts are the deleted spec's own length atc623b2f63c^; "callers" is an exact search across.github/workflows/,.husky/andpackage.json.buildScripts/util/check-block-alignment.mjs…/util/check-block-alignment.spec.mjspackage.jsonbuildScripts/dataSyncPipeline.mjs…/DataSyncPipeline.spec.mjs.github/workflows/test.yml(jobs.changesscope script)…/util/WorkflowConcurrency.spec.mjstest.yml— runs on every PRbuildScripts/util/check-theme-surfaces.mjs…/util/check-theme-surfaces.spec.mjscheck-theme-surfaces.yml,package.jsonbuildScripts/util/check-fixed-sleeps.mjs…/util/check-fixed-sleeps.spec.mjsfixed-sleep-lint.yml,package.jsonbuildScripts/dataSyncWatchdog.mjs…/DataSyncWatchdog.spec.mjsbuildScripts/util/check-branch-discipline.mjs…/util/check-branch-discipline.spec.mjsspec-retirement-lint.yml,.husky/pre-pushbuildScripts/util/developmentThemeAssets.mjs…/util/developmentThemeAssets.spec.mjsbuildScripts/helpers/watchThemes.mjs…/helpers/watchThemes.spec.mjspackage.jsonbuildScripts/util/check-codeql-extraction.mjs…/util/check-codeql-extraction.spec.mjscodeql-analysis.ymlbuildScripts/docs/index/discussions.mjs,…/index/pulls.mjs…/docs/index/PortalContentIndexes.spec.mjsdocs/rebuildContentIndexesAndSeo.mjs.github/workflows/test.yml(jobs.changesscope script)…/util/WorkflowScopeClassifier.spec.mjstest.yml— runs on every PRbuildScripts/util/check-ticket-archaeology.mjs…/util/check-ticket-archaeology.spec.mjsticket-archaeology-lint.yml,package.jsonbuildScripts/util/check-chore-sync.mjs…/util/check-chore-sync.spec.mjs.husky/pre-commitbuildScripts/docs/index/tickets.mjs…/docs/index/TicketIndex.spec.mjsdocs/rebuildContentIndexesAndSeo.mjsbuildScripts/release/publish.mjs…/release/PublishReleaseNoteOrphan.spec.mjsbuildScripts/docs/rebuildContentIndexesAndSeo.mjs…/docs/RebuildContentIndexesAndSeo.spec.mjsbuildScripts/util/agent-push.mjs…/util/agent-push.spec.mjspackage.jsonbuildScripts/util/check-jsdoc-types.mjs…/util/check-jsdoc-types.spec.mjsjsdoc-type-lint.yml,package.jsonbuildScripts/util/check-whitespace.mjs…/util/check-whitespace.spec.mjspackage.jsonbuildScripts/util/check-examples-body-only.mjs…/util/check-examples-body-only.spec.mjscheck-examples-body-only.yml,package.jsonbuildScripts/util/mergedPullRequestPush.mjs…/util/mergedPullRequestPush.spec.mjsbuildScripts/build/themes.mjs…/build/themes.spec.mjstheme-coverage-lint.yml,package.jsonbuildScripts/util/branchFreshness.mjs…/util/branchFreshness.spec.mjsbuildScripts/docs/seo/generate.mjs…/docs/seo/Generate.spec.mjscontent-logical-identity-lint.ymlbuildScripts/util/check-parse.mjs…/util/check-parse.spec.mjspackage.jsonbuildScripts/util/stagedDiff.mjs…/util/stagedDiff.spec.mjs7,962 lines of deleted spec, against implementations that all still run here.
check-branch-discipline.spec.mjsis the sharpest row: the guard it covers is executed by.husky/pre-pushand named inspec-retirement-lint.yml— the very workflow whose guard let this deletion through.check-spec-retirement's own spec survived only because it lives attest/playwright/unit/buildScripts/checkSpecRetirement.spec.mjs, outside theai/subtree that was swept.The consequence is the one the guard's header names: "a suite that stops existing takes its own assertions with it, so the run goes green with less coverage behind the same number." Every green
unitrun since 2026-08-27 has certified 302 spec files while reading as the same signal that used to certify 1098.Census correction — the surviving-subject set is 27, not 22
This ticket's original census selected by exact implementation-path survival and mis-counted its own population by five. The child (#17924 / PR #17925) surfaced five more surviving subjects during restoration: two index specs it could restore verbatim, and three whose subject survives but whose assertions encode post-split topology. Raised by @neo-gpt-emmy on PR #17925; reproduced independently before folding. Derivation: issuecomment-5476427652.
27 = 21 restored (PR #17925) + 6 retained here. The six residuals are this ticket's remaining operative scope:
DataSyncPipeline.spec.mjssyncGithubWorkflow.mjs --emit-onlyemission stage — the #17920 defect, witnessedutil/check-theme-surfaces.spec.mjs--fm-*tokens;collectShellSeamFailuresand the Fleet Manager surface left in07704934c3(#17805)docs/RebuildContentIndexesAndSeo.spec.mjsai/services/github-workflow/SyncService.mjs, which departedrelease/PublishReleaseNoteOrphan.spec.mjsbuildScripts/release/publish.mjssurvives; one assertion expectsai/scripts/lifecycle/postReleaseSync.mjs, which departedutil/WorkflowConcurrency.spec.mjsai/services/memory-core/MemoryService.mjstrips the parity lane; that path is no longer hereutil/WorkflowScopeClassifier.spec.mjsrun_integration/run_componentsadmissions the classifier no longer makes post-splitFour share one shape: the subject survives, but the assertions encode an
ai/**artifact that correctly departed. Restoring them verbatim would be a rewrite dressed as a restoration — which Fix step 1 above forbids.The three of the 30 with a genuinely departed subject are
util/check-aiconfig-antipatterns,util/check-aiconfig-test-mutationandutil/check-atomic-write-shape; all three implementations are absent at HEAD, verified by file probe. 30 − 3 = 27.The symmetry is stated rather than quietly corrected, because this ticket is about exactly this failure: its argument is that one sentence mis-described 804 deletions, and its own census then mis-described its population by five. Same failure mode, one order smaller. That is the argument for the ticket, not against it.
The Architectural Reality
test/playwright/unit/ai/held 783 specs atc623b2f63c^and holds 1 at HEAD. Theai/-prefixed subtree was swept as a unit, on path, and the sweep was right for 782 of them.git diff --diff-filter=R c623b2f63c^ c623b2f63c -- test/playwright/unit/is empty: no spec was relocated out ofai/into the surviving tree. These are deletions, not moves — which is why nothing turned red.neo-agent-brain:learn/agentos/decisions/0040-agentos-extraction-topology.md; greppinglearn/agentos/decisions/here finds nothing and that absence is not evidence.test/playwright/unit/buildScripts/(17 specs at HEAD, e.g.checkSpecRetirement.spec.mjs,checkPackageContents.spec.mjs). The restored files belong there, not at their oldunit/ai/buildScripts/paths — theai/prefix is what marked them as Brain substrate in the first place.neomjs/neoCI runsunitandcomponentsonly, so theunitproject is the surface that must regain these.The Fix
c623b2f63c^intotest/playwright/unit/buildScripts/**, mirroring the surviving sibling tree's layout rather than the deletedai/one. Import paths shorten by one segment. 21 of the 27 recover verbatim and are delivered by #17924 / PR #17925 — 28 depth-encoding specifiers re-expressed, 26 whitespace-only lines, 0 content changes. The remaining six do not, and are tabled under Census correction with a named cause each rather than trimmed into silence.devseparate them; any spec that no longer matches its subject is evidence of drift and is repaired, never deleted to make the suite green.spec-retired:prose onc623b2f63cis immutable history, so the correction lands as the restoring commit's own account naming what the original mis-described.check-spec-retirement.mjsso a deletion whose subject is still resolvable in-tree requires the account to say so explicitly — turning the 27-row case from unobservable into a named exception.Contract Ledger Matrix
test/playwright/unit/buildScripts/**neo-agent-brain); sibling precedentcheckSpecRetirement.spec.mjsbuildScripts/**unitproject spec-file count rises by 27 (+21 in PR #17925, +6 with the residuals); each restored spec red against a seeded mutation of its subjectcheck-spec-retirement.mjsdeletion contract#17151; this ticketc623b2f63c's 30ai/buildScriptsdeletions with its exact account; the guard must redspec-retired:account truth#17151Decision Record impact
aligned-with ADR 0040— restoring Engine-owned coverage to the Engine is what §2.3 already prescribes; the ADR is not amended. Verified atneo-agent-brain:learn/agentos/decisions/0040-agentos-extraction-topology.md:80-86.Acceptance Criteria
test/playwright/unit/buildScripts/**and pass against their HEAD implementations; the 27th (WorkflowConcurrency.spec.mjs) is dispositioned toneo-agent-skills#41, not restored here — re-implementing a CI/governance guard in the engine because its old spec lived here is the placement error that cost #18228 a Drop+Supersede. 21 are delivered by #17924 / PR #17925.neo-agent-skills#41scopes three mechanisms — rerun isolation (concurrency), the head gate, and the mergeability controller — and all three of its ACs are open as of 2026-09-04. Only the concurrency third has a script (scripts/check-workflow-concurrency.mjs, skills PR #42); the reusable baseline still offers none of them. So this row is relocated and still owed there, not discharged.check-spec-retirement.mjsreds when replayed overc623b2f63c's 30ai/buildScriptsdeletions carrying that commit's exact account, and stays green for a deletion whose subject genuinely left. Shown failing against the current implementation first.unitproject's collected spec-file count is asserted to have risen by 26 across this ticket and its child, measured by count and not by a green run — +21 in PR #17925, +5 when the residuals land. The instrument (collected spec-file count, never run colour) is unaffected by the supersede; only the target number moves, because the 27th row leaves this repository rather than landing in it.spec-retired:-adjacent account names whatc623b2f63cmis-described.Out of Scope
test/playwright/unit/ai/buildScripts/**only — 30 specs, 27 with surviving subjects. The remaining 774 deleted specs are not censused by that instrument and this ticket makes no claim about them; most coveredai/**sources that genuinely left. A general "does this deleted spec's subject still exist in the Engine?" sweep is worth doing and is not this.spec-retirement-lint.ymlblocking.#17171owns required-context binding for all 19*-lint.ymlworkflows; adding this one alone would leave eighteen false headers standing beside one true one.#17783(R2/R3) owns enforcement/callers and explicitly excludes guard logic. This ticket is about coverage of guards that do run.neo-agent-brain#201owns unselected/failing specs in that repo; different repository, different population.Avoided Traps
ai/paths. Theai/prefix is exactly what made the bulk sweep classify them as Brain substrate. Putting them back there re-arms the same deletion at the next boundary change.#17151rejected this deliberately and was right — it is a rule nobody can satisfy mechanically. The mechanical half is subject resolvability, which is why AC-4 tests that and not truthfulness.check-spec-retirementdefect. The guard is the only reason the deletion left an auditable account at all, and it honoured its documented contract exactly. The failure is that a single prose sentence was allowed to account for 804 deletions.unitrun as evidence. The entire finding is that green survived the loss of 804 specs. Any AC phrased against run colour re-creates the blind spot; the collected spec-file count is the honest instrument.Related
c623b2f63c— the split commit that deleted the specs;#17806was its PR91ae3604b4)neo-agent-brain#250— sibling casualty from this same commit: the seat lifecycle hooksefba884dcb— the guard whose contract this narrows*-lint.ymlfamilyHandoff Retrieval Hints
Retrieval Hint: "spec-retired account mis-describes Engine buildScripts specs as Brain-owned"Retrieval Hint: Commit range c623b2f63c^..c623b2f63c — 804 unit spec deletions, 30 under test/playwright/unit/ai/buildScripts/git diff --name-only --diff-filter=D c623b2f63c^ c623b2f63c -- test/playwright/unit/ai/buildScripts/, then for each,git ls-tree -r --name-only HEAD -- buildScripts/ | grep -i "/<basename>.mjs$".