You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
apps/loopover-ui/src/routes/roadmap.tsx is the public /roadmap marketing page. It hardcodes a ROADMAP_ITEMS array (lines 37-85) of 6 phase epics, each with a status of "shipping-soon"
("Now"), "planned" ("Next"), or "exploring" ("Later"), and each linking out to a specific GitHub
issue number (issue: 233 through 238, plus a top-level link to issue #127 as "the live roadmap
issue"). The page also shows a static LAST_UPDATED_LABEL ("June 1, 2026") to reassure visitors the
content is current.
As of this gardening pass (2026-07-24), all 7 referenced issues are closed:
So the live public page currently shows a 3-column "Now / Next / Later" board built entirely from
epics that are, in GitHub's own record, 100% done — while still presenting itself as an up-to-date
roadmap ("This reflects the live roadmap issue #127 and phase epics #233-#238", "Last updated June 1,
2026"). The page has silently drifted out of sync with reality with nothing to catch it.
Deciding what the roadmap should say now is a maintainer content call (what's actually next for
the product), not something this issue asks a contributor to do — that judgment call is explicitly out
of scope here. What is a safe, mechanical, contributor-buildable fix, with a clear precedent already
established repo-wide (docs:drift-check, manifest:drift-check, selfhost:env-reference:check/miner:env-reference:check, cf-typegen:check, ui:openapi:check, db:schema-drift:check, release-manifest:sync:check — this repo has an entire established pattern
of "generated/derived content must not silently drift from its source of truth, so a check fails
loudly when it does"): add a guard so this specific class of drift — every referenced issue closed
while the page still visually presents them as active/upcoming work — can never again silently persist
for weeks without anyone noticing.
Requirements
Add a script (following the existing scripts/*-check.ts/.mjs naming convention already used by
the drift-check family listed above) that reads ROADMAP_ITEMS from roadmap.tsx and, for each
entry, checks the referenced GitHub issue's state via the GitHub API (reuse whatever GitHub-API
client/auth pattern this repo's other maintenance scripts already use — grep scripts/ for an
existing octokit/gh api-style helper rather than inventing a new one).
The check must fail loudly (non-zero exit, clear message naming the stale issue number(s) and
their current status/stateReason) when a ROADMAP_ITEMS entry whose status is "shipping-soon" or "planned" (i.e. presented as still-active/upcoming) references an issue that
is CLOSED with stateReason: "COMPLETED" — that combination is definitionally stale content.
Do not flag "exploring" items the same way if the underlying issue is closed as NOT_PLANNED
(a legitimately-abandoned "later" idea reads differently from a genuinely-completed "now" item) —
only "presented as active, but GitHub says done" is the drift this check exists to catch. Judgment
calls beyond that (e.g. what to say instead) stay out of scope for this issue.
This is explicitly a local/manual or scheduled check, not a required PR-blocking CI job — it
needs live network access to the GitHub API, which test:ci's existing drift checks deliberately
avoid needing (they all diff two files already present in the repo). Wire it as an npm run roadmap:drift-check-style script only; do not add it to test:ci or any required GitHub Actions
status check.
Do not change ROADMAP_ITEMS's actual status/column content, LAST_UPDATED/LAST_UPDATED_LABEL,
or the page's visual layout in this PR — that content refresh needs the maintainer's real current
planning input and is out of scope here; this issue is the drift detector, not the content fix.
Deliverables
A new script (e.g. scripts/check-roadmap-issue-drift.ts) that fetches each ROADMAP_ITEMS
issue's live GitHub state and fails with a clear message when an actively-presented item's issue
is closed as completed.
A corresponding npm run roadmap:drift-check script entry in the root package.json.
A unit test for the script's own pure comparison logic (given a fixture of { status, issueState, issueStateReason } tuples, which combinations should fail vs. pass) that does not
itself require live network access — mock the GitHub API call the same way this repo's other
script tests do.
Test Coverage Requirements
This PR touches scripts/**, which — like apps/** — is outside this repo's Codecov coverage.include (vitest.config.ts / codecov.yml's ignore list covers both), so it owes no
Codecov patch-coverage percentage. Still add a real test/unit/-style test (following this repo's
existing pattern for testing other scripts/*-check.ts files' pure logic, e.g. how selfhost-env-reference-script.test.ts or setup-wizard-docs-parity.test.ts test their respective
scripts' comparison logic without hitting a live network) for the drift-detection logic itself. Run it
with npx vitest run <the new test file>, and npm run test:ci before opening the PR since this PR
touches scripts/**.
Expected Outcome
A maintainer running npm run roadmap:drift-check (locally or via a future scheduled task) gets a
clear, actionable failure the next time /roadmap visually presents a phase as active/upcoming work
whose underlying GitHub issue has actually shipped and closed — instead of the drift silently
persisting for weeks, as it has since the page's LAST_UPDATED of June 1, 2026.
Links & Resources
apps/loopover-ui/src/routes/roadmap.tsx (the page whose ROADMAP_ITEMS the script reads)
scripts/ — grep for the existing GitHub-API-client helper other maintenance scripts already use,
and for the *-check.ts naming/exit-code convention to follow
This repo's existing drift-check family for the general pattern to mirror: npm run docs:drift-check, npm run manifest:drift-check, npm run selfhost:env-reference:check, npm run db:schema-drift:check
Context
apps/loopover-ui/src/routes/roadmap.tsxis the public/roadmapmarketing page. It hardcodes aROADMAP_ITEMSarray (lines 37-85) of 6 phase epics, each with astatusof"shipping-soon"("Now"),
"planned"("Next"), or"exploring"("Later"), and each linking out to a specific GitHubissue number (
issue: 233through238, plus a top-level link to issue#127as "the live roadmapissue"). The page also shows a static
LAST_UPDATED_LABEL("June 1, 2026") to reassure visitors thecontent is current.
As of this gardening pass (2026-07-24), all 7 referenced issues are closed:
So the live public page currently shows a 3-column "Now / Next / Later" board built entirely from
epics that are, in GitHub's own record, 100% done — while still presenting itself as an up-to-date
roadmap ("This reflects the live roadmap issue #127 and phase epics #233-#238", "Last updated June 1,
2026"). The page has silently drifted out of sync with reality with nothing to catch it.
Deciding what the roadmap should say now is a maintainer content call (what's actually next for
the product), not something this issue asks a contributor to do — that judgment call is explicitly out
of scope here. What is a safe, mechanical, contributor-buildable fix, with a clear precedent already
established repo-wide (
docs:drift-check,manifest:drift-check,selfhost:env-reference:check/miner:env-reference:check,cf-typegen:check,ui:openapi:check,db:schema-drift:check,release-manifest:sync:check— this repo has an entire established patternof "generated/derived content must not silently drift from its source of truth, so a check fails
loudly when it does"): add a guard so this specific class of drift — every referenced issue closed
while the page still visually presents them as active/upcoming work — can never again silently persist
for weeks without anyone noticing.
Requirements
scripts/*-check.ts/.mjsnaming convention already used bythe drift-check family listed above) that reads
ROADMAP_ITEMSfromroadmap.tsxand, for eachentry, checks the referenced GitHub issue's state via the GitHub API (reuse whatever GitHub-API
client/auth pattern this repo's other maintenance scripts already use — grep
scripts/for anexisting
octokit/gh api-style helper rather than inventing a new one).their current
status/stateReason) when aROADMAP_ITEMSentry whosestatusis"shipping-soon"or"planned"(i.e. presented as still-active/upcoming) references an issue thatis
CLOSEDwithstateReason: "COMPLETED"— that combination is definitionally stale content."exploring"items the same way if the underlying issue is closed asNOT_PLANNED(a legitimately-abandoned "later" idea reads differently from a genuinely-completed "now" item) —
only "presented as active, but GitHub says done" is the drift this check exists to catch. Judgment
calls beyond that (e.g. what to say instead) stay out of scope for this issue.
needs live network access to the GitHub API, which
test:ci's existing drift checks deliberatelyavoid needing (they all diff two files already present in the repo). Wire it as an
npm run roadmap:drift-check-style script only; do not add it totest:cior any required GitHub Actionsstatus check.
ROADMAP_ITEMS's actualstatus/column content,LAST_UPDATED/LAST_UPDATED_LABEL,or the page's visual layout in this PR — that content refresh needs the maintainer's real current
planning input and is out of scope here; this issue is the drift detector, not the content fix.
Deliverables
scripts/check-roadmap-issue-drift.ts) that fetches eachROADMAP_ITEMSissue's live GitHub state and fails with a clear message when an actively-presented item's issue
is closed as completed.
npm run roadmap:drift-checkscript entry in the rootpackage.json.{ status, issueState, issueStateReason }tuples, which combinations should fail vs. pass) that does notitself require live network access — mock the GitHub API call the same way this repo's other
script tests do.
Test Coverage Requirements
This PR touches
scripts/**, which — likeapps/**— is outside this repo's Codecovcoverage.include(vitest.config.ts/codecov.yml'signorelist covers both), so it owes noCodecov patch-coverage percentage. Still add a real
test/unit/-style test (following this repo'sexisting pattern for testing other
scripts/*-check.tsfiles' pure logic, e.g. howselfhost-env-reference-script.test.tsorsetup-wizard-docs-parity.test.tstest their respectivescripts' comparison logic without hitting a live network) for the drift-detection logic itself. Run it
with
npx vitest run <the new test file>, andnpm run test:cibefore opening the PR since this PRtouches
scripts/**.Expected Outcome
A maintainer running
npm run roadmap:drift-check(locally or via a future scheduled task) gets aclear, actionable failure the next time
/roadmapvisually presents a phase as active/upcoming workwhose underlying GitHub issue has actually shipped and closed — instead of the drift silently
persisting for weeks, as it has since the page's
LAST_UPDATEDof June 1, 2026.Links & Resources
apps/loopover-ui/src/routes/roadmap.tsx(the page whoseROADMAP_ITEMSthe script reads)shown as active/upcoming on the live page
scripts/— grep for the existing GitHub-API-client helper other maintenance scripts already use,and for the
*-check.tsnaming/exit-code convention to follownpm run docs:drift-check,npm run manifest:drift-check,npm run selfhost:env-reference:check,npm run db:schema-drift:check