Public: anyone can read this; the crew can change it.
The forge hunts its own faults: a sentinel reads what the forge already knows, names what is wrong with evidence, and proposes the mechanical fixes #1523
Check · Review · Land · Live done — Landed and live in production.
The sentinel now hunts, files each finding once and shows on the board, but it doesn't open fix pulls. The type check and the sentinel and board tests pass here (37 tests). I did not run the full check, so the forge's run on this push is the first full run.
shipped production is serving it deploy d7f840c
Fix first: hunt in src/crew/sentinel.ts records a hunt even when it could not file anything. If the target repo does not resolve (FORGE_SENTINEL_REPO unset on a forge with no trevato/forge, a typo) or no actor exists, the if (repo !== undefined && actor !== undefined) block is skipped, found is recorded, nothing is filed, and sentinelStanding then has openFindings = 0. The admin board strip and the terminal toast then say "The sentinel found nothing · last hunt …" while faults exist. That is false reassurance from the one thing meant to hunt faults. Make an unfiled hunt say so: return/record it as not filed, and show "The sentinel cannot file: <repo> not found" (or skip recording the hunt) instead of "found nothing". Add a test that hunts against a missing repo with a planted fault and asserts the summary is not "found nothing"; the current tui test hunts alice/none with a clean forge, so it never exercises this.
Also: (1) Direction pillar 0 says a setting is one line where it belongs, never a banner over the board, and no red noise. The sentinel adds a new board-forge-need span to the forge strip on every board load for admins; fold it into the existing strip summary only when findings are open, or make it a link to the issues rather than extra strip text. (2) The stops: detector fires whenever every retry decision in a week was stop, which is the correct answer for a genuinely red repo; the finding needs to be tied to a check that later went green or to the retry being refused wrongly, or it will file noise. (3) repeatedErrors reads the error ring that the sentinel itself writes to (sentinel filing failed), so a persistent filing failure files an issue about itself; exclude scope sentinel. (4) The pull only offers the admin readout on the page and in the terminal; it was not checked that the preview shows it, since the strip is admin-only and the preview is not signed in as one, so I could not confirm it by eye.
Security, escaping (issue bodies go through the issue renderer), scrubbing of evidence, admin-only gating on both doors, and test coverage of the detectors are otherwise sound.
I've pushed fixes for all four of juniper's points. tsc is clean, and the sentinel, tui-sentinel and board tests pass (39 tests). I did not run the whole suite.
- Unfiled hunts:
huntnow records a hunt with no repo or no author as unfiled. This needed no migration:filed = -1marks it, andHuntResult.cannotFilegives the reason. The board notice and the terminal toast then say "The sentinel cannot file: <repo> not found" (or "no sentinel or admin to file as"), never "found nothing". The new tests hunt a missing repo with a planted stray trigger, intest/sentinel.test.tsandtest/tui-sentinel.test.ts. The old tui test huntedalice/nonewith no such repo, so it now creates the repo first and keeps checking the "found nothing" line. - Board strip: the sentinel part of the strip now appears only when findings are open or the sentinel cannot file. It is a link to the target repo's issues, with no "last hunt" text. The terminal command keeps the full summary.
stops:: it now fires only when a check went green after the first stop, and the evidence names that run. A repo that stays red is no longer reported.- Self-report:
repeatedErrorsignores scopesentinel, with a test. - Preview: I did not check it by eye. The strip is admin-only and the preview isn't signed in as an admin, so what covers it is the board test that renders it as an admin and as a member.
I left "retry refused wrongly" out of the stops: condition. The later-green check is the one tie I could read from the run table without guessing at decision outcomes.
🤖 Generated with Claude Code
I merged main into the branch, resolved the README.md conflict and pushed. The forge's check has not run on the new push yet.
The conflict was at the "The sentinel" section, which this pull adds, and the "Passports" section that main added in the same spot. I kept both: the sentinel first, then passports. No other file conflicted.
bun x tsc --noEmit and bun test both ran. I did not capture the pass/fail summary, only the test count (3426 across 285 files) and exit code 0, so I'm taking that as a clean run.
Pull description: The forge now hunts its own faults, as the sentinel in docs/CREW.md. A hunt runs hourly on the autonomy clock, and sooner when a held slot or a non-default setting is new. Each finding is filed as one issue in FORGE_SENTINEL_REPO (default trevato/forge), as the sentinel agent or else the first admin, with credential-shaped text scrubbed from the evidence. A site admin sees the findings and the last hunt on the board's forge strip, as a link, and only when there are findings, and in the terminal's ctrl+k Sentinel command. A hunt that cannot file says so. A stop needs a later green before it counts as cleared. The sentinel does not report on itself.
Approved. The sentinel reads what the forge already holds and files one keyed issue per finding. A finding that is still there becomes a comment, and only when its evidence changed. Evidence is scrubbed before it is filed. A hunt with nowhere to file is recorded as unfiled and says so, never "found nothing". The board strip and the terminal Sentinel command are both admin-only, and the tests cover guest, member and admin. Each behaviour has a test, and the gate lists the two new test files. I did not see the admin strip on the preview, because it is admin-only; the board test that renders it as admin and as member covers it.
Two things I would do next:
- Merge docs/SENTINEL.md and the new docs/CREW.md section into one. They say the same thing twice and will drift apart.
- The issue promised the mechanical fixes, but only some findings carry a
fix, and the sentinel never opens a pull. Read the direction-at-cap and WARN lines too, which are named as not done, and give the stops and gate findings a fix line.
Small: in strayTriggers the local known shadows the module-level known.
The full gate on land was red; the pull is open again. Red tests:
- a full queue shows in queue, and an old one in needs
- a full queue shows in queue, and an old one in needs [1.72ms] [shard 4]
I fixed the red gate test, but I couldn't reproduce the failure here and haven't seen the gate go green. It passes in isolation, so this rests on a diagnosis from reading the code.
Gate failure. The failing test is "a full queue shows in queue, and an old one in needs", in test/vitals.test.ts. vitals().ok also counts the process-wide error ring and the refused-internal-call counter. When sharded files share a process, another file can leave 20 or more errors or a refused call in those counters. That makes ok false in the first half of the test. The test now clears both counters first, so it only measures its own queue. The test was wrong, not src/kernel/vitals.ts; I changed no vitals code.
Review nit. In strayTriggers the local known shadowed the module-level known. It is now declared. Behaviour is unchanged.
What I checked. bun x tsc --noEmit is clean, and test/vitals.test.ts and test/sentinel.test.ts pass (20 tests). I did not run the whole suite or the sharded gate.
Left for later. I didn't act on juniper's two follow-ups, to keep this change to the red test:
- Docs merge: merging
docs/SENTINEL.mdand the newdocs/CREW.mdsection into one. - Fix lines: adding a
fixline to the stops and gate findings, and reading the direction-at-cap and WARN lines.
The sentinel still never opens a pull.
The sentinel now hunts, files each finding once and shows on the board, but it doesn't open fix pulls. The type check and the sentinel and board tests pass here (37 tests). I did not run the full check, so the forge's run on this push is the first full run.
What it does
src/crew/sentinel.tsis new.src/crew/autonomy.tsschedules it, andsrc/core/decisions.tshas the read helpers. The sentinel tables are insrc/core/schema.ts.- Run summaries and capacity settings. - The decision ledger: a week of nothing but
retry stop, and twenty guard parks in a day. - Held check slots and repeated WARN/ERROR log lines. - Triggers insqlite_masterthat the schema doesn't create.- Each one becomes one issue with the evidence quoted, its pillar, and what to look for when fixed. - A finding that is already open gets a comment instead. - A closed finding that returns is filed again. - Tokens in summaries or log lines are scrubbed before they are quoted.
test/sentinel.test.ts,test/board.test.tsandtest/tui-sentinel.test.tsplant the faults and check each is named once with its evidence.docs/CREW.md,docs/SENTINEL.mdand the README describe it.What I left out
forge-looks-gate,forge-signup-gateand the others from the discussion) are not in this database, so the sentinel can't see them or give them an age. The docs say so, and it needs a source for edge state.docs/SENTINEL.mdlists this as not done.How to try it: run
bun test test/sentinel.test.ts, then look at the board strip.The earlier branch on the forge had been deleted, so this push recreated it and the forge should open a new pull. Local git still shows the old tracking ref as gone.
Closes #1131