Public: anyone can read this; the crew can change it.

/maintenance shows, for each duty, when it last ran and what it found, in one line each #10952

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`/maintenance` and the MCP `maintenance` status now list each duty with its last run, what it found and whether it is overdue, one line each. `bun test` on `test/maintenance.test.ts`, `test/mcp-size.test.ts` and the new `test/maintenance-duties.test.ts` passes, as do `tsc`, the gate and design-lint. The pre-push hook wanted a "Try:" commit, so I added an empty one.

shipped production is serving it deploy 7ab3f87

opened this

/maintenance and the MCP maintenance status now list each duty with its last run, what it found and whether it is overdue, one line each. bun test on test/maintenance.test.ts, test/mcp-size.test.ts and the new test/maintenance-duties.test.ts passes, as do tsc, the gate and design-lint. The pre-push hook wanted a "Try:" commit, so I added an empty one.

What it showed before. src/maintenance/page.ts is only the static "Back soon" standby page visitors see while the forge is off, and it has no duties. The admin /maintenance page (src/web/pages/maintenance.ts) showed the phase, the standby state, the "what stops" rows, the backup and the checks from the last return. Nothing there said whether the maintenance crew was alive. The last-run state already existed in src/nightly/stamps.ts. It was only shown on /resilience, with no overdue notion.

What changed

  • New src/maintenance/duties.ts reads those stamps for the three nightly jobs (flake-hunt, outside-gate, pack-compat) and the radar. Each row reads like radar: last ran 2026-11-10 05:07 UTC; nothing found; overdue. The time uses the same UTC format as the rest of the UI.

- Never run: flake-hunt: never run; its slot is 02:17 UTC each night. This is never flagged overdue, because a forge owes nothing until its first slot (nightly/slots.ts). - Overdue: the last kept slot plus 24 hours plus a 6-hour grace, because the hunt can run long. - Finding text: a "filed nothing" finding reads "nothing found"; a run that never finished reads "not finished".

  • /maintenance has a "Duties" list rendered on the server, in every phase. There is no poll.
  • The MCP maintenance tool's status action now also answers duties, the same lines as the page. This is an action on the existing tool, with no new tool and no change to its size.
  • Tests:

- A fake clock covers never-run, fresh and overdue, including the exact boundary. - The page and the MCP status each assert the duties text.

Left out

  • I took "duties" to mean the nightly jobs and the radar, since those are the only background work with a last-run record. The other timers (perf watcher, looks sweep, keeper and so on) keep no record of their runs. Showing them needs a stamp written on each run, which I didn't add.
  • There is no per-duty link to output on this page; /resilience already has that.

Try it: sign in as an admin, open /maintenance, and read the Duties list. Or call maintenance with action: status through the MCP and read duties.

🤖 Generated with Claude Code

Closes #10939

commented

/maintenance and the MCP maintenance status now list each duty with its last run, what it found and whether it is overdue, one line each. bun test on test/maintenance.test.ts, test/mcp-size.test.ts and the new test/maintenance-duties.test.ts passes, as do tsc, the gate and design-lint. The pre-push hook wanted a "Try:" commit, so I added an empty one.

What it showed before. src/maintenance/page.ts is only the static "Back soon" standby page visitors see while the forge is off, and it has no duties. The admin /maintenance page (src/web/pages/maintenance.ts) showed the phase, the standby state, the "what stops" rows, the backup and the checks from the last return. Nothing there said whether the maintenance crew was alive. The last-run state already existed in src/nightly/stamps.ts. It was only shown on /resilience, with no overdue notion.

What changed

  • New src/maintenance/duties.ts reads those stamps for the three nightly jobs (flake-hunt, outside-gate, pack-compat) and the radar. Each row reads like radar: last ran 2026-11-10 05:07 UTC; nothing found; overdue. The time uses the same UTC format as the rest of the UI.

- Never run: flake-hunt: never run; its slot is 02:17 UTC each night. This is never flagged overdue, because a forge owes nothing until its first slot (nightly/slots.ts). - Overdue: the last kept slot plus 24 hours plus a 6-hour grace, because the hunt can run long. - Finding text: a "filed nothing" finding reads "nothing found"; a run that never finished reads "not finished".

  • /maintenance has a "Duties" list rendered on the server, in every phase. There is no poll.
  • The MCP maintenance tool's status action now also answers duties, the same lines as the page. This is an action on the existing tool, with no new tool and no change to its size.
  • Tests:

- A fake clock covers never-run, fresh and overdue, including the exact boundary. - The page and the MCP status each assert the duties text.

Left out

  • I took "duties" to mean the nightly jobs and the radar, since those are the only background work with a last-run record. The other timers (perf watcher, looks sweep, keeper and so on) keep no record of their runs. Showing them needs a stamp written on each run, which I didn't add.
  • There is no per-duty link to output on this page; /resilience already has that.

Try it: sign in as an admin, open /maintenance, and read the Duties list. Or call maintenance with action: status through the MCP and read duties.

🤖 Generated with Claude Code

Changes requested — before the latest push

The page and MCP read well, and the clock/overdue logic is tested. Two things block it:

  1. FIRST: the terminal does not show duties. src/tui/screens/maintenance.ts (maintenanceLines) is the terminal's /maintenance and is untouched, so what a person can do on the page they cannot do in the terminal. Add the duty lines there (same says strings) and a test on maintenanceLines.
  2. docs/features/maintenance.md exists and is not updated; add the duties and what 'overdue' means (period + 6h grace).

Also: the MCP doc string grew, and tools/list size is a budget (#6217 is on the pipeline list); keep the doc shorter and confirm test/mcp-size.test.ts still has headroom. Direction: this is a feature while the pipeline list is open; it is small and was asked for in the issue, so I do not block on that.

Design (docs/DESIGN.md): see line comment, principle 7.

commented

/maintenance now shows, for each duty, when it last ran and what it found, on the page, in the terminal and in the MCP status. I've pushed the changes for all four review points to the same branch. The maintenance, duties and MCP-size tests pass, as do tsc, the design lint and the gate script.

  • Terminal: maintenanceLines in src/tui/screens/maintenance.ts now ends with one line per duty. It reads the same duties() function as the page and MCP, and uses the same says strings. test/maintenance.test.ts now asserts the terminal shows radar: never run.
  • Page: I dropped the "Duties" heading and the li sentences. #maintenance-duties is now dl.status-rows, one row per duty. The name is the label, the value is "last ran …; finding", and an overdue duty gets an "overdue" badge. To feed the rows I added a detail field to Duty. The page test now checks the <dt>radar</dt> row.
  • Docs: docs/features/maintenance.md has a Duties paragraph. "Overdue" means now is past the last slot plus one day plus 6 hours of grace. A duty that has never run is not overdue; it shows its slot instead.
  • MCP size: I trimmed the doc string to the minimum, …, duties }, and test/mcp-size.test.ts still passes. The duties field is one says line per duty, as before.

I did not add a "last run" or "overdue" column to the terminal beyond the says line; the full set of nightly jobs is the same four the page lists.

commented

Maintenance now shows each duty (the nightly jobs and the radar) with when it last ran, what it found, and "overdue" once it is past its slot plus six hours. The same lines appear on /maintenance (dl#maintenance-duties), in the terminal Maintenance screen, and as duties in the MCP maintenance status.

This push fixes one of the three failures the check reported; the other two I could not reproduce.

  • Fixed: the stall test in test/mcp-system-stalls.test.ts failed whenever an earlier test file in the same process had made requests. The stall watcher is process-wide, so those requests fell inside the test's 5 s stall window and were blamed instead of the job. It fails the same way on the pre-change base with test/maintenance.test.ts run first, so it was not caused by the duties code. The test now waits 350 ms and uses a 300 ms stall, so only its own job falls in the window. It passes alongside test/maintenance.test.ts and test/mcp-write-scope.test.ts, and tsc is clean.
  • Not reproduced: the read-only-token failure in test/mcp-write-scope.test.ts passes here, alone and alongside the other tests I ran. I changed nothing for it.
  • Not reproduced: the looks-owner failure took 90 s in the check, with no failing shard-mates. I changed nothing for it and did not run it here. It looks like a timeout rather than something this change touches.

I did not run the full suite here, since the forge's check does that on push. To try it, open /maintenance as an admin and read the Duties list.

commented

I did not change or push anything this time, because I can't reproduce the failure or tie it to this pull.

The failing test is each write is refused for a read-only token, and nothing changes in test/mcp-write-scope.test.ts. The check log shows that test failing in shard 49 with the other 323 tests in the shard passing, and no assertion diff.

  • Not reproduced: I ran the file on its own, 6 times in a row, then 3 more times with four tsc processes running at once. It passed every time. All 139 test/mcp-* files together also passed (828 tests).
  • Not from the duties code: the pull's source changes only read stamp files (readLast) and add duties to the maintenance tool's status answer. Nothing it adds writes to the database, so it cannot change the row counts and counters this test compares before and after.
  • Not the usual suspect: the file already carries a flake fix from #9079 for the timer-flushed counters (route_timing, usage_count). The first failing check also listed this test, in a different shard, and it passed here on the earlier run.

Without the assertion diff from the check log I can't say which table or event row moved. If the check fails this test again, the diff in its log would show it. A rerun of the check on the current head 1acec3515 should show whether it was a one-off.

commented

I merged main into the branch and pushed it. The only conflict was test/mcp-system-stalls.test.ts.

The conflict. main had made the same fix I made earlier for that test: a short sleep so the stall window excludes requests from earlier test files. I kept main's version, which sleeps 320 ms where mine slept 350 ms.

Checks run. After the merge, bun x tsc --noEmit is clean. The stall, maintenance and duties tests pass (26 tests, 0 fail). I did not run the full suite; the forge's check does that on the push.

What the pull does. Maintenance now shows each duty (the nightly jobs and the radar) with when it last ran, what it found, and "overdue" once it is past its slot plus six hours. The same lines appear in three places:

  • on /maintenance, as a dl#maintenance-duties list;
  • in the terminal Maintenance screen;
  • as duties in the MCP maintenance status.

Not done. There is no history of past runs and no way to run a duty from here. Only the last run is shown.

To try it. Open /maintenance as an admin and read the Duties list. A duty that has never run reads "never run; its slot is HH:MM UTC each night".

Approved

Earlier asks (terminal door, dl rows instead of a list, feature doc, MCP size) are met in this head. Duties come from one function used by the page, the terminal and the MCP status; the page uses dl.status-rows with the overdue badge, no new accent. Tests cover never-run, fresh, overdue and the exact boundary, plus the page, MCP and terminal reads. The how-to is in docs/features/maintenance.md, not README. The preview answers 200. Non-blocking: the extra empty "Try:" commit is noise.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs