Skip to content

fix: close six Console, prompt, and gate defects that assert a state the code lacks - #116

Open
dichovsky wants to merge 5 commits into
mainfrom
fix/console-roster-and-stale-comments
Open

fix: close six Console, prompt, and gate defects that assert a state the code lacks#116
dichovsky wants to merge 5 commits into
mainfrom
fix/console-roster-and-stale-comments

Conversation

@dichovsky

Copy link
Copy Markdown
Owner

Closes #23
Closes #24
Closes #50
Closes #59
Closes #60
Closes #68

Six defects that share one shape: something in the repo asserts a state of the world that the code does not have. Two of them are only comments, but a comment claiming an exact inventory is the thing a reader audits from — and the other four are live: an HTTP request can drive the Console into tmux attach, a supported Participant CLI renders as unrecognized, a whole tsconfig project sits outside the typecheck gate, and every shipped Role prompt tells an Agent to wait for a reset that no code delivers.

All six were re-verified against main @ 09e67cd by opening the cited files, not from the issue bodies. Deltas found are recorded per-issue below.

What changed and why

Issue File(s) Change
#59 web/view-model.ts ENGINE_META gains a little-coder entry (label Little Coder, matching docs/design/setup-integration.md and src/platforms/little-coder.ts) and is exported so a test can pin its key set.
#50 src/launcher/resume.ts, src/ui/actions.ts runTeamResume's deps slice widens from 'adapter' | 'delay' | 'relayBin' to include 'noAttach'; resumeTeam passes noAttach: true exactly as launchTeam already does.
#23 src/templates.ts The Manager and Worker prompts stop asserting that crew performs the context reset, and say it is not delivered yet.
#24 e2e/ui/tsconfig.json, package.json The tsconfig gains skipLibCheck and a DOM lib so it compiles; typecheck now runs it.
#60 src/ui/server.ts The header's "EXACTLY" route list gains the FR-U36 agent-archive/restore POSTs.
#68 src/format.ts The CREDENTIAL_KEY comment drops the nonexistent env guardrail and points the environment property at FR-J13.

#50 — the delicate one

FR-U20 (docs/design/srs.md:809-812): "A Team launch from the Console shall be detached, and attaching to its session shall remain a terminal-only action." Under docs/README.md's authority order the SRS is rank 2 and the code is the bug.

The mechanism reproduces exactly as filed. launchTeam passes noAttach: true; resumeTeam structurally could not, because runTeamResume's deps were Pick<LiveLaunchDeps, 'adapter' | 'delay' | 'relayBin'> — the attach seam was not in the slice. The resumed plan is rebuilt from current config with no flags, so attach: flags.noAttach !== true (src/launcher/config.ts:408) yields attach: true, and runLiveLaunch reached adapter.attach(session) (src/launcher/session.ts:292) inside the foreground crew ui server process.

The fix is deliberately the minimum: one type widened, one field passed. No new HTTP route, no new capability, no requirement change, and crew team resume from a terminal is untouched — the CLI omits noAttach, so its plan-driven attach behavior is bit-for-bit what it was. web/components/operations.tsx needed no change; the client was already correct.

For #79 (Console team-resume traceability), which is a different PR: the only behavioral change here is that POST /api/team/resume no longer attaches. TEAM_POSTS in tests/integration/ui-server-team.test.ts is deliberately not touched — adding /api/team/resume to that shared registry stays #79's, so nothing here collides with it.

#23 — why the prompt moves, not the ADR

ADR-0016 is authority rank 1, and its Consequences are explicit: "The Relay delivery, the registry field, and their requirements land in a follow-up change to this one." That follow-up has not landed — clear_safe reaches no delivery in src/relay.ts or src/launcher/, and no src/platforms/ record carries a reset field. So the shipped prompt is the wrong side.

The new wording keeps ADR-0016's own finding (a Worker cannot reset itself — proven impossible on every supported engine) and drops only the claim that crew already delivers the reset.

Deltas against the issue bodies

Issue Delta
#59 The body's parenthetical suggests ENGINE_META's labels "diverge from the registry's". There is no display-name field in the registry at allgrep -n displayName src/platforms/ is empty; ParticipantTarget carries id/executable, never a human label. So there was nothing to reconcile, and the judgment call the body offers is moot. Only the missing-key gap is closed; the other seven labels are untouched.
#50 Every cited line still resolves. TeamActionDeps is at :293-300 and resumeTeam at :377-387 before this change (both shift by the added docblock). The docblock already called it "a DETACHED recovery launch", confirming the divergence was unintended.
#24 The body says "~20 TS2304 errors". The real count on main is 139npx tsc -p e2e/ui/tsconfig.json 2>&1 | grep -c "error TS"139, exit 2. Same root cause, an order of magnitude more.
#23 src/templates.ts:33-34 and :73 both still hold verbatim. The second half of the issue's acceptance is NOT in this PR — see Cross-PR dependency.
#60 Every line cited is exact: header :12-18, TASK_ACTION_ROUTE :262, AGENT_ACTION_ROUTE :264-265, POST_PATHS :268-276, isActionPath :277-283, correct docstring :278. One thing the body does not mention: with the agent routes listed, the header's trailing "the destructive three gated by the FR-U25 flag" also became wrong — archive is FR-U25-gated too (src/ui/actions.ts:646-650). Corrected to "the destructive ones (stop, prune, clean, archive)" in the same sentence, so the header is not left half-true.
#68 Confirmed exactly, including that src/doctor.ts and src/setup/index.ts read the environment only for PATH lookup and path derivation. FR-J13's title is "No credential env value" (srs.md:692), as the body states.

None of the six were already fixed by #85/#91/#94/#97/#101; all six reproduce on 09e67cd.

Red → green evidence

Every behavioral fix was driven test-first. Each RED was produced by running the new test against the unfixed source (git stash push <the source file>, run, git stash pop), not by reasoning about it.

Issue Test RED (before fix) GREEN (after fix)
#59 web/view-model.test.tsENGINE_META covers exactly the shared Participant id vocabulary, plus a little-coder label/glyph case 2 failed / 34 passed. expected 'little-coder' to be 'Little Coder'; and TypeError: Cannot convert undefined or null to object (ENGINE_META was not exported) 36 passed
#50 tests/integration/ui-server-team.test.tsPOST /api/team/resume (FR-U20) > resumes a cleanly stopped session DETACHED: zero attach calls AssertionError: expected [ 'isPresent', …(29) ] to not include 'attach' — the resume returned 200 having attached, i.e. the server really did reach tmux attach 37 passed (whole file)
#23 tests/unit/templates.test.tsADR-0016 relay-delivered reset is still a follow-up (2 cases) 2 failed / 3 passed, on crew then resets the Worker's session itself and crew performs the context reset itself 5 passed
#24 npx tsc -p e2e/ui/tsconfig.json, and tests/unit/typecheck-projects.test.tsnpm run typecheck compiles every TypeScript project in the repo tsc exit 2, 139 errors; the guard failed with tsconfigs outside the typecheck gate: e2e/ui/tsconfig.json tsc exit 0; guard passes

#60 and #68 are comment-only and add no tests (CONTRIBUTING.md:98, .github/ISSUE_TRIAGE.md: docs/comment-only exemption, claimed explicitly here). Every other issue in this PR carries a test — this PR takes no blanket docs-only exemption.

One test-fixture change worth flagging

The #50 test needs the resume happy path to actually complete, or "zero attach calls" would pass vacuously on an early failure. Two things in fakeTmux prevented that, and both were fixture inaccuracies rather than product behavior:

  1. The fake joined panes with no platform, so after a stop the archived rows failed assertArchivedResumable's agent.platformId !== plan.client check (409 TEAM_DRIFT). Real panes register on the configured client.
  2. A resume launch appends --resume to the invocation, which the fake's positional parser read as the agent id, and it never passed resume: true — so the reactivation became a suffixed new row and stage-2 roster readiness failed.

Both were corrected in the fake only. All 36 pre-existing tests in that file still pass unchanged.

Verification

Run on the final pushed tree, Node v24.19.0, uid 501 (not root).

Command Exit Result
npm run typecheck 0 clean — four projects now
npm run lint 0 clean
npm run format:check 0 clean
npm run build 0 dist/ + dist/ui-assets/main.js
npm run build:docs 0 dist-docs/main.js
npm run test:coverage 1 1394 passed, 11 skipped, 1 failed suite — pre-existing and environmental

Coverage — all four thresholds clear 95%:

Stmts Branch Funcs Lines
All files (src/**, bin/**) 97.64 95.2 98.45 98.27

Because vitest suppresses the coverage table when a suite fails to collect, those numbers come from an otherwise identical run with the failing file moved aside, which exited 0 — i.e. the thresholds were genuinely evaluated and passed, not inferred.

Pre-existing-failure proof (performed, not assumed). The failure is tests/integration/package/pack-smoke.test.ts, collapsing in beforeAll with TypeError: Cannot read properties of undefined (reading 'files') at :40 — this npm parses npm pack --json into a shape the test does not expect; its 9 tests skip. Proven by git stash push -u on every changed file, confirming git status --porcelain reported only the untracked node_modules symlink, re-running that file standalone on the clean tree, then git stash pop. Identical both ways: 1 failed suite / 9 skipped. This PR's CI run, on the pinned Node 24.18.0, is authoritative.

The two doctor.test.ts tests that fail under uid 0 did not appear here — id -u is 501.

Cross-PR dependency — read this before merging

npm run typecheck now runs FOUR tsconfig projects, not three. Exactly three documents state the old count, verbatim and identically. None were edited here — all three are out of scope for this PR — so each needs a lockstep update or it goes stale on merge:

Document Location Current text
CLAUDE.md :59 npm run typecheck # 3 tsconfigs, all noEmit: root (incl. tests), web/, docs-site/
AGENTS.md :59 (byte-identical file) same
CONTRIBUTING.md :26 same

One correction to the hazard as originally scoped to me: docs/design/srs.md does not state the count. Its automated-gate sentence (:1217) names npm run typecheck as a command and never enumerates projects, so it stays true and needs nothing. CONTRIBUTING.md:26 carries the claim instead — same total of three sites, different third one.

#23's ADR-index half is not done here. The issue's acceptance is "soften the Role wording in src/templates.ts and add the 'lands in a follow-up change' caveat to the ADR index row". docs/adr/README.md:20 still states the mechanism unconditionally, and this PR must not edit docs/**. PR #110 touches both docs/adr/README.md and ADR-0016 but leaves that row's wording unchanged — so nothing currently open closes it. The Closes #23 above is claimed on the code half; if the reviewer wants the ADR index caveat in the same change, that row needs a docs-owning PR.

Deliberately not done

  • crew_version was not bumped on the two changed Role prompts (manager/worker stay at 4). No code compares versions — parseVersion (src/roles.ts:53) only reports it, and infoFor's packaged-vs-project classification is a byte comparison, not a version comparison. Bumping would also require editing tests/integration/commands/roles.test.ts:62's pinned version: 4. Left minimal and flagged rather than decided silently.
  • e2e/ui/tsconfig.json was not aligned to the root project's other strict flags (exactOptionalPropertyTypes, noUncheckedIndexedAccess, verbatimModuleSyntax). Only the two options e2e/ui tsconfig is neither wired into typecheck nor able to compile #24 names were added; tightening the specs is a separate change.
  • The other seven ENGINE_META labels ("Codex", "Gemini", "Copilot") are untouched — see the Console: ENGINE_META omits little-coder, so its panes render the raw id #59 delta.

Contract impact

No ADR is amended, no FR-*/NFR-* is added or given new meaning, no CLI grammar rule, record type, error code, command, or flag moves, and CURRENT_SCHEMA_VERSION is unchanged. #50 moves the code toward FR-U20 rather than changing it. package.json's only edit is the typecheck script — no version, dependency, or files change.

Related open PRs

No file overlap with any open PR (gh pr list --state open --json number,title,files). #115 touches src/doctor.ts, #114 src/platforms/shared.ts, #113 the agent guides, #112/#111/#110 docs/**. The only relationships are the two dependencies named above: #110 (ADR index, for #23) and #113 (which already edits CLAUDE.md/AGENTS.md — the natural home for the tsconfig-count update).

`ENGINE_META` covered seven of the eight Participant CLI ids, so an Agent
joined as `little-coder` fell through to the unknown-engine branch and the
Console presented a fully supported platform as unrecognized — the raw id
string with the neutral fallback badge.

The gap is invisible from the docs-facts guard, which compares generated
facts against the platform registry and never reads `web/`. Exporting
ENGINE_META lets a test pin its key set to PARTICIPANT_IDS, so the next
engine that lands in the shared vocabulary without a badge fails a test
instead of shipping.

Closes #59
FR-U20 requires that a Team launch from the Console be detached and that
attaching stay a terminal-only action. The launch route honored that through
the `noAttach` seam; the resume route could not, because `runTeamResume`'s
deps slice omitted `noAttach` entirely. The resumed plan carries the same
`attach: true` a terminal launch would, so `POST /api/team/resume` drove
`tmux attach` inside the headless `crew ui` server process — an HTTP request
reaching for a terminal the Operator is not sitting at.

Widening the slice is the whole fix: the Console passes `noAttach: true` like
its launch route, and the CLI omits it so `crew team resume` keeps its
plan-driven attach behavior unchanged. No route, requirement, or user-facing
capability changes.

The test fake now models two things the real panes already do — registering
on the configured client and re-joining an archived row with `--resume` — so
the resume happy path is reachable and the zero-attach assertion is real
rather than an artifact of an early failure.

Closes #50
…eset

ADR-0016 decided that crew's Relay delivers the Worker context reset, but its
Consequences put "the Relay delivery, the registry field, and their
requirements" in a follow-up change that has not landed: `clear_safe` reaches
no reset delivery in `src/relay.ts` or `src/launcher/`, and no platform record
carries a per-engine reset command.

The packaged Manager and Worker prompts asserted the unbuilt half as live, so
an Agent launched with a shipped Role waits for a reset that never arrives.
The ADR outranks the prompt, so the prompt text moves: both now say crew does
not deliver the reset yet and a human types it, while keeping ADR-0016's own
finding that a Worker cannot reset itself.

Closes #23
`e2e/ui/tsconfig.json` was referenced by no script and no workflow, and it did
not compile: alone among the repo's tsconfigs it set `lib: ["ES2023"]` with no
DOM lib and omitted `skipLibCheck`, so `tsc -p e2e/ui/tsconfig.json` failed
with 139 errors inside playwright-core's own declarations. Playwright
transpiles without type-checking, so the specs escaped the repo's otherwise
universal gate while the dangling config implied they were covered.

Wiring it into `typecheck` rather than the ui-e2e workflow keeps the gate
where every other project already is, so a type error surfaces per-PR instead
of in a nightly browser smoke. The added guard walks the repo for tsconfigs
and fails on any the script does not compile, so the next dangling project
cannot repeat this silently.

NOTE: `npm run typecheck` now runs FOUR tsconfig projects, not three.

Closes #24
Both comments claim an exactness they do not have, and both are the first
thing a reader of that module sees.

`src/ui/server.ts`'s header says the write surface is EXACTLY the FR-U19
action POSTs and then lists nine, omitting the `/api/agents/:id/archive` and
`/api/agents/:id/restore` routes that `isActionPath` admits and that mutate
Agent rows. Anyone auditing the write surface from the header would miss two
live routes. The neighbouring docstring already says "FR-U19/FR-U36", so the
header now matches it.

`src/format.ts` attributes `CREDENTIAL_KEY` to a "name-based env-guardrail
set" that no code implements — neither `doctor` nor `setup` reads a variable
for reporting. The comment now describes the constant as what it is, the
credential-word vocabulary of the keyed-pair redaction in free text (FR-J14),
and points the environment property at FR-J13, which actually governs it.

Comment-only: no route table, dispatch path, or behavior changes, so no test
changes are expected.

Closes #60
Closes #68
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment