Skip to content

P8: lazurio doctor — the Environment's state in one read-only answer, every check mapped from an existing reader (base-instructions-12) - #77

Merged
immakermatty merged 6 commits into
mainfrom
claude/DEV-6628-doctor
Sep 28, 2026
Merged

immakermatty merged 6 commits into
mainfrom
claude/DEV-6628-doctor

Conversation

@immakermatty

@immakermatty immakermatty commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Why

Slice P8 of the Launchpad parity program (#65 B9; C.2 step 4): the read-only preflight of the Machines switch and the operator's or agent's one-command view of an Environment's state. Until now that view was spread over update status, tools status, organization list, recover and the handover commands.

What changes

  • lazurio doctor [--folder <abs>] [--sign-in] [--json]: {kind: "doctor", verdict ok|attention|broken, locale, checks[{id, outcome ok|warn|fail|skipped, reason?, context?}]}; exit 0 / 10 / 3, usage 2. No check of its own — every answer is mapped from an existing reader: update state, self-check and Launchpad unit/health from collectRecovery; running vs active version, update available and Folder refresh from readStatus; Folder state, preset, Machine kind and template revision from observeFolder; the recorded binding vs the live handover (machine-identity-changed, handover-changed, binding-absent, handover-unreadable, never a digest); tools from the catalog tiers (required missing = fail, recommended/enabled missing = warn); every Organization and module from readFolderCatalog with its typed reason (unreadable Organization or non-executable module = warn); machine-entry recorded or not on a hosted preset.
  • Tier-1 discipline as recover: every context passes the recover allowlist plus doctor's own enumerated keys; no absolute path, no free text; names that are not identifier-shaped print as invalid.
  • Read-only, provably: a test asserts the whole temp tree is byte-identical after a run; the Folder read lock is taken only where the state is recognized (taking it elsewhere would create the lock directory).
  • Human output in the CLI table style, cs/en by the Folder's locale. Generated manual base-instructions-12: one bullet for lazurio doctor in the product-update section (hosted and workstation).
  • Docs: docs/launchpad-development.md "Doctor" (every check id with its source, the C.2 preflight).

What deliberately does NOT change

No update/recover/module core, no Launchpad server, no /settings/diagnostics page. Sign-in probes are opt-in (--sign-in) because they may contact providers.

Verified

Author of the slice: bun run check 907 pass. Thread owner's bun run check on 8b3273a: 907 pass, 0 fail, exit 0. Linux supervised paths covered only through recover's existing tests (no real systemd here).

Review round (Pablo 5341832065, head 8b3273a → e4b700e)

Risks / follow-ups

  • On a broken installation doctor reuses collectRecovery as-is, which also prepares recover's evidence and issue (read-only, thrown away) — a cost, not a defect.
  • Tools without a catalog tier (codex, git, node) are not judged.
  • docs/launchpad-parity.md row 30 still says "not implemented" (the table has no status column to edit consistently).

🤖 Generated with Claude Code

immakermatty and others added 4 commits September 28, 2026 18:21
…y check mapped from an existing reader (launchpad-parity B9, P8)

- src/doctor/doctor.ts: collectDoctor composes collectRecovery (update
  state, self-check, Folder state, unit, health socket), readStatus (running
  vs active, a verified newer release, Folder refresh needed), observeFolder
  (preset, template revision), the recorded Machine binding against the live
  handover (identity, then document digest; reason only, never a digest),
  toolsOverview under the Folder's read lock or toolsStatus without one, and
  readFolderCatalog (every Organization and module with its typed reason).
  No check of its own, no write, no network; sign-in probes only with
  --sign-in.
- One shape per check, {id, outcome ok|warn|fail|skipped, reason?,
  context?}: enumerated ids and reasons, and a context allowlist that
  extends recover's tier 1 (catalog names only in identifier form, else
  `invalid`). Verdict ok|attention|broken; exit 0, 10, 3, usage 2.
- src/doctor/cli.ts: lazurio doctor [--folder] [--sign-in] [--json]; the
  human form groups the checks in the catalog's column style (control
  characters escaped), Czech or English by the Folder's locale. The
  catalog's columns() is exported for it.
- tests/doctor.test.ts: healthy fixture ok with nothing written, pending
  transaction broken, missing required and recommended tools, a module not
  executable, the hosted binding against a rewritten or foreign handover,
  Recovery mode on the health socket, update available in Czech, usage, and
  the real command line; JSON checked against the tier-1 rules and the human
  rows against the JSON.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… product update section (base-instructions-12)

