Skip to content

Reads stop handling what the retired verbs wrote; colour fixes; accepted enquiries say why - #611

Merged
danbarua merged 7 commits into
mainfrom
read-side-retired-shapes
Oct 1, 2026
Merged

danbarua merged 7 commits into
mainfrom
read-side-retired-shapes

Conversation

@danbarua

@danbarua danbarua commented Oct 1, 2026

Copy link
Copy Markdown
Owner

The follow-up to #608, #609 and #610. Measured with the compiled binary (bun run cli:build) against throwaway records, always with --db. The "before" binary was built from main at e4250a4.

1. Reads stop handling shapes only the retired verbs wrote

For each shape, I grepped every staged write in packages/core-domain/write/*.ts (unitOfWork.node/edge). UnitOfWork.set and setEdge have no callers, so no live write sets any property, retracted included. None of the shapes below is produced by a live write:

shape written only by what went
review kind in why recordReview kept, see below. Removed: the ReviewRef alias and the minted reviewRef codec
sharpening arm of originAlready (Decision MOTIVATES Question + SHARPENS) sharpen the arm; originAlready now reads only the note
closed gate state (Decision CLOSES Gate) closeGate the state, GateStatus.closure, the closed lookups in gateStatus/gateList, the explainGate case, closed in GATE_STATES and in the why descriptions
undecided standing (GRADES) isUndecided the verdict, the standing, the GRADES lookup in standingsConferred, the view branch, the vocabulary word
retracted nodes undo every retracted IS NULL / retracted !== true filter in explain, happened, inventory, standing, core; everGated and the unlabelled ever match in workList; retractedIn and the retracting line in happened
revisedBy (Decision MOTIVATES/SUPERSEDES Computation) and the review behind it replaceAnalysis revisedBy, impliedSupersession, conclusionsOf, the BASED_ON-review edge in concluding; the Review match and because on analysisRevision; the Review lookups in whySupported (EVALUATES, BASED_ON Review, INVALIDATED_BY)

Not done: the review kind. search walks every searchable label in SEARCHABLE_TEXT (core-db/domain.ts) and refuses a label with no kind. Review is one of them. With the kind removed, every search failed:

$ labkit --db …/rec1 --no-ansi search seed
labkit: Review is searchable but names no research-concept kind
exit 1

Removing the kind needs one of two changes that this PR does not make: take Review out of the schema's searchable annotations, or make search skip a label with no kind (its comment says that case should fail loudly). The kind is back, and so is ", review" in the why descriptions.

Tests: the undecided view test and the undecided verdict case are gone; the workStateFrom test lost its retracted-gate case; tests/events/retraction.test.ts is gone, since it checked that reads hide retracted nodes. closed leaves the CLI vocabulary because tests/cli/vocabulary.test.ts failed once no schema could say it (+ "closed"). The enquiry list still prints closed, uncoloured.

The same reads over two records, before and after: the throwaway record (happened 52 lines, now 16 lines, why CLM_6 on a replaced claim) and the rebuilt Bonsai record (now 82 lines, claims 51, enquiries 29, work 11, gates 20). diff printed nothing for any of them. The one visible change is gates --state closed:

before: Gates — 0 / nothing (exit 0)
after:  labkit: Invalid option: expected one of "never-evaluated"|"incomplete"|"blocked"|"satisfied" (exit 1)

bun run bonsai:record with this binary:

107/107 criteria recorded
107/107 evaluations recorded, 57 citing a measurement
gate GATE_243, task TASK_135, enquiry LOE_134, 107 criteria/evaluations from experiments/stage2b_denoising/gates.toml
OK: the live event stream and graph state are exactly what the scripts produce, commit hashes and clocks aside.
OK: record built (…/bin/labkit --db …/tmp/bonsai), replay clean.

What nothing writes any more

Graph schema and migrations are unchanged. Declared: 14 node labels and 31 edge labels; written: 13 and 25.

  • Label: Review.
  • Edge labels: REVERIFIES, GRADES, KEEPS, SHARPENS, EVALUATES, INVALIDATED_BY.
  • Endpoint pairs on edges still written elsewhere: MOTIVATES Decision→Question, MOTIVATES Decision→Computation, SUPERSEDES Decision→Computation, CLOSES Decision→Gate, BASED_ON Decision→Review, GATES Gate→Computation, PRODUCES Task→Computation, PRODUCES Task→Artefact, and CONCERNS/MENTIONS Note→Review.
  • Properties: retracted (nothing calls UnitOfWork.set). ClaimProps.kind still allows "undecided". provisioning.ts still installs the <label>_hide_retracted RLS policy, and with retraction.test.ts gone no test exercises it.

Reads of these that were outside this brief and are still in place: reverifiedBy/REVERIFIES in whySupported and the "Re-checked by" view; the Computation lineage, KEEPS and the changed/restated/unpaired lists in analysisRevision, which now always return the empty shape; and the withdrawn-verdict helper in checks.ts.

2. labkit gates lines its columns up with colour on

rows() padded by string length, escape codes included. It now pads by visible width. The test renders renderGateList with colour on, strips the escape codes, and compares the result with the plain rendering. It failed before the fix:

- "blocked     GATE_1  no publication
+ "blocked              GATE_1  no publication

Compiled binary, FORCE_COLOR=1 labkit gates | strip-ansi:

before:                                     after:
never-evaluated      GATE_4  no publication   never-evaluated  GATE_4  no publication
holding up  TASK_3  write it up               holding up       TASK_3  write it up

3. The record daemon's log lines take the CLI's colour decision

colourWanted moves to packages/core-db/colour.ts, because core-db cannot import app-cli. stderrLine sits beside it and writes one line to stderr, in red when colourWanted says so. The daemon's log(), the wire host's two lines, the daemon entry's usage line, the client's "replacing it" line and the CLI's refusals all go through it. core-db has no access to --no-ansi, so the daemon decides from the environment alone. Bun colours console.error whenever FORCE_COLOR is set, even beside NO_COLOR=1:

$ echo 'console.error("x")' > ce.ts
$ NO_COLOR=1 bun ce.ts 2>&1 | od -c     # FORCE_COLOR=3 inherited from the shell
033 [ 0 m 033 [ 3 1 m x 033 [ 0 m \n

Daemon log, fresh --db each, under FORCE_COLOR=3 NO_COLOR=1:

before: ^[[0m^[[31m2026-10-01T00:30:39.226Z [labkit daemon 63989] serving …^[[0m
after:  2026-10-01T00:30:42.025Z [labkit daemon 64191] serving …

tests/persistence/daemon-log-colour.test.ts runs the daemon entry under FORCE_COLOR=1 (the control, which must be coloured), FORCE_COLOR=3 NO_COLOR=1 and FORCE_COLOR=0.

4. The --http launcher test clears the colour variables for its child

The child now gets process.env without FORCE_COLOR, NO_COLOR, CI and TERM, which are the variables colourWanted reads.

before: FORCE_COLOR=3 bun test packages/app-acp/http.test.ts
  Received: "http://127.0.0.1:55791/acp\u001B[0m"
  13 pass, 1 fail
after:  FORCE_COLOR=3 bun test packages/app-acp/http.test.ts
  14 pass, 0 fail

5. labkit why on an accepted enquiry prints the reason and the reopening condition

before:
LOE_1 is open — its question is accepted as unresolved because
  - (Q_1)  does the schedule move convergence? — currently accepted
after:
LOE_1 is open — its question is accepted as unresolved because
  - (Q_1)  does the schedule move convergence? — currently accepted
accepted because: the effect is below seed noise
reopens if: a run with ten seeds

The accept help text now points at labkit why and no longer at labkit --json why. tests/cli/enquiries.test.ts asserts both lines through the CLI.

6. The deleted root README

infra/ci/triggers.tf no longer lists README.md in ignored_files. infra/ci/README.md had the same list in prose, and it is updated too. No other file referred to the root README; every other README.md hit is a package README or test data.

Not in this PR: removing the MCP read-only mode

The coordinator also passed on a request to remove labkit mcp --read-only, the readOnly paths in app-mcp/server.ts and docs.ts with their tests, and the MCP_CALL_WRITE switch in the skill's mcp-call.sh. I made the change, and typecheck, the MCP tests (22 pass) and mcp-call.sh tools/list (9 tools, 4 with readOnlyHint) all passed. The permission system then refused the commit as test removal. The change is not in this branch. It is saved as a patch outside the repo for Dan to decide on.

Checks

  • bun test, before: 1644 pass, 2 skip, 1 fail (http.test.ts under this shell's FORCE_COLOR=3), 1647 tests across 221 files.
  • bun test, after: 1647 pass, 2 skip, 0 fail, 1649 tests across 221 files. The difference: +1 gates-colour test, +3 daemon-colour tests in a new file, −1 undecided view test, −1 retraction.test.ts (one test, one file).
  • bun run check:quick: all 25 passed.
  • Rebased onto origin/main (e4250a4) before pushing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY

danbarua and others added 7 commits October 1, 2026 01:24
FORCE_COLOR in the developer's shell made Bun colour the child's
stderr, and the endpoint read back carried an escape code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY
`rows()` padded each cell by its string length, escape codes included,
so a coloured `holding up` cell pushed the work handle out of the gate
handle's column. It pads by visible width now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY
…reopen it

Both were on `--json` only. The `accept` help text pointed there; it
points at plain `why` now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY
`colourWanted` moves to core-db, beside the daemon, with `stderrLine`
writing one line through it. The daemon's log, the wire host's two
lines, the daemon entry's usage line, the client's "replacing it" line
and the CLI's refusals all go through it rather than `console.error`,
which Bun colours whenever FORCE_COLOR is set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY
No live write produces any of these, so the code reading them is gone:

- the `closed` gate state and a gate's `closure` (`closeGate`);
- the `undecided` verdict and standing, and the GRADES lookup behind
  them;
- the `retracted` filters on reads, `retractedIn`, and the
  `retracting` line in `happened` (`undo`);
- `revisedBy`, the implied supersession that rested on it, and the
  BASED_ON a review it carried (`replaceAnalysis`);
- the review behind a revised analysis, a superseded finding and an
  invalidated artefact;
- the sharpening arm of the check for a question's origin (`sharpen`);
- the `ReviewRef` alias and the minted `reviewRef` codec.

The `review` kind stays: `search` walks every searchable label in the
schema, `Review` is one, and it refuses a label with no kind.

`closed` leaves the CLI vocabulary, since no schema can say it now.
The test that reads hid retracted nodes goes with the filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWZHuy7xJbVqxyLipnvwdY
@github-actions github-actions Bot added area:record The record: core-domain, core-db, the CLI, the MCP server, the domain model and workspaces area:agent The agent and its hosts: core-agent, app-acp, app-vscode, acp-fake, acp-scenarios, acp-transcripts labels Oct 1, 2026
@danbarua
danbarua enabled auto-merge (squash) October 1, 2026 00:52
@danbarua
danbarua merged commit eaeba66 into main Oct 1, 2026
10 checks passed
@danbarua
danbarua deleted the read-side-retired-shapes branch October 1, 2026 00:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent The agent and its hosts: core-agent, app-acp, app-vscode, acp-fake, acp-scenarios, acp-transcripts area:record The record: core-domain, core-db, the CLI, the MCP server, the domain model and workspaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant