Skip to content

feat(079): "N releases / M weeks behind" upgrade delta (#1081), and finish the ux-audit sweep - #1085

Merged
Dumbris merged 4 commits into
mainfrom
claude/issue-1081-roadmap-df1ca5
Aug 29, 2026
Merged

Dumbris merged 4 commits into
mainfrom
claude/issue-1081-roadmap-df1ca5

Conversation

@Dumbris

@Dumbris Dumbris commented Aug 29, 2026

Copy link
Copy Markdown
Member

Pull Request

Description

Closes the last outstanding slice of Spec 079, and finishes the ux-audit epic's regression net.

1. Spec 079 FR-002 — the "N releases / M weeks behind" delta (#1081)

FR-002 requires the current version, the latest version and a human-readable delta on mcpproxy status, doctor, the startup log, the Web UI and both trays. Only latest-version-only ever shipped; the deferral survived as TODO(spec-079/FR-002) comments, which is how an outside contributor found it.

The blocker was data, not rendering: the checker fetched only /releases/latest, so it had the offered release's publish date but not the running one's, and no tag sequence to count.

  • internal/updatecheck/delta.go — new, pure (no network, no clock, no locks), so every spec rule is a table row.
  • Fetching is best-effort enrichment of the existing check, never a second pipeline (FR-001): one ETag-conditional page of /releases, plus a by-tag lookup only when the running build predates that page.
  • Both requests share one context deadline. A per-request timeout bounds each hop and nothing bounds the total — and CheckNow runs synchronously inside GET /api/v1/info?refresh=true, so an unbounded delta would stall a request a user is waiting on.
  • Counting is by semver, never list position: GitHub orders /releases by created_at, and the live data has v0.53.0-rc.9 sitting ahead of the later-published rc.10.

Three degradation rules matter more than the feature, each with a regression test. A delta miss must not set CheckError (statusVersionSuffix returns "" whenever it is non-empty, so that would delete the nudge instead of enriching it), must not touch the FR-018 backoff counters, and must leave every surface rendering exactly what it rendered before.

The clause is rendered once in Go (FormatBehindSummary) and printed verbatim everywhere, with raw numbers alongside for machine consumers. GuidanceLine is already hand-ported into UpdateBanner.vue with a "keep the two in sync" comment; FR-002 asks for consistent framing across five surfaces, so authoring it once is the cheap way to get that.

Fields are additive per FR-021 and had to be threaded through six hand-maintained mirrors — VersionInfo, the InfoResponseUpdate DTO and its field-by-field copier, internal/contracts (→ make swagger), the contracts.ts generator, status_cmd's map decoding, and the Swift tray's Codable, which turned out never to have decoded the US2 fields either.

Two adjacent bugs fixed because the delta sits on the same code:

  • GetLatestReleaseIncludingPrereleases returned releases[0] from a created_at-ordered list, so an RC user could be offered a release older than the one they run. Now max-by-semver.
  • GetReleaseByTag interpolated an unvalidated tag into the request path, deferring validation to callers by comment only. The delta feeds it the ldflags-stamped version, so it now validates and escapes.

Both trays put the delta in the update item's tooltip, not its title: Spec 092 FR-010 fixes the title's exact shape, and a menu row reading Update v0.62.0 — ready to restart? — 8 releases / ~14 weeks behind stops being scannable.

2. ux-audit — finish the sweep's regression net, and fix what it caught

The August Web UI audit closes by asking for four assertions in e2e/web-ui-sweep. Three were already there (F9 contrast, F30 names/aria-live, F14 responsive); this adds the two that were not.

  • F6 — modal focus/Tab-trap/Escape/focus-restore. Escape is dispatched in-page, never page.keyboard.press: re-checking F6 during the audit produced a false negative for exactly that reason, because a synthetic key never reaches the document listener under test.
  • F1 — Activity and Usage vs the API. The invariant is not naive equality: Usage folds blocked into its error tile while Activity splits them, and /activity/usage is served from a short read cache, so the assertion polls for convergence.

Running the completed net turned up three defects already on main, none regressions of the audit's 36:

  1. The landing page failed AA in both themes (3.09–4.23:1) and two of its controls had no accessible name. Usage.vue uses raw opacity-*; fix(webui): AA contrast, system theme, mobile layout and a11y gaps #1054 fixed that failure mode for the text-base-content ramp and .stat-* but never covered raw opacity, and nothing caught it because the audit walked / before feat(webui): make the analytics dashboard the default landing page #1044 made Usage the landing page.
  2. The Activity status pill clips at 390px for any status outside the known four — tool_auto_approved measured 145px in a 93px table-fixed cell. The pill now truncates against the cell rather than the column being sized to today's longest label.

The phone check that caught #2 had been passing vacuously: it measures rows.first(), and a success row (~90% of traffic) renders an sr-only zero-width label. It only became a real assertion once the new F1 check put an error row first.

3. Roadmap truth-sync

upgrade-nudge was done with FR-002 unbuilt; ux-audit was todo with both sweeps and every finding actually shipped in August. Also cleared both --check-github errors: tpa-db and mcp-2026-upgrade each had a docs(specs) PR in pr: (implementation evidence), so a spec merge read as "epic done" — moved to the notes, statuses left honest at todo.

Testing

  • I have tested these changes locally
  • I have added/updated tests that prove my fix is effective or my feature works
  • All existing tests pass
Check Result
go test -race, CI's own skip regex exit 0, 79 packages, zero failures
golangci-lint v2 (.github/.golangci.yml) 0 issues
Playwright web-UI sweep 30 passed / 0 failed (clean HEAD: 25 pass / 3 fail)
Frontend vitest 962 passed
Swift tray 1136 tests, 1 failure — proven pre-existing on clean HEAD
make swagger regenerated and committed
Roadmap validators --check clean, --check-github 0 errors (was 2)

Live end-to-end, real GitHub API, v0.30.0-stamped core — all six surfaces agree:

API      releases_behind: 47, weeks_behind: 15, behind_summary: "47 releases / ~15 weeks behind"
status   v0.30.0 (update available: v0.62.0, 47 releases / ~15 weeks behind — <url> — Download…)
-o json  behind_summary + releases_behind + weeks_behind, unparsed
doctor   Version: v0.30.0 (update available: v0.62.0, 47 releases / ~15 weeks behind)
log      Update available {"current":"v0.30.0","latest":"v0.62.0","behind":"47 releases / ~15 weeks behind"}
Web UI   Update available: v0.62.0 — you are running v0.30.0, 47 releases / ~15 weeks behind.

Numbers verified independently, not just for self-consistency: v0.30.0 (2026-05-12) → v0.62.0 (2026-08-28) is 108 days = 15 weeks, and GitHub serves exactly 47 stable releases in that range. Correctly not saturated, since page 1 reaches back to v0.26.2.

That check also justified a guard that looked like over-engineering: there are 48 stable-looking tags in the range but 47 releases. The extra one is v0.36.0, which carries a clean vX.Y.Z tag but is flagged prerelease: true on GitHub. Requiring both a false prerelease flag and an empty semver prerelease segment is what excluded it — trusting either signal alone would show a stable user the wrong number.

Notes for the reviewer

  • Known bound, accepted deliberately: the scan reads one 100-release page, so a build older than that window reports a lower bound (59+ releases), and a semver-in-range release created long ago can be missed without setting that flag. Spec 079's own assumption (L159) permits an approximation where an exact count is unavailable, and the figure is motivational, not load-bearing. deltaScanPages is a named constant if that ever needs raising.
  • Cross-model review: reviewed with opencode (gpt-5.6-sol), which found four defects — the latency bound was ineffective (gated only between requests: ~18s worst case, not 8s), the delta cache never expired, and deltaFunc had a data race. All three fixed and re-reviewed as fixed; the fourth is the page-boundary bound above.
  • Not verified, deliberately: the Swift tray on a running tray. It compiles and its decode path is unit-tested, but observing it needs the dev bundle-swap, and restarting the tray kills the core it manages. Tracked as the ux-audit-tray-live-verify roadmap task. The Go tray renders from the same behind_summary field the CLI does.
  • The Swift AppLifecycleTests journal failure is environmental and reproduces identically on clean HEAD — I checked before attributing it.

Closes #1081.

Two epics claimed a state the repo contradicts.

upgrade-nudge was `done` with all four tasks done, but Spec 079 FR-002 —
the human-readable "N releases / M weeks behind" delta required on status,
doctor, the startup log, the Web UI and both trays — was never built. The
four shipped tasks are US-slices and the FR belonged to none of them; spec
079 has only spec.md, so no checkbox surface could catch the gap. It
survived only as TODO(spec-079/FR-002) comments in
internal/updatecheck/checker.go and cmd/mcpproxy/status_cmd.go, which is
how an outside contributor found it (#1081). Epic back to in_progress with
an explicit upgrade-nudge-delta task.

ux-audit was `todo` with both sweeps todo, but both shipped in August
(#1046 Web UI, 36 findings; #1043 macOS tray, 16 findings) along with ten
PRs closing every finding and the five defects the re-check pass raised
(#1061/#1064/#1065, all closed). Recorded the sweeps and fix waves as done
and added the two items that really are open: folding the audit's F6 modal
Escape/focus and F1 cross-view total assertions into e2e/web-ui-sweep, and
verifying the tray fixes on a running tray (the 2026-08-26 re-walk found
the installed tray still on v0.60.0, so #1055 remains unobserved).

Also cleared the two --check-github errors, neither introduced here:

- tpa-db and mcp-2026-upgrade each linked a docs(specs) PR in `pr:`. That
  field is implementation evidence, so a spec merge read as "epic done".
  Both entries' own notes already said implementation had not started;
  moved the refs into the notes and left the statuses honest at todo.
- analytics-default-landing (#1044) and schema-deferred (#1063, tasks.md
  89/89) were genuinely finished and are now done.
Closes the last outstanding slice of Spec 079. FR-002 requires the
current version, the latest version AND a human-readable delta on
`mcpproxy status`, `doctor`, the startup log, the Web UI and both trays;
what shipped was latest-version-only, and the deferral survived as
TODO(spec-079/FR-002) comments that an outside contributor found (#1081).

The blocker was data, not rendering: the checker fetched only
/releases/latest, so it had the offered release's publish date but not the
running one's, and no tag sequence to count.

internal/updatecheck/delta.go computes the delta as a pure, network-free,
clock-free function, so every spec rule is a table row. Fetching is a
best-effort enrichment hung off the existing check — never a second check
pipeline (FR-001):

- one page of /releases (ETag-conditional, so a repeat costs no rate-limit
  budget), plus a by-tag lookup only when the running build predates that
  page and its date is therefore unknown;
- both requests share one context deadline. A per-request timeout bounds
  each hop and nothing bounds the total, and CheckNow runs synchronously
  inside GET /api/v1/info?refresh=true, so an unbounded delta would stall
  a request a user is waiting on;
- counting is by semver, never by list position: GitHub orders the list by
  created_at, and the live data has v0.53.0-rc.9 sitting ahead of the
  later-published rc.10.

Three degradation rules matter more than the feature. A delta miss must not
set CheckError (statusVersionSuffix returns "" whenever it is non-empty, so
that would DELETE the nudge instead of enriching it), must not touch the
FR-018 backoff counters, and must leave every surface rendering exactly what
it rendered before. There is a regression test per rule.

The clause is rendered once in Go (FormatBehindSummary) and printed verbatim
by every surface, with the raw numbers alongside for machine consumers. That
is deliberate: GuidanceLine is already hand-ported into UpdateBanner.vue with
a "keep the two in sync" comment, and FR-002 asks for consistent framing
across five surfaces.

Fields are additive per FR-021 and had to be threaded through six
hand-maintained mirrors — VersionInfo, the InfoResponseUpdate DTO and its
copier, internal/contracts (→ make swagger), the contracts.ts generator,
status_cmd's map decoding, and the Swift tray's Codable, which turned out
never to have decoded the US2 fields either.

Two adjacent bugs fixed because the delta sits on the same code:

- GetLatestReleaseIncludingPrereleases returned releases[0] from a
  created_at-ordered list, so an RC user could be offered a release older
  than one already published. Now max-by-semver.
- GetReleaseByTag interpolated an unvalidated tag into the request path and
  deferred validation to callers by comment only. The delta feeds it the
  ldflags-stamped version, so it now validates and escapes.

Both trays render the delta in the update item's tooltip rather than its
title: Spec 092 FR-010 fixes the title's exact shape, and a menu row reading
"Update v0.62.0 — ready to restart? — 8 releases / ~14 weeks behind" stops
being scannable.

Known bound, accepted deliberately: the scan reads one 100-release page, so a
build older than that window reports a lower bound ("59+ releases") and a
semver-in-range release created long ago can be missed without setting that
flag. Spec 079's own assumption (L159) allows an approximation where an exact
count is unavailable, and the figure is motivational, not load-bearing.

Verified: unit + integration tests against an httptest GitHub (delta,
saturation, tag fallback, 304 reuse, budget, malformed tags), `go test -race`
across internal and cmd, golangci-lint v2 clean, 962 frontend unit tests, and
a live version-stamped instance confirming the degradation path renders the
pre-delta output when the check fails.
…ught

The August Web UI audit closes by asking for four assertions to be folded
into the committed sweep. Three were already there (F9 contrast, F30
accessible names + aria-live, F14 responsive); this adds the two that were
not, and then fixes the defects they immediately exposed on main.

F6 — the Add Server modal takes focus, traps Tab, closes on Escape and
restores focus to its trigger. These `<dialog :open>` modals are opened by
the `open` attribute rather than showModal(), so none of that comes from the
browser; it all comes from useModalA11y, whose own comment delegates the
real-browser half of its coverage to "the Playwright sweep" — a promise the
sweep did not keep. Escape is dispatched IN-PAGE, never via
page.keyboard.press: re-checking F6 during the audit produced a false
negative for exactly that reason, because a synthetic key never reaches the
document listener under test.

F1 — Activity and Usage must report the same 24h numbers as the API. The
invariant is not naive equality: Usage folds `blocked` into its error tile
while Activity splits them, and /activity/usage is served from a short read
cache while /activity/summary counts live, so the assertion polls for
convergence and encodes the real relationship.

Running the completed sweep turned up three defects already on main, none of
them regressions of the audit's 36:

1. The LANDING PAGE failed AA in both themes (3.09-4.23:1) and two of its
   controls had no accessible name. Usage.vue uses the raw `opacity-*`
   utility for muted text; #1054 fixed that failure mode for the
   text-base-content ramp and .stat-* but never covered raw opacity, and
   nothing caught it because the audit walked `/` before #1044 made Usage
   the landing page. Moved onto the AA-checked --tone-muted; both selects
   got an aria-label.

2. The Activity status pill clips at 390px for any status outside the known
   four. An unmapped status falls through to a ghost pill carrying the raw
   value, and `tool_auto_approved` measured 145px inside a 93px cell (the
   table is table-fixed below 640px). The pill now truncates against the
   cell and keeps the full value in its title, rather than the column being
   sized to today's longest label — which would hold only until the next
   status is added.

The phone check that finally caught #2 had been passing vacuously: it
measures rows.first(), and a `success` row — ~90% of traffic — renders an
sr-only label of zero width. It only became a real assertion once the new F1
check generated an error row and put one first. That coupling is worth
knowing about: the sweep shares one instance, so one check's traffic is the
next check's data, and a newly-failing neighbour after adding a check is more
likely a real find than a flake. Both were separated from the change under
test by running the same sweep against clean HEAD.

Sweep: 25 passed / 3 failed on clean HEAD, 30 passed / 0 failed now.

Roadmap: ux-audit was still carrying both sweeps as `todo` although they and
every finding shipped in August; recorded here along with what the completed
net found.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 29, 2026 •

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4f6f4a1
Status: ✅  Deploy successful!
Preview URL: https://b10fb206.mcpproxy-docs.pages.dev
Branch Preview URL: https://claude-issue-1081-roadmap-df.mcpproxy-docs.pages.dev

View logs

…dmap-df1ca5

# Conflicts:
#	ROADMAP.md
#	roadmap.yaml
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 81.99052% with 38 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cmd/mcpproxy/status_cmd.go 20.00% 7 Missing and 5 partials ⚠️
internal/updatecheck/github.go 72.72% 6 Missing and 6 partials ⚠️
internal/updatecheck/checker.go 92.10% 3 Missing and 3 partials ⚠️
cmd/mcpproxy/doctor_cmd.go 0.00% 4 Missing ⚠️
internal/updatecheck/delta.go 93.75% 2 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown
Contributor

📦 Build Artifacts

Workflow Run: View Run
Branch: claude/issue-1081-roadmap-df1ca5

Available Artifacts

  • archive-darwin-amd64 (29 MB)
  • archive-darwin-arm64 (26 MB)
  • archive-linux-amd64 (17 MB)
  • archive-linux-arm64 (15 MB)
  • archive-windows-amd64 (29 MB)
  • archive-windows-arm64 (26 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (23 MB)
  • installer-dmg-darwin-arm64 (21 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 33253006954 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@Dumbris
Dumbris merged commit cb97dd1 into main Aug 29, 2026
41 checks passed
Dumbris added a commit that referenced this pull request Aug 31, 2026
…ithub warnings (#1136)

* chore(roadmap): truth-sync statuses against code, clear all --check-github warnings

An evidence-based re-derivation of every non-done roadmap.yaml leaf. Each flip
below was verified against the tree, git/gh state and the rendering sites, then
independently re-checked by an adversarial pass; claims that did not survive
that pass were dropped rather than applied.

Statuses that were wrong in the "already shipped" direction:
- upgrade-nudge-delta todo -> done (#1085, closes #1081). The note asserted
  TODO(spec-079/FR-002) markers exist and that the checker calls only
  /releases/latest; both are false. internal/updatecheck/delta.go now computes
  the delta and all six surfaces render it.
- upgrade-nudge epic in_progress -> done (all five tasks now done).
- analytics-dashboard in_progress -> done. Both children shipped; the
  default-landing half is live (router '/' -> Dashboard, guarded by
  dashboard-default-landing.spec.ts). Spec 069's one open task is a local
  Playwright sweep that leaves no artifact and can never tick from code.
- discovery-eval-harness todo -> done. Both halves ship: cmd/scan-eval for
  security recall/FP, and the eval.yml retrieval-d1 gate plus bench/'s own
  RecallAtK/NDCGAtK + recall@5 parity gate for discovery quality.
- hygiene-spec-gardener in_progress -> done (#824, #870, #999, #842). Its
  recorded blocker is cleared: check-spec-evidence.py is on main.

Statuses that were wrong in the "claimed progress it does not have" direction:
- windows-tray and windows-tray-window in_review -> todo. No Windows-tray PR is
  open or merged and native/windows/ is a README placeholder, so "in review"
  pointed at nothing. The section header is renamed to match.
- planning-hygiene todo -> in_progress and action-log-transparency todo ->
  in_progress; both already have done children.

Notes corrected where they would misdirect the next implementer:
- token-bench-harness claimed it absorbs discovery-eval-harness by measuring
  retrieval recall. Recall is already measured, and bench/ already covers token
  counting, encoding arms (incl. direct_deferred), break-even and reporting.
  The note now records what is genuinely open: activity-log session replay,
  measured first-call success/retry rate, and tokens-per-successful-task.
- token-bench-public: the MCP-specific third already ships via spec 083
  (ToolRet, LiveMCPBench snapshot, lap-score); only agent-loop suites remain.

specs/098-tools-preflight/tasks.md: tick T001, T024, T031, each confirmed
against the tree (doc.go states both invariants T001 requires;
toolslist_snapshot_test.go is labelled T024 and green; README carries all three
FR-017 examples). T025/T027/T032/T033 are left unchecked — they are one-time
process acts or did not survive verification.

Deliberately NOT changed: no epics were added for shipped specs (084-100).
roadmap.yaml is the working set by design and ROADMAP.md already renders a
generated per-spec progress table, so absence of an epic is not drift.

scripts/gen-roadmap.py --check-github: 3 warnings -> 0 errors, 0 warnings.

* fix(roadmap): correct six claims flagged by cross-model review

All six findings from the opencode gpt-5.6-sol review were independently
re-verified against the tree before being applied; none were false positives.
(The reviewer's initial claim that spec-gardener-auto-approve.yml is missing
WAS a false positive from its glob tool and it self-corrected — the file exists
at .github/workflows/spec-gardener-auto-approve.yml.)

1. Un-tick specs/098 T024. T024 asks for a golden snapshot test proving
   tools/list is BYTE-IDENTICAL across all three modes. Spec 099 (FR-014/015)
   later converted that test from a no-delta gate into an ENUMERATED-delta gate
   (toolsListAllowedDelta permits describe_tool and quarantine_security to
   move), so at HEAD the test no longer demonstrates the property T024 states.
   It may well have held on 098's own branch, but that is not checkable from
   the tree, and an unverifiable tick is exactly what this PR exists to remove.
   Badge 29/33 -> 28/33.

2. discovery-eval-harness note: drop the "SUPERSEDED — folded into
   token-bench-harness" framing. It contradicted itself once the epic was
   marked done — token-bench-harness is still unbuilt, so nothing could have
   been folded into it. Both halves shipped independently.

3. Same note: the eval.yml retrieval-d1 job is REPORT-ONLY on pull requests
   (continue-on-error, guarding against npx/uvx fetch flake) and blocks only on
   the nightly schedule. Promoting it to PR-blocking is still open (MCP-742).

4. Same note: the SC-003 recall@5 = 0.68 +/- 0.05 parity gate is asserted in
   bench/armindex_test.go, not armindex.go — the latter supplies the production
   index wiring, not the assertion.

5. token-bench-harness note: the literature-derived retry defaults live in
   bench/session.go (armRetryRates, research D8). bench/report.go only renders
   and labels them as estimates. The substantive point stands: retry rates are
   assumed, not observed.

6. token-bench-public note: "CI-wired" overstated the LiveMCPBench snapshot.
   bench.yml's regular job passes only -corpus-v2; the snapshot is runnable via
   -livemcptool but not run in CI, and its loader has no retrieval golden set,
   so it measures token/scale rather than recall. ToolRet does have its own
   bench.yml job.

gen-roadmap.py --check and --check-github both still clean.

* fix(roadmap): tighten two claims from cross-model review round 2

Both findings verified against the tree before applying.

1. The retrieval-D1 blocking scope was stated too narrowly. eval.yml sets
   continue-on-error only for github.event_name == 'pull_request', and the
   workflow triggers on pull_request, workflow_dispatch and schedule — so the
   job is report-only on PRs and BLOCKING on both nightly and manual dispatch
   runs, not "only on the nightly schedule". The note now says so, and records
   that the workflow's own inline comment carries the same omission.

2. discovery-eval-harness is now done but still declared
   depends_on: [token-bench-harness], which is unbuilt — a done node cannot
   depend on an open one, and the edge contradicted the corrected note saying
   both halves shipped independently. Edge removed; the id remains a valid
   depends_on target for anything that needs it.

gen-roadmap.py --check and --check-github both clean.

* fix(roadmap): scope four over-broad claims from cross-model review round 3

All four verified against GitHub and the tree before applying.

1. windows-tray: "no Windows-tray PR is open or merged" was false. #74
   ("feature: windows tray support") merged 2025-10-23 and the cross-platform
   Go/systray build still ships on Windows. The claim now scopes to what the
   epic actually tracks — the native WebView2 replacement — for which no PR
   exists and native/windows/ is a README placeholder.

2. analytics-dashboard: "can never tick from code" conflated two things. A
   human can run spec 069's T023 Playwright sweep and tick the box; what can
   never exist is code evidence for it. Reworded so the distinction is explicit.

3. hygiene-spec-gardener: "three gardener runs ... auto-approved by #842" was
   wrong. Only #999 carries a github-actions APPROVED review. #824 has none and
   merged ~24 minutes BEFORE the auto-approve workflow landed; #870 records no
   approving review either.

4. token-bench-public: calling the MCP-specific third "integrated" overstated
   completion. ToolRet and LiveMCPTool are static retrieval/token corpora and
   lap-score is a linter — none is a public agent-loop task suite, which is what
   the task ultimately owes.

Also noted for the record: the linux-arm64 Build Binaries failure on the
previous commit is a flaky test, not a regression from this docs-only change.
TestServiceStartScanDeepOnRunsSourceResolutionAndPass2
(internal/security/scanner) passes locally with -count=3, and two runs of this
same branch four minutes apart — 33360429077 and 33360648947, both docs-only —
disagreed on it.

* fix(roadmap): ToolRet is not MCP-specific (cross-model review round 4)

Verified: bench/corpusio/toolret.go documents ToolRet as a general
tool-retrieval corpus whose documentation fields are "heterogeneous JSON/text,
NOT MCP input schemas" (Schema stays nil). Grouping it under "the MCP-specific
third" was wrong.

The token-bench-public note now says public corpus/linter groundwork is
integrated while NO public agent-loop task suite is, and names the ToolRet
caveat explicitly so the next implementer does not re-inherit the error.

Round 4 found no other issues; the round-3 windows-tray, analytics T023 and
gardener corrections were all confirmed accurate against GitHub and the tree.

* fix(roadmap): discovery-eval-harness is in_progress, not done (review round 5)

The final review round caught an error in this PR's own flip, and it is the
same failure mode the PR was written to fix: an epic marked done while a
governing FR is unmet.

Spec 065 FR-009 and SC-005 require CI to FAIL on a discovery regression beyond
tolerance. The retrieval-D1 job sets continue-on-error for pull_request (D1
depends on npx/uvx fetches, a known flake source), so on the PR path CI does not
fail — and eval.yml's own comment records the promotion to PR-blocking as still
planned (MCP-742). The HARNESS shipped; the GATE did not.

Reverted to in_progress and added the remaining work as a child task
(discovery-eval-pr-blocking, MCP-742) so the epic's status has something in the
DAG to point at.

The reviewer also read CN-002 (frozen corpus, never live) as violated because D1
boots a live mcpproxy serving seven reference servers. Recorded as a weaker
tension to adjudicate rather than a violation: #931 pinned all seven upstreams
to freeze-era versions and the job gates on the exact corpus ID set, so the
corpus is reproducible in practice. Whether that satisfies CN-002 or a committed
snapshot is required is a judgement for the spec owner.

gen-roadmap.py --check and --check-github both clean (0 errors, 0 warnings).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Spec 079 FR-002: upgrade delta follow-up

2 participants