One bullet, the same on a hosted Machine and a workstation, after
`lazurio update status`: doctor shows the Environment's state read-only
(product, Folder, tools, Organizations and modules, Launchpad) and changes
nothing. The template revision becomes base-instructions-12 and the
snapshots are regenerated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…th its source, the tier-1 answer and the C.2 preflight

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Taking the operation lock of a state without `.operation-lock` creates the
lock directory, a write. Doctor now reads the tool selection under the lock
only when recover's Folder check is ok; otherwise it reads the catalog's
tiers with the selection the Folder recorded, without a lock, as
observeFolder does. A test removes the lock directory and finds the tree
unchanged after doctor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@immakermatty — exact-head review of 8b3273a (P8). REQUEST_CHANGES; do not merge.

  1. [P1] --json leaks free text through a tool version (src/doctor/doctor.ts:204-206, src/doctor/doctor.ts:417-436). The Tier-1 validator allows an arbitrary 40-character alphanumeric prerelease/build suffix, and toolsStatus extracts it from tool stdout. In a disposable fixture with a Folder named folderincidentorchid and fake gh --version output gh version 2.63.0-versionincidentorchid, the CLI returns tool.context.toolVersion: "2.63.0-versionincidentorchid"; the Folder marker itself does not appear. This directly breaks the stated no-free-text JSON contract. Keep only a bounded product-defined version form (e.g. numeric segments or explicitly enumerated prerelease types), or omit an unrecognized tool version, and add a regression that probes both Folder name and tool output.

  2. [P2] The read-only assertion does not prove byte identity (tests/doctor.test.ts:285-309). tree() records only path, size and mtime; overwriting a file with different same-length bytes while retaining mtime still passes. Hash/compare file contents (and symlink targets as appropriate) before/after healthy and unrecognized-state runs. The unrecognized lock-directory regression currently passes; this is an evidence gap, not an observed write.

Evidence: isolated detached clone at the named SHA; bun --smol test tests/doctor.test.ts 10 pass; manual/render/tools snapshot shard 57 pass, 37 snapshots; lint/typecheck pass; git diff --check clean. Both required CI jobs (check (ubuntu-24.04), check (macos-14)) succeeded on this SHA, and no unresolved review threads were present. The existing reader mappings and base-instructions-12 snapshots were traced; the current human table is projected from the same result, though its parity test checks only selected fields rather than every context value. No merge performed.

immakermatty and others added 2 commits September 28, 2026 18:45
…ad-only proof compares file bytes and link targets (review 5341832065)

- [P1] toolVersion admitted a 40-character suffix, so a version line such
  as `gh version 2.63.0-versionincidentorchid` carried free text into
  --json. The rule is now `^[0-9]{1,6}(\.[0-9]{1,6}){0,3}$`; anything else
  is dropped from the context and the check keeps its outcome. A regression
  test puts the marker in the Folder's name, an Organization directory and
  both tools' version lines and finds it in neither output.
- [P2] tree() records mode, size and modification time of every entry, the
  SHA-256 of every file's bytes and every link's target (lstat), so the
  before/after comparison of the healthy, pending and unrecognized-state
  runs proves byte identity.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@immakermatty — APPROVED on exact head e4b700e (base main after #79); do not merge in this review lane.

Both blockers from review 5341832065 are fixed. The tool-version context now admits bounded numeric segments only and omits suffixes. I repeated the version-line probe: gh 2.63.0-versionincidentorchid and composio 0.7.1+incidentorchid are extracted but omitted from public context, while plain gh 2.63.0 is retained. The end-to-end regression plants incidentorchid in the Folder name, Organization directory and both version outputs; neither --json nor human text leaks it. The read-only tree comparison now includes SHA-256 of file bytes and symlink targets, and passes for healthy, pending and unrecognized state.

Isolated detached clone at this SHA: doctor tests 11 pass (including the version-line probe); folder manual/render/tools 57 pass and 37 snapshots; lint and typecheck pass; git diff --check clean. Required macOS 14 and Ubuntu 24.04 check runs are completed/success on this exact SHA. Final live preflight: mergeable, zero unresolved threads, no pending reviewer requests. No merge performed.

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.

2 participants