Skip to content

Batch: terminal, Git, worktree, update guard, Share this host and crash fixes (#348, #351 to #358, #360 to #362, #366) - #365

Merged
mubeda merged 136 commits into
mainfrom
claude/open-issues-pr-dc3c33
Nov 14, 2026
Merged

mubeda merged 136 commits into
mainfrom
claude/open-issues-pr-dc3c33

Conversation

@mubeda

@mubeda mubeda commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

What this changes

One batch of fixes for the issues that were open on 2026-11-13, planned in docs/plans/2026-11-13-issue-batch-348-358/ (triage, evidence, spec, plan, phases, progress log, reviews). Every item of every issue was checked against the code first and got one disposition: fixed with a test that failed first, decided by a recorded test or probe, or recorded as a limit in code or docs.

Issue Change
#348 A terminal re-measures and repaints after a font loads late, and one created after the server's settings arrived repaints once the bundled font is in. A development-only record of size decisions holds no terminal content.
#351 Expanding a reasoning row that the reader scrolled to no longer pulls the chat to its end.
#352 The removal drain test waits on its condition instead of a 2-second bound.
#353 Other AppImage mounts are hidden from Host dashboard volumes; the packaged e2e harness recovers from a dead webview before every test; a re-attach no longer sends a transient terminal size; Fit says when the server kept the size; the Host dashboard's values view no longer redraws on the clock tick; terminals count widths by Unicode 11.
#354 Sign-in guidance appears only for Git's own fatal: line; the pull and hook limits of the index-lock cleanup are recorded; two doc entries added.
#355 Pull-request lookups end at quiesce, a failed lookup waits 5 seconds, a remembered pull request is cleared by a failed lookup on data older than 5 minutes, and a status-neutral local change that outdates a running lookup triggers a new one.
#356 Worktree creation records are deleted by id, both creation-rollback arms reach the profiler audit, and a record under a missing parent directory (an unmounted volume) is kept.
#357 The unsaved-edits block around a remote update install survives a reload, covers a Files source opened during the install, and never ends on a failed state query; the installing dialog has Check again; "Manage devices" is switched off while the install runs.
#358 A popup hides a macOS native preview only where they overlap; a dedicated terminalSizeHandOver capability; a new terminal retries WebGL; refused pairings are logged at warn with a fixed class; the model picker reopens empty; the read-only Markdown view loads relative images from the workspace.
#360 The app no longer falls to "Something went wrong" (React error 185) when a closed branch picker or model picker receives a new list. With the Profiler on, an error the error screen catches is recorded as client.render-error.
#361 Share this host lists this computer's private addresses while remote access is still local-only. On Windows without administrator rights, BiBCode asks through the Windows permission prompt for its firewall rule, or says what is missing and offers Retry. BiBCode no longer manages Tailscale Serve.
#366 Timestamps sent by the web client and those of imported sessions are re-written in the server's nine-digit form before they are stored, so they sort correctly beside server rows. Only the known timestamp fields of each command are touched; answers, tool data and message text stay as sent (follow-up of #362, filed and fixed here).
#362 An expired pairing link, pairing offer or session is refused from the moment it expires, and the OAuth cleanup no longer deletes a refresh token up to a second early. Every timestamp the server stores and compares as text is now written by one function at a fixed width of nine fraction digits (found here, filed and fixed here).

#350 (a server-side terminal screen) was closed as not planned by the owner. Its design, three design reviews and the results of a serializer proof are kept in docs/plans/2026-11-13-terminal-screen-350/.

Diagnoses worth reading

  • Windows: expanding a reasoning row scrolls the chat list to its end #351. A trace from the Windows VM ruled out the three paths first suspected. The scroll came from the live-follow of a still-streaming thought, about 150 ms after the toggle: a scroll away from the end that no gesture made never switched "follow the end" off. It is a timing condition, not a Windows one.
  • Git Manager: app crashes with React #185 after switching branch and fetching in a large repo #360. Reproduced with the real list library and the real popover: open the branch picker, close it, replace the refs. It fails at 1,400 branches and passes at 1,200. The library recorded a 0 by 0 rectangle of a hidden row as its size; with hidden rows measuring 30 px the same test passes at 4,000. The model picker fails the same way at 50 models. The guard is in both bundle formats of the patched library, and the branch list is rendered only while its picker is open or closing.
  • Auth: an expired pairing link or session can be accepted for up to a second after it expires #362. A pairing-refusal test failed once under load. It was not the test: expiry times were stored as ISO text with trailing zeros dropped and compared as text, so a whole-second time sorted after times up to a second later. Before the fix an already-expired pairing was accepted in 21 of 200 runs under load; after it, 0 of 200. The last review found the same form in about ten more writers (the OAuth cleanup, retention cutoffs, the orchestration clock). A first fix at millisecond width made two events in one millisecond tie, which a review caught (the wrong latest assistant message; a skipped check after a compaction), so the final form keeps nanoseconds at a fixed width.
  • Follow-ups from the #349 validation rounds #353 (terminal size transient). The test recorded two size claims on re-attach (85x33, then 85x30). A re-measured font, a pixel-ratio change and the bundled-font load now wait for the layout to settle.

Decisions by the owner

Agent's calls recorded in the spec for the owner to confirm: "Manage devices" is disabled during an install instead of being shown above the installing dialog; a failed lookup's 5-second backoff and the 5-minute rule for a remembered pull request; a creation record is reaped only when its parent directory exists; pull stays out of the index-lock cleanup list; tooltips take no preview lease.

Limits, stated plainly

Validation

Where What Result
macOS (dev host), final head vp check --no-fmt, vp check on every changed file, vp run typecheck, vp run check:contracts, vp run check:markdown-links, cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings exit 0
macOS web unit suite 788 files, 11,709 passed, 24 skipped
macOS contracts, shared, client-runtime, desktop package, scripts 937; 844; 1,312; 164; 942 passed
macOS cargo test -p bibcode-server; cargo test -p bibcode-desktop 7,387 passed, 0 failed; 560 passed (before the last timestamp commits and the merge of main); both exit 0 with no failed test on the final head
macOS removal drain test alone under CPU load 50 of 50
macOS pairing expiry, before and after the fix, under CPU load 21 of 200 failed before; 0 of 200 after
Linux (Docker lab, Ubuntu 22.04, WebKitGTK, xvfb), Profiler on packaged default list 37 passed, 0 failed, 4 skipped (macOS-only cases), on three builds of this branch
Linux web process killed during a test (four runs) no hook error; app relaunched once; next test started about 5 s later
Linux reload during an allowed install block and dialog restored
Windows 11 arm64 (VM) removal drain test in 12 whole-suite runs 12 of 12
Windows packaged chat-reasoning-rows on the fix 3 of 3 (1014 px of movement before the fix)
Windows build, Clippy, vp check --no-fmt, desktop tests, firewall argument probe (at the commit before the timestamp widening and the merge of main) exit 0; 471 desktop tests passed; probe passed with no prompt. One whole-suite server run: 6,296 passed, 1 failed (a load test's websocket aborted by Windows, not touched here)
Windows profiler audit test, 30 runs 30 of 30 (it failed 3 of 12 whole-suite runs before its fixed 1-second wait was replaced)
Released server current client against v0.15.3 (checksum verified): capabilities, keybindings, attach, resize legacy path, no error

Two more tests that depended on timing were fixed along the way, without product changes: the profiler worktree audit test (a fixed 1-second wait) and a GitLab poller test (a paused clock moved while a child process was still running; 24 of 160 failed under load before, 0 of 160 after).

Whole-suite runs on Windows at an earlier commit also failed tests this branch does not touch, on a VM sharing the host with other builds: two Git index-lock tests (background_status_does_not_break_a_concurrent_git_add and its linked-worktree variant) and shutdown or single-flight timeouts. On macOS two script tests with a 5-second limit (ci-platform-contract.test.ts, bibcode-identity.test.ts) timed out inside a loaded full run and passed alone. Neither is changed here. On Windows, whole-tree vp check reported formatting in files under docs/plans only, which pass on macOS; CI decides.

Reviews: the plan had two Codex reviews (22 and 13 findings, all handled); the code had Codex reviews of the whole branch and of each later addition, with every finding verified against the code and fixed or rejected with a reason in the plan log.

Profiler: on for every packaged run. No finding caused by this change. Pre-existing on the labs: client.stall and one cpu.sustained on the web process under software rendering, and rpc.slow for Git ref listing and partial staging on the Windows VM. Profiler coverage of the change: a new quiesce step pull-request-lookups (timed by the existing step marks); a new worktree.removal mode create-rollback; a new client event and finding client.render-error through the existing client batch, redacted on both sides; new warn logs carry fixed classes and never a credential, URL or path; the Tailscale status read reports its exit.

React and UI.md: changed components and hooks were reviewed against vercel-react-best-practices, and changed screens, dialogs and messages against UI.md.

Runbooks: docs/testing/cross-platform-validation.md and windows-desktop.md were updated; linux-desktop.md and macos-desktop.md were reviewed and remain accurate.

Closes #348, closes #351, closes #352, closes #353, closes #354, closes #355, closes #356, closes #357, closes #358, closes #360, closes #361, closes #362, closes #366.

🤖 Generated with Claude Code

mubeda and others added 30 commits November 13, 2026 07:59
…to #358

Draft plan for nine issues (9 phases, 47 tasks) with its first Codex
review, and the #350 design in its own folder with the review that
returned it for rework.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Records how the 13 findings of round 2 were handled, and the state of
the #350 design rework.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
A native surface now hides only when a lease's rectangle overlaps it;
a lease without a rectangle still hides every surface.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…tall (#357)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erlaps it (#358)

Popover, Menu, Select, Combobox and Autocomplete lease their positioner's
rectangle while it carries data-open and follow it frame by frame; a
kept-mounted closed popup holds no lease. Tooltips take none; dialogs keep
their full lease.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…ading (#348)

A late font changes xterm's cell without changing the mount box, so the
ResizeObserver stays silent and the fit addon proposes from the cached cell
size. The mount observer now listens for document.fonts loadingdone,
re-measures the cell and runs the usual layout and repaint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a failed state query from an answer (#357)

A sessionStorage marker restores the block when the window loads; only a confirmed
state with no remote requester clears it. The bridge's getUpdateState now rejects on
a native failure and falls back only when the desktop lacks the command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…loads (#348)

The font effect ran only on a font or visibility change, so a renderer created
later (an AI terminal waiting for host config) was never repainted after the
bundled font loaded. It now re-runs for each committed renderer epoch and
re-measures the cell before the layout and repaint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ery deadline (#353)

The shared specs run in one worker, so the probe in `before` ran once for
all of them. `beforeTest` now probes first, and the probe, stop, relaunch,
session reload and mock restore share one 100 s deadline inside the 120 s
test allowance. Failure evidence in `afterTest` tolerates a dead webview so
the worker's later tests still reach their probe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The popover keeps its content mounted while closed, so the search typed
before survived. Key the content by opening, counted on every closed-to-open
change of the open state, so the trigger, the composer shortcut and the
controlled prop all start a fresh search.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
… it when no remote install runs (#357)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he bridge only (#357)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cisions (#348)

A ring of the last 200 sizing and repaint decisions (trigger, generation,
mount box, fitted and applied grid, role, pixel ratio, font status, renderer,
request and outcome, repaint), off by default and enabled only in development
from window.__bibcodeTerminalSizeDiagnostics. It records no ids and nothing
written to the terminal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r the installing dialog (#357)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… nothing (#348)

A second press after the server declined the claim sent nothing and showed
nothing. The size notice now adds "The server kept this size." in its
existing status region until the applied size changes or a claim is sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the workspace (#358)

The read-only rendered view now passes the file's path to ChatMarkdown,
whose image renders through the rich editor's loader when a path, a thread
and a workspace are known, so a relative image is read from the workspace
and a path that leaves it is refused. Chat messages pass no path and keep
a plain image.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ending Check again on a push (#357)

A completed install clears the requester while the phase stays installing until the
restart, so only a cleared requester outside protecting and installing ends the block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the app cannot be reached (#357)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…353)

The 1 s tick rebuilt `values` with a fresh object each time, so the
values view rendered three times across three ticks with an unchanged
reading. Compare its props by content and keep it memoized; a changed
reading or uptime text still renders it.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…353)

Another running instance's image, or a stale one a killed instance left, was
shown as a full read-only volume because the `.mount_` marker also required
this process's executable under the mount. The marker now stands alone; the
file-system-name marker still needs the executable. The two assertions of
the_running_app_image_mount_is_hidden_before_it_is_read that pinned the old
behavior are rewritten on purpose.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fixed class (#358)

A refused pairing offer logged its reason at debug, and a refused pairing
credential logged nothing, so a one-off "Invalid pairing token" left no
trace. The offer refusal is now a warn with its trace id and fixed reason.
consume_grant logs each refusal once at warn with a fixed class (empty,
unknown, revoked, already_used, expired, proof_key_mismatch,
desktop_bootstrap_expired, unclassified). The persisted store names the
class with one read of the kept row on the refusal path only. Nothing that
identifies the credential, link, device or address is logged, and the HTTP
responses are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…und (#353)

The removal test bounded the whole removal (plan, Git, SQLite) with a
2 s timeout, so a loaded machine failed it before the drain. It now waits
on the drain having been entered and on the removal's result, with 30 s
guards only a real hang reaches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…exists

A missing parent cannot be told apart from an unmounted volume, so the
audit now keeps the record, both when it reads the records and when it
re-checks before the reap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mubeda and others added 18 commits November 13, 2026 14:29
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
)

The Tailscale HTTPS switch, its setup and disable dialogs, the stored
Serve preference and the desktop command that changed it are gone. The
command stays registered and answers the unsupported payload; stored
keys are ignored. A MagicDNS HTTPS address is listed only when a Serve
set up outside BiBCode already answers BiBCode's well-known endpoint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and explain an address read failure (#361)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…TTPS default, and say what a locked failure restarts (#361)

A rule is ours only when it names this program or reads as it did when
this process added it. The default address is chosen once over every
listed address. An unanswered legacy MagicDNS endpoint and an empty
This environment section are not shown. A firewall failure under the
lock avoids the wide restart; recovery still restarts local-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tecture contract test (#361)

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…r is time order (#358)

The store compares RFC 3339 text (`expires_at > ?`), but format_iso trimmed
the fraction, so `…:00Z` sorted after `…:00.001Z`. A pairing link, session or
offer whose expiry fell on a trimmed fraction stayed valid for up to a second
after it expired. That is why the persisted refusal test accepted its -1 ms
link about one run in ten under load. format_iso now always writes three
fraction digits, which still parses as RFC 3339. The refusal assertion now
prints what it got, and two tests pin the order and the refusal one
millisecond after expiry with explicit timestamps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…on fails

The Windows VM sees a third finding at the interrupted-removal count now
and then. The count assertions now print each finding's id, severity,
count and summary (mode and reason token, never a path).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… s sleep

The test slept 1 s and assumed the removal plan had finished. A slow plan
(the Windows VM) saw the interrupt itself and raised a repository-mismatch
finding. The test now waits on the drain-entered signal, which the removal
services expose to integration tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t test diagnosis

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
gitlab_poller_auth_failure_ends_every_subscriber_and_deletes_host_rows
jumped the paused clock 10 s every 200 real steps. Under load the git
scope read (10 s budget) or the glab tick probe (5 s) was still running,
so its deadline fired and the subscription ended with timeout instead
of not_authenticated. The clock now moves only after both subscribers
joined and no tick is in flight, under a 60 s real-time guard.
Reproduced 24 of 160 runs under load; 0 of 160 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l gates

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…lisecond width (#362)

SQLite compares these timestamps as text, and the time crate's Rfc3339
trims the fraction, so `…:00Z` sorts after `…:00.001Z`. Beyond the pairing
path fixed earlier, the OAuth cleanup could delete a live session's refresh
token up to a second early, and the server's now-helpers fed the same
variable-width text into expiry, retention and pruning cutoffs, MAX() of
last activity, and created_at keysets and ORDER BY, beside fixed-width
strftime and client values. One formatter, persistence::format_timestamp,
now writes RFC 3339 UTC with exactly three fraction digits (SQLite's %f and
toISOString form). auth::format_iso, the repositories' cleanup and every
SQL-bound now-helper call it. Values from now_utc lose their
sub-millisecond part; epoch-millisecond values parse unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-dc3c33

# Conflicts:
#	tools/objc-exception-probe/src/firewall_argv_echo.rs
#362)

Three fraction digits tied rows written within one millisecond, where the
older trimmed text almost never did: a turn's later assistant message with
the lower id lost to the earlier one, a turn starting in the compaction's
millisecond failed the strict `>` and skipped the guard, and a 3-digit
cutoff could delete a longer row under a millisecond early. The store form
is now RFC 3339 UTC with exactly nine fraction digits: clock values keep
their nanoseconds, epoch-millisecond values are zero-padded, and every
server-written operand shares one width. The compaction query moves to a
named constant so a test can run it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l gates

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-14T00:19:22.489555Z 1724fac PR opened
🔒 Security Review ✅ Completed 2026-11-14T00:25:40.238746Z 1724fac PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Nov 14, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1724face0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src-tauri/src/firewall.rs Resolved
mubeda and others added 4 commits November 13, 2026 23:14
… admits this program (#361)

A rule that was disabled or changed to block still names the program in the
netsh listing, so it was kept and an offer was made while inbound stayed
blocked. Before keeping a rule, read its stored fields with reg.exe query:
enabled, allow, inbound and this path. The fields are fixed tokens, unlike the
localized listing, and a standard user can read them. Otherwise the rule is
replaced as a rule for another path is. An unreadable store keeps the
listing's word and logs a warning.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…r's one form (#366)

A client writes toISOString's three fraction digits, and the store compares
timestamps as text at nine, so a client message or turn sorted after a
server row of the same millisecond. The public command decoder now re-writes
every client createdAt, updatedAt, completedAt and implementedAt that parses
as RFC 3339 in the store form before the command is decoded; text that does
not parse is kept and stored as sent, as before. Imported agent-session
times use the same shared formatter instead of their own three-digit one.
This also covers the compaction guard's requested_at fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
)

The client timestamp rewrite walked the whole command JSON and changed any
key named createdAt, updatedAt, completedAt or implementedAt, so a user's
answer to a question whose id is createdAt reached the provider re-written.
It now touches only explicit paths: those four fields at the command's root,
and per command type bootstrap.createThread.createdAt (thread.turn.start),
messages[*].createdAt (thread.history.import), proposedPlan.createdAt,
updatedAt and implementedAt (thread.proposed-plan.upsert), activity.createdAt
(thread.activity.append) and session.updatedAt (thread.session.set).
Answers, tool payloads, provider data and message text stay byte for byte.
The payload digest is still taken from the bytes as sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@mubeda mubeda changed the title Batch: terminal, Git, worktree, update guard, Share this host and crash fixes (#348, #351 to #358, #360 to #362) Batch: terminal, Git, worktree, update guard, Share this host and crash fixes (#348, #351 to #358, #360 to #362, #366) Nov 14, 2026
@mubeda
mubeda merged commit 1e731a2 into main Nov 14, 2026
26 checks passed
@mubeda
mubeda deleted the claude/open-issues-pr-dc3c33 branch November 14, 2026 10:45
mubeda added a commit that referenced this pull request Nov 14, 2026
Bump every version source to 0.16.0 and turn the Unreleased CHANGELOG
section (PRs #349, #359, #365 and #369) into the v0.16.0 entry. Raise
the Claude Code additive-hook ceiling to 2.1.323 after the live
PreToolUse guard proof passed on that build, and move the above-ceiling
test example to 2.1.324. Give the CI Test lookup contract test a
30-second limit: it runs bash and jq eleven times and timed out against the
5-second default under load.

Verified locally: cargo check for the workspace, vp check, vp run
typecheck, the full vp run -r --concurrency-limit 1 test graph in all
nine packages, release:smoke, the updater regression sets, cargo test
-p bibcode-desktop, and the macOS arm64 DMG signature and Finder icon
check. CI: the Seeded Packaged Desktop Upgrade workflow from v0.8.0
passed on all seven lanes for this branch (macOS x64 on a rerun after
its hosted runner lost its connection). Reviewed by Codex with no
findings.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment