Context
Operator, 2026-08-20, after testing the app from dev: "tested the devindex app after pulling from dev => works fine. first real friction item with the new repo => it will stay broken there, until the next neo release. on the bright side: we can now remove the app, its learn items, scss, and tests from the neo repo (vba if all tests (not just unit) are there)."
This is the terminal step of neomjs/neo#17238. neomjs/devindex owns the app, its Data Factory and its own tickets and PRs; what remains here is a copy that is behind the destination (config.publishedWorkingSet exists only there — see neomjs/neo#17238's revision comment).
The requested V-B-A came back negative. Recorded here as the ticket's own precondition rather than discovered mid-removal.
Live latest-open sweep: latest 20 open issues at 2026-08-20T14:45Z, no equivalent. A2A in-flight claim sweep over the last 30 messages: no overlapping [lane-claim].
The Problem — the tests are NOT all there
| suite |
in neo |
in neomjs/devindex |
gap |
unit (unit/app/devindex/) |
9 |
9 |
not the same 9 |
| e2e |
5 |
0 |
no e2e harness exists there at all |
Unit — one spec exists only here. StoragePublishedIndex.spec.mjs (8 tests) covers neomjs/neo#17374's published-artifact read path: fetched-vs-checkout record parity, the single declared config URL, fallback-with-disclosure on failure, non-2xx handling, an unparseable body on the bootstrap run, digest mismatch, absence-of-provenance, and curated files untouched.
neomjs/devindex has a spec neo does not — StorageWriteDirectory.spec.mjs — but it is a different subject (atomic write, parent-dir creation, temp-file cleanup, the empty-index door). The two do not overlap. Deleting neo's copy drops the read-path coverage entirely, and that path is exactly the mechanism neomjs/neo#17394 is about.
E2E — none of the five have a home. neomjs/devindex has one playwright config (playwright.config.unit.mjs) and one script (test-unit). There is no e2e config, no e2e directory, no test-e2e.
All five drive /apps/devindex/ exclusively — not one has an alternative target:
| spec |
devindex-specific dependency |
grid/ThumbDragDevIndex.spec.mjs |
the app itself; named for it |
grid/ThumbDrag.spec.mjs |
devindex-stop-stream-button |
grid/ThumbDragPause.spec.mjs |
50,000 rows |
benchmarks/GridScrollBenchmark.spec.mjs |
devindex-stop-stream-button |
benchmarks/GridProfile.spec.mjs |
devindex-stop-stream-button |
So this is not a goto rewrite. Three of the five click a control that only that app has, and examples/grid/bigData (20,000 rows / 50 columns) is not row-comparable with DevIndex's 50,000.
The Architectural Reality
Removal surface, measured on origin/dev:
| area |
count |
note |
apps/devindex/** |
49 files, 27 MB |
incl. the 23 MB still-tracked users.jsonl |
resources/scss/**/devindex/** |
14 |
8 src + 3 dark + 3 light |
learn/guides/devindex/** |
27 |
plus 30 learn/tree.json entries |
| tests |
14 |
9 unit + 5 e2e |
apps/portal registration |
6 |
4 examples_*.json + sitemap.xml + llms.txt |
buildScripts + ai/scripts |
6 |
webpack appworker dev/prod, esmodules, dataSyncPipeline, check-package-contents, retry-bound-registry |
package.json |
6 scripts |
`devindex:add |
resources/content/** carries 0 devindex entries, so the generated mirror needs no prune.
The Fix
Remove in one PR, with the four decisions below resolved rather than discovered.
D1 — port StoragePublishedIndex.spec.mjs to neomjs/devindex first. The code it covers lives only there. Order matters: port and prove green in the destination before deleting here, so the coverage is never absent from both.
D2 — ThumbDragDevIndex.spec.mjs follows the app. It is devindex-specific by construction. That requires standing up an e2e harness in neomjs/devindex (config + script + fixture), which is the larger half of this ticket and may deserve its own leaf.
D3 — the three stream-dependent specs retarget to a neo-owned fixture. bigData loads synchronously and has no stream, so the devindex-stop-stream-button step is not replaced — it is unnecessary there and drops out. The benchmark series re-baselines at the cut (50k→20k rows, 37→50 columns): the numbers before and after are not comparable and must not be read as a regression. That discontinuity is the real cost of the removal and is recorded here deliberately rather than left to be discovered as a mystery drop in a future comparison.
D4 — the public URL is an operator call. apps/devindex is a registered portal example with its own sitemap.xml entry at https://neomjs.com/apps/devindex/index.html and an llms.txt listing. Deregistering removes a live public URL; a redirect to the app's new home is the obvious disposition, but changing a published URL is not mine to decide unilaterally.
Acceptance Criteria
Out of Scope
- Reclaiming the 23 MB from history — that is neomjs/neo#17376 and needs the one-shot rewrite; this ticket only stops the working tree carrying it
neomjs/devindex#1 (column resize) — that app stays broken until a neo.mjs release, which the operator has explicitly accepted as the trade for removing now
- Standing up the devindex e2e harness, if D2 is split into its own leaf
Avoided Traps
Do not delete the tests and "port them later." The unit gap above is exactly how that ends: StoragePublishedIndex would be the only record of neomjs/neo#17374's read-path contract, and it would be deleted from the one repo that has it while the code it covers lives in the other.
Do not silently retarget the benchmarks. A benchmark whose fixture changed is a new series. Renaming the target without recording the discontinuity produces a future "performance regression" that is really a fixture change.
Related
- neomjs/neo#17238 — the epic this closes out
- neomjs/neo#17376 — history reclaim (the other half of the size problem)
- neomjs/neo#17394 — the read-path defect
StoragePublishedIndex covers
neomjs/devindex#1 — why the destination app is currently broken
Origin Session ID: 3e4f33e0-fb23-4a61-a2a0-7f396950f3d6
Handoff Retrieval Hints: query_raw_memories("remove apps/devindex from neo test parity e2e harness"). Anchors: StoragePublishedIndex.spec.mjs, devindex-stop-stream-button, learn/tree.json.
Context
Operator, 2026-08-20, after testing the app from
dev: "tested the devindex app after pulling from dev => works fine. first real friction item with the new repo => it will stay broken there, until the next neo release. on the bright side: we can now remove the app, its learn items, scss, and tests from the neo repo (vba if all tests (not just unit) are there)."This is the terminal step of neomjs/neo#17238.
neomjs/devindexowns the app, its Data Factory and its own tickets and PRs; what remains here is a copy that is behind the destination (config.publishedWorkingSetexists only there — see neomjs/neo#17238's revision comment).The requested V-B-A came back negative. Recorded here as the ticket's own precondition rather than discovered mid-removal.
Live latest-open sweep: latest 20 open issues at 2026-08-20T14:45Z, no equivalent. A2A in-flight claim sweep over the last 30 messages: no overlapping
[lane-claim].The Problem — the tests are NOT all there
neomjs/devindexunit/app/devindex/)Unit — one spec exists only here.
StoragePublishedIndex.spec.mjs(8 tests) covers neomjs/neo#17374's published-artifact read path: fetched-vs-checkout record parity, the single declared config URL, fallback-with-disclosure on failure, non-2xx handling, an unparseable body on the bootstrap run, digest mismatch, absence-of-provenance, and curated files untouched.neomjs/devindexhas a spec neo does not —StorageWriteDirectory.spec.mjs— but it is a different subject (atomic write, parent-dir creation, temp-file cleanup, the empty-index door). The two do not overlap. Deleting neo's copy drops the read-path coverage entirely, and that path is exactly the mechanism neomjs/neo#17394 is about.E2E — none of the five have a home.
neomjs/devindexhas one playwright config (playwright.config.unit.mjs) and one script (test-unit). There is no e2e config, no e2e directory, notest-e2e.All five drive
/apps/devindex/exclusively — not one has an alternative target:grid/ThumbDragDevIndex.spec.mjsgrid/ThumbDrag.spec.mjsdevindex-stop-stream-buttongrid/ThumbDragPause.spec.mjsbenchmarks/GridScrollBenchmark.spec.mjsdevindex-stop-stream-buttonbenchmarks/GridProfile.spec.mjsdevindex-stop-stream-buttonSo this is not a
gotorewrite. Three of the five click a control that only that app has, andexamples/grid/bigData(20,000 rows / 50 columns) is not row-comparable with DevIndex's 50,000.The Architectural Reality
Removal surface, measured on
origin/dev:apps/devindex/**users.jsonlresources/scss/**/devindex/**src+ 3 dark + 3 lightlearn/guides/devindex/**learn/tree.jsonentriesapps/portalregistrationexamples_*.json+sitemap.xml+llms.txtbuildScripts+ai/scriptspackage.jsonresources/content/**carries 0 devindex entries, so the generated mirror needs no prune.The Fix
Remove in one PR, with the four decisions below resolved rather than discovered.
D1 — port
StoragePublishedIndex.spec.mjstoneomjs/devindexfirst. The code it covers lives only there. Order matters: port and prove green in the destination before deleting here, so the coverage is never absent from both.D2 —
ThumbDragDevIndex.spec.mjsfollows the app. It is devindex-specific by construction. That requires standing up an e2e harness inneomjs/devindex(config + script + fixture), which is the larger half of this ticket and may deserve its own leaf.D3 — the three stream-dependent specs retarget to a neo-owned fixture.
bigDataloads synchronously and has no stream, so thedevindex-stop-stream-buttonstep is not replaced — it is unnecessary there and drops out. The benchmark series re-baselines at the cut (50k→20k rows, 37→50 columns): the numbers before and after are not comparable and must not be read as a regression. That discontinuity is the real cost of the removal and is recorded here deliberately rather than left to be discovered as a mystery drop in a future comparison.D4 — the public URL is an operator call.
apps/devindexis a registered portal example with its ownsitemap.xmlentry athttps://neomjs.com/apps/devindex/index.htmland anllms.txtlisting. Deregistering removes a live public URL; a redirect to the app's new home is the obvious disposition, but changing a published URL is not mine to decide unilaterally.Acceptance Criteria
StoragePublishedIndex.spec.mjsruns green inneomjs/devindexbefore its removal here (D1)apps/devindex/**, its 14 SCSS files, its 27 learn guides and the 30learn/tree.jsonentries are gone, andnpm run build-themesplus the learn-tree lint both passdevindex-*selector remaining anywhere intest/**apps/devindexreference survives outside deliberately-retained history —git grep -l 'apps/devindex'returns only files this ticket consciously keepsdevindex:*npm scripts are gone andnpm runstill resolvesOut of Scope
neomjs/devindex#1(column resize) — that app stays broken until aneo.mjsrelease, which the operator has explicitly accepted as the trade for removing nowAvoided Traps
Do not delete the tests and "port them later." The unit gap above is exactly how that ends:
StoragePublishedIndexwould be the only record of neomjs/neo#17374's read-path contract, and it would be deleted from the one repo that has it while the code it covers lives in the other.Do not silently retarget the benchmarks. A benchmark whose fixture changed is a new series. Renaming the target without recording the discontinuity produces a future "performance regression" that is really a fixture change.
Related
StoragePublishedIndexcoversneomjs/devindex#1— why the destination app is currently brokenOrigin Session ID: 3e4f33e0-fb23-4a61-a2a0-7f396950f3d6
Handoff Retrieval Hints:
query_raw_memories("remove apps/devindex from neo test parity e2e harness"). Anchors:StoragePublishedIndex.spec.mjs,devindex-stop-stream-button,learn/tree.json.