Mesh pins of hosts gone before page load are never pruned #258
Open
opened 2026-10-29 18:10:40 +00:00 by kayg
·
150 comments
No Branch/Tag specified
main
j470b-server-mesh-rejoin
mesh-compat-382
j444b-d381-key-wins-flood
j461b-macos-utun-reader-thread
j475b-remove-host-motion
fix-reconnect-new-link
j481-d380
dev
j479-mesh-soak
fix/j476-host-facts
j475-motion-pill-split
j470-mac-node-join
root-upgrade-d376
j474-review-merge
latency-targets-120hz
nightly-suite-shards
gotatun-pin-j469
macos-utun-reader-thread
fix-flood-echo-stall
wip/j416
motion-fast-ease-out
mesh-addhost-j259
takeover-close-terminals-d368
kbd-instant-followups
fix-trust-key-double-click
nightly-suite-partial-report
appwin-icons-j207
rusqlite-slice1
swipe-content-first-d374
mesh-mtu-381
addhost-instant-open
glass-contrast-d365-mock
glass-contrast-d365
signout-followups-442
fix-startup-toast-red
research-gotatun-matrix-j317
themes-sync-j304
fix-load-flakes
fix-nix-zig-patch
fix-compute01-browser-baseline
ratchet-size-baseline-419
predict-auto-d130
revoke-coverage-d367
nightly-suite-queue-timeout
nightly-browser-suite
fix-rustsec-2026-0459
fonts-ioskeley-obel
log-retention-d375
fix-kbd-no-anim-427
fix-dev-red-specs-2
takeover-proof-305-j205
wip/j410-server-pump
ui-consistency-d372
fix-osc52-clipboard
libghostty-vt-1.0
forget-retired-host-d369
j404-merge-426
fix-setup-lock-race
fix-touch-select-426
revoke-access-report-ui
fix-predictive-echo-specs
fix-selinux-agent-exec
wip/j395-checkpoint2
wip/j395
j391-review-scratch
ui-consistency-j195-deferred-rebased
fix-rustc-paths-421
decisions-wording-341
fix-install-suite-red
fix-dev-rtt-specs
fix-pending-removal-align
fix-privileged-skip
fix-install-suite-404
review-j368
mesh-dns-j254
revoke-access-report-d356b
revoke-privilege-round5
fix-removal-confirm
review-j360
gotatun-rotation-367
deps-refresh-340
review-j354
review-J351
review-j350
addhost-takeover-d359
revoke-report-items-347
revoke-end-sessions-d362
review-j348
size-mesh-ssh-346
size-trim-337
revoke-access-diff-d356
j259-pre-rebase-b06c5a6
j305-ended-at-start-spec
addhost-sudo-consent
fix-layout-real-specs-411
fix-shell-open-411
fix-console-hosts-373
fix-shell-exit
fuzz-host-name-353
fix-host-details-410
macos-filter-j197
research-gotatun-tricks
revoke-p3-j216l
stale-state-pill
revoke-followups-j216k
revoke-progress-j216e
backup/macos01-20261106/lume/j197
backup/macos01-20261106/lume/appwin-icons-j207-stash0
backup/macos01-20261106/claude/stash-0
backup/macos01-20261106/claude/stash-1
backup/macos01-20261106/claude/J80-macos-s1
backup/macos01-20261106/claude/J80
backup/macos01-20261106/claude/J80-slice1-20261102
backup/macos01-20261106/claude/J16b-appwin-on-dev
backup/macos01-20261106/claude/appwin-launch-idle-146
backup/macos01-20261106/claude/J80-s1-run
wip/j259
trust-285-p3c
runtime-lock-j216f
mesh-ssh-p3-j175
tun-proof-p3b
trust-285-p3
terminal-polish-j271
tun-proof-p3
ssh-install-flakes-j216i
fuzz-fixes-j264
trust-285-a
trust-285-b
restart-oversized-fixture-j198
backup/macos01-20261106/lume/appwin-icons-j207
restart-bound-j216h
up-preflight-p3-j198
backup/macos01-20261106/lume/j251
up-preflight-j198
wip/up-preflight-j198-j245-p2
wip/up-preflight-j198-j245-p1
agent-fsync-offloop-j196
wip/up-preflight-j198-j245
settings-offscreen-j231
wip/up-preflight-j198-j226-inspection
wip/j103f
themes-j206
wip/up-preflight-j198-j226
flakes-j216c
backup/macos01-20261106/claude/j197
flakes-j216b
backup/macos01-20261106/claude/j197-red
wip/up-preflight-j198-review
flakes-j216
backup/macos01-20261106/claude/appwin-icons-j207
engineering-j208b
appwin-mock-j209
toast-stack-j165
engineering-j208
decisions-d351
decisions-d350
decisions-d349
appearance-presets-mock-j129
decisions-d348
docs-audit-spec
doc-coverage-baseline-raise
decisions-d347
decisions-d346b
decisions-d346
j88h-profile
ui-consistency-j195-deferred
ui-consistency-j195
engineering-practices-j194
preferred-login-ui-j166
signin-pools-263-j174
macos-node-265-s1
decisions-d345
decisions-d344
proxy-cgroup-j164
verify-quick-fuzz-329
proxy-start-io-j168
timing-flakes-j163
up-263-s1
mcp-events-j147
verify-quick-fuzz-j158
proxy-p3-j159
agent-resource-j157-detect
wip/j103d-final
remote-cancel-hang-j155
proxy-traefik-281-j62d
j149-verify-quick
proxy-traefik-281-j62b
j150-drop-unnamed
wip/j79d-red-r4
wip/j103d-d332
rootless-toast-j142
wip/j103d-head
wip/j103d
j125c-mcp
macos-build-j136
backup/macos01-20261106/claude/j136
wip/j79d-red-cli
wip/j79d-red-server
j121-link-liveness
j118c-tracer-failures
wip/j79c-head
release-desktop-j131
j124c-signed-macos
wip/j79c-red-p3
wip/j79c-red-p23
wip/j79c-red-p22
merge-j128-check
perf-deferred-j128
sidebar-toggle-260
j127-shortcut-changed-dot
j125-mcp
j118-tracer-failures
j126-account-summary
settings-sections-mock-j92
j120-pinch-lock
sidebar-292
backup/macos01-20261106/claude/j120
taste-2026-11-03
row-actions-242-215
backup/macos01-20261106/claude/stash-0-untracked
backup/macos01-20261106/claude/J80-265-s1-run
backup/macos01-20261106/claude/J80-macos-s1-20261102
j112-canvas-commands
ui-no-overshoot-scroll
fix-recovery-restart
backup/macos01-20261106/claude/stash-1-untracked
taste-2026-11-02
size-baseline-ratchet
machine-cards-structure-j108
j109-boot-copy-mockups
fix-dev-red
wip/up-263-s1
j95b-settings-rows
proxy-traefik-281
j95-option-rows
docs-human-j91
docs-keys-palette
fix-flood-1013-270-j38d
mesh-ssh-s1
mesh-ssh-s0
addhost-d291-tunnel
test-stability-load
mesh-relay-220
repro-296
shim-thp-off-24
mesh-pins-258-v2
mesh-dns
signin-d311-merged
docs-pages
ui-size-283
fix-ui-batch-specs
wip/j12b-edge-update
gate-on-arm
fix-rename-sync-293
trust-285-j60b
fix-focus-ring-clip
integ-ui-1101
edge-update-v2
signin-d311
taste-2026-11-01
layout-per-tab-250
ui-approved-splitopt-224
ui-approved-splitopt-224-on-dev
icon-text-centre-282
ui-approved-189-212-216
research-reverse-proxy
transfer-budget-320
review-mesh-pins-258-r2
sidebar-pill-259
review-mesh-relay-220
wip/j12-edge-update-v2
nix-package
status-crash-loop-237
fix-dev-test-failures
fix-fixture-socket-path
wip/mesh-relay-220-pre-dev-advance-rebase
fix-canvas-side-clip
research-head-to-head
frosted-real-256
review-mesh-pins-258
wip/mesh-relay-220-pre-final-rebase
review-layout-per-tab-250-r2
broad-suite-triage
nix-devshell
review-status-crash-loop-237-r3
wip/nix-devshell-pre-p3
taste-frosted-real
wip/code-serve-demo-2026-10-30
wip/code-serve-glass-2026-10-30
wip/code-serve-clusters-2026-10-30
wip/code-merge-release94-dev-2026-10-30
wip/rproxy-delta-scratch-2026-10-30
wip/stale-note-257-staged-2026-10-30
wip/d241-size-staged-2026-10-30
review-broad-suite-207
wip/mesh-pins-258-pre-split
wip/mesh-relay-220-pre-rebase
mesh-measure-220
plan-211-update
review-edge-autoupdate-r3
perf24-reconnect
review-stale-note-r2
release-prod-live
d241-shell-marker
review-mesh-pins-server-258
review-revocation-r3
review-setup-token-r2
review-sync-journal-r3
wip/review-mesh-pins-258-prune-review-1995fee46
frosted-scroll-256
sync-journal-r3
revocation-per-account-wip
review-tokio-asyncfd-0386
review-sync-p3s
wip/stash-8by64-stash0-2026-10-30
mesh-drag-r2
setup-token-data-wip
release-9-4
auth-busy-1013
mesh-view-overlap
sync-p3s
review-auth-busy-wake
review-readd-r8-wip
mesh-drag-bounds
audit-auth-93
app-windows-stream-start
review-authority-cap-r3
app-windows-r7-measure
readd-minimal-r6
readd-minimal-r5
app-windows-r7-soak
readd-minimal-r4
app-windows-r7
app-windows-r6
readd-minimal-r3
readd-minimal-r2
readd-minimal
merge-release8-dev
review-busy-page-liveness-r2
review-busy-page-liveness
mesh-view-trim
review-authority-read-retry-r2
review-remove-uninstall-r2
release-retry-reattach
release-retry
review-remove-uninstall
review-authority-read-retry
app-windows-ship
mesh-autoswitch-p2
mesh-ssh
mesh-relay
mesh-macos-node
screen-and-control
session-labels
review-real-logins-r5
review-real-logins-r4
review-real-logins-r3
shim-memory-r2
review-real-logins-r2
shim-memory
shadow-addhost-instant
shadow-real-logins
shadow-same-session-flood
shadow-prod-perf-fix
hosts-from-server
app-windows-real
app-windows-transport
release-prod-6w
mesh-policy-verify
quiet-close-toast
dev-merge-r4
review-mesh-agent-transport
review-app-windows-transport
settings-roundtrip
review-release-pipeline-r4
mesh-agent-transport
ended-strip-fix
review-audit-ca-update-d244
settings-rows
phone-width
signout-clear
fix-restart-tests
dev-merge-rp
signer-hardening
review-audit-ca-update
terminal-fidelity
review-audit-ca-update-wip
mesh-integrate
review-mesh-agent-transport-515d3712
review-mesh-dataplane-feec1988
mesh-dataplane
signout
research-canvas-node
wip/review-renderer-cost
wip/review-terminal-fidelity
padlock-glyph
review-release-pipeline-2e95b689
phone-polish
sidebar-polish
inbox-generic
review-mesh-dataplane-378d4055
prod-batch
ui-inbox
ui-ca-unlock
ui-machine-sections
review-mesh-dataplane-a5f744fb
tls-session-prod
session-bounds-prod
fix-dead-session
session-bounds
tls-session
palette-polish
shortcuts-d222
research-appmeta
phone-gutter
ui-centre-button
wip/ui-centre-button
wip/tls-session
review-addhost-breakit
ui-platform
renderer-cost
remote-agents
mesh-api
ssh-bootstrap
prod-hotfix2
prod-fixes
review-remote-agents
review-mesh-dataplane
session-life
research-browser
review-mesh-api
research-capture
review-mesh-api-round3
review-mesh-api-round1
gate-stability
review-gate-stability
review-relay-direct
review-mesh-api-findings
proto-sessions
font-picker
proto-addhost
proto-windows
mesh-core
latency-gate
research-bsd
research-discovery
keytray-mods
mock-core
ui-tweaks
fix-motion-sel
fix-motion
integrate2
fix-robust
t-web
t-server
vt-ghostty
fix-snap-echo
t-web-auth
review-vt2
t-agent
lane-protocol
lane-shim
lane-auth
s1-base
s1-contracts
s1-workspace
No results found.
No labels
launch-qa
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
kayg/infraternal#258
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up from the mesh-drag rounds (#254 §3b.3, P3).
In the Mesh view, a pin (a saved position) for a host that was already gone when the page loaded is never pruned, and it still counts toward the 256-pin limit.
apps/tracer/src/canvas/mesh/api.tsonly drops pins for hosts that disappear while the page is open. Over time, removed hosts can use up the pin budget, so new hosts can no longer be placed.Expected: on load (and on every full host-list refresh), pins for hosts that no longer exist are pruned, and the pruning syncs the same way a drag does (only the affected pins are written; per mesh-drag round 4, a write touches only the pins it changes). Pins for hosts that are only temporarily unreachable must not be pruned: offline is not gone.
Starting #258. Branch mesh-pins-prune-258, base origin/dev
63773bb3ec(worktree ~/wt-infraternal/mesh-pins-prune-258).Finding (read-only so far, no server change needed): the client CAN tell "removed" from "offline" from the data it has.
mesh.listreturns every enrolled node; an unreachable one arrives withlive:falseand parses tostate: "offline"(protocol.ts parseNode), a removed one is absent fromnodes. So a pin is dead only when its id is neither a listed host name nor a listedtag:<name>.Where the pins live: the source's own
pinsmap (api.ts, seeded from the saved document) and the saved canvas document (view.graphPins-> toDocument ->edits()emits onepinintent per key that differs, no position = remove). api.ts only touches its own map, and only for nodes seen in an earlier snapshot; the document is never pruned. Plan: the source says when its list is complete (MeshData.complete: status ready, non-empty list, never while loading/error/withdrawn); a smallmesh/prune.tsdrops dead keys from each graph view'sgraphPinson every applied list and callsstore.changed(), so only the removed pins go out as intents. Pagination already fails whole (MeshClient assembles one revision or rejects), so a partial page never reachesapply.Progress, branch
mesh-pins-prune-258(pushed), 3 commits on base63773bb3e:2b32f39f2mesh: the source drops pins that name nothing in a whole host listb19a13d9emesh: pins of hosts that are gone leave the saved canvas documentd26304949test(mesh): Playwright specs for pruning pins of gone hostsChoices (so a reviewer can overrule them):
mesh.listcarries every enrolled host, an unreachable one withlive:false("offline"). A pin is dead only when its id is neither a listed host name nor a listedtag:<name>(tag pins are pruned too: same budget, same bug).MeshData.complete). Failed, cut-off (protocol client rejects a partial revision, soapplynever sees it), loading, withdrawn: nothing pruned. EMPTY list: also nothing pruned. A server that has not loaded its inventory answers the same way, a wrong prune loses the whole layout while a stale pin costs one slot of 256, and the round-4 spec "a snapshot with no nodes after a reconnect does not wipe the pins" keeps its meaning. Consequence: removing the last host leaves its pin until any host exists.view.graphPins; the existing sync diff then writes onepinremoval per key and nothing else (unit test at the transport: 56 removals for 56 gone pins, 200 kept pins not rewritten; the 257th pin is refused before and accepted after).Evidence: new unit tests were red first (5 of 8 failing before the source change); the 5 new/changed Playwright specs all fail with the document prune disabled and pass with it.
Pre-existing, not mine:
bun test srcrun as one process shows 5 fail / 5 errors (matchMedia read-only global, missingrecoveryAuthexport); a clean origin/dev gives the same 5/5 (467 pass there, 481 here = +14 new tests).Finished. Head
d26304949fon branch mesh-pins-prune-258 (pushed; base63773bb3e; not merged, dev untouched).Gate output (arm64 build VM: scripts/verify fast not run, per the brief):
Open points for the owner: the empty-list and rename trade-offs in the previous comment; the unmitigated cross-device race (item 5).
Independent verification starting: review-mesh-pins-258 at
d26304949f; comparison base63773bb3ec. Read #258 and its four comments, including the declared trade-offs. Reviewing list completeness, cross-device layout safety, pin-only sync writes, tags and limits. Functional checks only on this arm64 shared VM, at most two browser workers; no scripts/verify fast/static native builds, per review brief. Evidence outside the checkout; only regression tests will be committed. Follow-up originated from #254; reading that record too.Independent review of #258
R1 — P1 — delayed inventory removes a newer pin from another device
review #258: an older inventory reply preserves a newer host pin from another devicein apps/tracer/src/canvas/model/server-store.test.ts.19537252c. This confirms the author's declared race and makes it durable shared-layout loss (D180), not just a stale local display.Independent review R2 (P1):
complete = ready && nodes.size > 0mistakes a non-empty authorized inventory for proof of deletion. The existingMeshApiService::list_with_deadlineexplicitly filters hosts by role scopes (crates/plugins/mesh/src/api.rs:821-920). Narrow visibility from prod+dev to prod, then restore it: the new document prune permanently removes the still-enrolled dev host's saved pin.Failing regression committed/pushed at
0762d68e6:review #258: narrowing then restoring visibility preserves pins of enrolled hosts(apps/tracer/src/canvas/mesh/api-prune.test.ts). Expected{prod-db: {x:10,y:10}, dev-db: {x:20,y:20}}, received only prod-db. 0 pass, 1 fail, 8 filtered out.Related browser regression at
d8e361655:review #258: a partial inventory during recovery preserves the saved layout(test/mesh.spec.ts): empty -> one-host subset -> restored four-host inventory; saved nix-cache pin {x:400,y:290} becomes undefined. 1 failed using 1 worker. This controls the recovery sequence; it does not establish that the current transactional server emits partial startup inventories. Both cases show why list non-emptiness alone cannot authorize destructive saved-layout pruning. Logs: ~/.cache/codex-scratch/review-mesh-pins-258/R2-scope.log and R2-browser.log.Review progress: regression evidence is pushed on review-mesh-pins-258 at
1995fee46(implementation unchanged). R1 reproduces a newer peer pin deleted through ServerCanvasStore after a delayed inventory reply. R2 now includes both host and tag pins plus explicit tag membership: temporarily narrowing scope removes dev-db and tag:dev, and neither saved position returns when visibility is restored. Production server filtering is at crates/plugins/mesh/src/api.rs:821-920 and 1812-1859; the new completeness/prune logic is apps/tracer/src/canvas/mesh/api.ts:102-104,230 and source.ts:68-72.Current checks: TypeScript clean; mesh/model unit tests 118 pass, 2 intentionally failing review regressions; all Mesh protocol tests 30 pass, 0 fail. Four additional boundary checks pass: page revision restart, inconsistent cursor, superseded pending response, idempotent host/tag pruning. Full non-timing Mesh Playwright suite is running with one worker on TRACER_TEST_PORT=4358; memory remains above 50 GiB available. No native static builds or performance claims.
Failing-test receipts:
R1.log
R2-scope.log
R2-browser.log
Verdict: merge after fixes. Counts: P0=0, P1=2, P2=0, P3=0.
Review branch
review-mesh-pins-258, head1995fee4684643fa7918aaa8e4e48ed8d1cb3ed3(pushed). Pinned targetd26304949f8145aba3cbfab82c886846a255adb1vsorigin/dev63773bb3ecd990b09d3663c1bd32b2cd8e49991f. Only regression/verification tests changed. No implementation fixes, deployment or issue closure.R1 (P1): delayed older inventory deletes a newer host pin saved by another device; the removal reaches the shared document and peer. Regression:
review #258: an older inventory reply preserves a newer host pin from another device(commit19537252c).R2 (P1): non-empty permission-filtered inventory does not establish deletion. Narrowing and restoring visibility permanently loses an enrolled host pin and its existing tag pin. Regression:
review #258: narrowing then restoring visibility preserves pins of enrolled hosts(0762d68e6, fixture expanded at1995fee46). Browser regression:review #258: a partial inventory during recovery preserves the saved layout(d8e361655). The recovery sequence is controlled; the current server reads snapshots transactionally. Its real role-scoped filtering independently establishes this problem.Round 4: the changed removal/rejoin spec deliberately replaces retained coordinates with fresh placement; this is the stated #258 behavior, so it no longer protects pin retention across temporary inventory absence. The unchanged empty reconnect and withdrawn-view specs still check their narrow cases. In particular, the empty reconnect spec restores all names in one synchronous batch and cannot protect an intermediate non-empty subset: the new browser regression demonstrates the gap. The moved-card-only guarantee remains covered independently by the 1,000-host drag spec, negative-origin unit/layout tests, and ServerCanvasStore's negative-drop test. The added pruning transport test checks precisely 56 removal intents, zero rewrites of 200 retained keys, and refusal of the 257th pin before cleanup followed by acceptance after cleanup. That limit test uses the existing modeled PinLimitTransport, not a newly run native server.
Validation uses one Playwright worker, unique ports 4358/4359, and the shared build-slot wrapper; available memory stayed well above the requested 10 GiB pause line. Native static builds and
scripts/verify fastwere not run, per the arm64 review brief. No performance claims. The existing frontend bundle build is part of the requested Playwright harness.Gate output below is verbatim (command plus final result blocks; complete logs attached):
Only the added review regressions fail. Four added boundary tests pass; all original 114 mesh/model unit tests and all original 57 non-frames browser specs pass. Working tree clean; local and origin review heads match. Cleanup: test proxy PID 2478999 and test server PID 2479000 are absent; no listeners remain on 4358/4359. No Cargo target was created; requested review worktree retained.
R1.log
R2-scope.log
R2-browser.log
check-final.log
unit-final.log
protocol-final.log
browser-final.log
findings.md
Fixing the two P1 review findings (R1 delayed inventory, R2 narrowed visibility). Local branch mesh-pins-258-fix (the earlier job's worktree still holds mesh-pins-prune-258, so I push HEAD to origin mesh-pins-prune-258, fast-forward). Base
d26304949(impl head) + merge of origin/review-mesh-pins-258 (1995fee46, the failing tests). Plan: look for a real removal signal (event, revision, tombstone, unscoped flag) in the mesh protocol/contracts; prune only on evidence of removal, never on absence. If no signal exists, disable the client prune and write precisely here what the backend needs to provide.Fix for R1 and R2 pushed: branch mesh-pins-prune-258, head
6578b0d89(fast-forward fromd26304949; includes the merge of review-mesh-pins-2581995fee46). Client prune is disabled pending a backend signal. Status: BLOCKED on backend for the "pins of hosts gone before load" behaviour; the two P1 layout-loss bugs are fixed.What I found (no removal signal exists)
mesh.list/ snapshot ={revision, nodes, tags, grants, next_cursor}(contracts/mesh-api.md §2, crates/plugins/mesh/src/api.rs:76). It is permission-filtered (§4) and carries no scope/unscoped flag.changedevent ={revision}only; no host or tag is named.mesh.node.delete/mesh.tag.deleteadvance the revision, but nothing tells a viewer which node or tag went.{x,y}keyed by host name ortag:<name>; it carries no mesh revision (the canvas document has its own revision line). So "the list is provably newer than the pin's write" cannot be compared either.Absence from a list is therefore indistinguishable from a stale list (R1) or a narrower view (R2).
Change (
6578b0d89)MeshData.removed(ids the server reported removed) is the only thinggonePins/pruneGonePinsact on. The source never fills it, so nothing is pruned.completestays (the review tests read it) but no longer authorizes anything.review #258: an older inventory reply preserves a newer host pin...) and R2 (...narrowing then restoring visibility...) and the browserreview #258: a partial inventory during recovery...pass unchanged.previousandtag:retiredpruned). The round-4 spec "a node that leaves the mesh and rejoins keeps its pin" is restored as it was on dev. Offline-keeps-pin, failed/partial load prunes nothing, sync-writes-only-pruned-keys and 256-limit-frees tests are kept.What the backend job must provide (no server/protocol code touched here)
Any one of these makes pruning safe; (A) is the smallest:
A. Removal reports with revisions: a
removedlist in the snapshot or aremovedsubscription event, naming the exact node (host name + node_id) and tag, each with the mesh revision at which it was removed, kept for a bounded window or until acknowledged. Permission-filtered like the rest: a viewer only gets removals for hosts they could see, and a role/scope change that merely hides a host must NOT emit one (R2).B. A revisioned, provably full inventory:
scope: "full"(instance-wide authority and no tag filter) on the snapshot, plus a comparable revision on pin writes (the canvaspinintent recording the mesh revision it was made against), so the client can prove "this unscoped list is newer than this pin and does not name the host" (R1).Either way a re-enrolled host with the same name must not be killed by a late removal of its old node: removals need the node id (ids are never reused, contracts/mesh-api.md §3) and a pin needs to know which node/revision it was written for.
Client side once a signal exists: fill
MeshData.removedin api.ts from it;prune.ts, the sync and the tests already take it.Gate output (verbatim; arm64 VM,
scripts/verify fastnot run per brief)Frame benchmarks skipped (no timing claims). MemAvailable about 52 GB throughout. Logs: ~/.cache/codex-scratch/mesh-pins-258-fix/evidence/browser3.log. No Cargo build, no binary-size change (TypeScript only).
Starting server-side #258 implementation on mesh-pins-server-258, client base 6578b0d89f (origin/mesh-pins-prune-258); merging origin/dev before implementation. Read all #258 comments including R1 delayed inventory and R2 role-filtered inventory, plus the client finish explaining why absence cannot authorize pruning. Server deletion and startup cleanup will use authoritative persisted inventory and normal layout revisions; no new wire removal signal, no client absence pruning. Heavy gates and sequential static links use the shared build slot.
Finding: remote host revocation deletes mesh_nodes in migration 0024's remote_hosts_retire_mesh trigger, in addition to mesh.node.delete. API-only cleanup would miss that path. New migration 0031 therefore removes exact host/tag keys and records normal canvas.layout.operation revisions plus 128-revision checkpoints in the deletion transaction. No crash queue is needed. Startup history cleanup reads persisted inventory under SQLite's writer transaction, one <=48 KiB document per transaction, with a durable account cursor.
Real SQLite pre-fix reproduction: deleting node gone leaves document revision 1 and pins gone={x:1,y:2}, kept={x:-600,y:320}. With migration 0031, revision=2 and only kept remains; replay intent is {type:pin,view_id:mesh,node_id:gone}, with no position and no retained-pin writes. Raw output is in the job scratch evidence/sql-red-green.log (will attach with final receipts). Role/membership changes do not invoke the deletion triggers. No credentials or new wire signal involved.
Additional data-safety finding: api.rs decode_host (around 1967–1985) exposes reported/placeholder hostnames to non-owners as stable unnamed- labels; server-sourced hostnames also have the neutral server alias. Pins use those displayed keys. Comparing only mesh_nodes.name would incorrectly sweep a still-enrolled node's neutral pin and miss it on deletion. Migration 0031 and the sweep therefore recognize both stored names and reserved identity aliases. The regression retains a neutral pin during the sweep, changes name_source, then deletes the node and requires both aliases removed from both accounts. This preserves layouts across visibility/name-source changes without introducing a client signal.
Regression receipts: the same real-SQLite deletion check fails against migrations 0001–0030 (deleted pin remains, revision 1) and passes with 0031 (only the deleted pin removed, retained coordinates unchanged, revision 2). The sweep query plan uses the existing hostname, integer node-id and tag indexes. Focused Rust/client checks are queued through the shared build slot; the cold native run found test-fixture normalization/schema mistakes, now corrected. No completion claim yet.
sql-red.log
sql-green.log
query-plan.txt
Merged dev
07c5da77b3into the client repair, pushed asc25877458. No conflicts or resolution edits. Correction to the start comment: client base is6578b0d89e. Implementation source remains uncommitted pending focused gates; shared slots are currently occupied. No new client pruning signal is introduced.Implementation pushed in atomic steps:
bb4f0350a(transactional deletion migration/replay),744969c8d(post-commit subscription invalidation),a0c966308(bounded restartable sweep, server wiring and regressions). No client/wire changes or new dependencies.Focused gate passed: touched-crate fmt/clippy/tests; 14 new real-SQLite server regressions; TypeScript check; client Mesh/model 120 pass, 0 fail (including both P1 review tests); Mesh protocol 30 pass, 0 fail. Full iterate, 58 functional browser cases, and sequential dev/branch static measurements are next.
focused.log
Wider iterate gate found two stale migration-chain fixture expectations in src/remote_migration_tests.rs: fresh schema expected [1..30] but received [1..31], and the release6-copy upgrade expected 30 applied checksums but received 31. Runtime server tests: 647 passed, only these 2 failed. Updated the fixture chain/count to 31 and added explicit migration31 ordering; historical checksums and canvas preservation remain asserted. Running the corrected upgrade tests before committing, then the final fast gate will recheck the full workspace. No baseline exception is claimed.
Functional production-build Mesh browser suite passed: 58 passed, 0 failed, one worker, TRACER_TEST_PORT=4558. Includes the unchanged review recovery regression, absence/offline preservation, phone touch drags and per-pin sync cases. Frame benchmarks excluded; no build-host timing claim. Corrected migration-fixture validation and the sequential dev/branch image measurements are running next.
browser.log
Fixture correction pushed as
561023632: contiguous migration history through 0031, shipped checksums and saved canvas data still asserted. Workspace clippy passed; all five enrollment migration-upgrade fixtures passed (0 failed), including both cases that iterate found. The earlier narrow-feature command selected no fixtures, and its remote-only clippy retry lacked the workspace feature union; neither is counted as validation. Corrected workspace commands and results are attached. Dev and branch static measurements are in progress.migration-upgrade-remote.log
Fresh D243 baseline receipts on 8by64-compute02, pinned stripped static recipe, sequential builds, dev
07c5da77b3: x86_64=21,400,400 bytes; aarch64=19,575,064 bytes. Both reproduce the existing exact caps. Implementation head561023632is building next with the same recipe and target folder.baseline-sizes.log
D243 measurements complete, pinned stripped static recipe on 8by64-compute02, sequential builds:
07c5da77b561023632Written reason for growth above 16 KiB: the server adds transactional deletion/revision/replay/checkpoint cleanup, the bounded restartable full-inventory sweep, and cancellation-safe post-commit invalidation. These provide removal authority without the two proven client layout-loss paths. Existing SQLite/JSON/async engines are reused; no new dependencies, features or release settings. Both deltas are below 64 KiB. Client pruning on absence and a new wire tombstone signal remain rejected.
Exact caps and docs/PROCESS.md table/note pushed as
4ad0f74b5(no allowance). Final scripts/verify fast is queued/running on that committed head. Full baseline receipt is linked in the preceding comment; branch receipt follows.branch-sizes.log
Finished server-side #258 on branch
mesh-pins-server-258, head4ad0f74b500201858f72754ba3702ec9d83cdef6(pushed; local/origin match).Node/tag deletion removes only the affected keys from every account/view in the deleting SQLite transaction, including remote-host revocation. Normal layout revisions, replay and checkpoints commit atomically; there is no post-deletion crash gap. The bounded one-time sweep uses full persisted inventory, a durable per-document cursor, and skips a missing inventory authority row. Reserved neutral identity aliases are retained while enrolled. Role/scope hiding never invokes removal. No new wire signal or client changes beyond the inherited repair.
Validation: 14 new real-SQLite pin regressions; migration upgrade fixtures 5 passed; focused client Mesh/model 120 passed and Mesh protocol 30 passed; functional production-build browser suite 58 passed, including the unchanged P1 review regressions. SQL pre-fix/after-migration receipts, indexed query plan and logs are linked above. The full final fast gate passed with exit 0; no baseline load exception used.
D243: x86_64 21,444,304 bytes (+43,904 vs fresh dev); aarch64 19,617,704 bytes (+42,640). Exact caps and PROCESS table/note ratcheted. The preceding measurement comment documents the reason for growth above 16 KiB; both deltas are below 64 KiB.
Self-review covered transaction/rollback boundaries, readiness and concurrency, cross-account removal, alias/name reuse, role filtering, per-key operations, checkpoint/revision limits and notification cancellation. No dependencies, permission changes or retained-pin writes. The gate does not execute the aarch64 key-memory runtime check on this x86_64 host, as its output states.
Cleanup: removed the job CARGO_TARGET_DIR and temporary dev baseline worktree; retained the implementation worktree and evidence. No listeners on 4558/4559; git tree clean. No merge, deployment or issue closure.
Final gate output below is verbatim (static results, Rust summary and final result block); the complete transcript is attached unchanged.
final-gate.log
Independent review starting: review-mesh-pins-server-258 at base
4ad0f74b50, diff against origin/dev. Reviewing deletion authority, startup/readiness, identity changes, cross-account privacy, revision/replay and pin limits. Implementation remains unchanged; regression tests and issue-attached findings only.Review progress: inherited client Mesh/model tests 120 pass, 0 fail; both earlier P1 test bodies are byte-for-byte unchanged and pass individually. New native regressions are queued through build-slot.sh (both shared slots occupied).
Preliminary real-SQLite finding at migrations/0031_mesh_canvas_pins.sql:41: automatic placeholder names use free suffixes, while redacted aliases use node IDs. Seed anchor(id=1), unnamed(id=2), unnamed-2(id=3); deleting id=2 emits a pin removal for unnamed-2 in the owner's document even though id=3 remains enrolled. The scratch SQL receipt confirms the removal. A Rust regression exercises attach_named to establish this state without directly editing inventory. Final severity/test evidence will follow its execution.
R258-S1 (P2), startup rename cleanup. Location: crates/infraternal-server/src/canvas_store/mesh_pins.rs:33. Existing layout pins before-rename; mesh.node.rename changes the same enrolled node to after-rename. The first historical sweep removes the old saved position without any node deletion. Immediate rename did not change the document.
Failing real-SQLite regression: review_258_startup_sweep_preserves_a_renamed_enrolled_hosts_pin, crates/infraternal-server/src/mesh_api_tests/pins.rs:626. Expected {x:-600,y:320}, received Null. Result: 0 passed; 1 failed; 703 filtered out. Committed as
7f153ac12on review-mesh-pins-server-258; implementation unchanged. Receipt will be attached with the final findings.R258-S2 (P1), hidden-host deletion disclosure. Location: crates/infraternal-server/migrations/0031_mesh_canvas_pins.sql:35-42.
A member denied mesh.list saves a guessed hostname through the normal canvas pin API. Owner deletes that hidden node. The trigger advances the member's document from revision 2 to 3 and emits a normal canvas.layout.operation naming private-db. Canvas subscriptions publish this operation, so an account with no prior host visibility learns that host's existence/deletion. Unrelated keys remain untouched, but exact-key matching alone does not preserve privacy.
Failing test: review_258_hidden_host_deletion_does_not_answer_a_members_name_probe, crates/infraternal-server/src/mesh_api_tests/pins.rs:660. 0 passed; 1 failed; 703 filtered out. Test explicitly confirms mesh.list is Denied before deletion. Review commit
a6510f928, implementation unchanged. Run the already-built native server test binary with the test name; receipt R2.log will be attached with final findings.R258-S3 (P1), deletion removes a different enrolled node's layout pin. Location: crates/infraternal-server/migrations/0031_mesh_canvas_pins.sql:41.
Reproduction uses the production naming API: enroll anchor as node 1, attach two hosts without reported names. Node 2 is named unnamed; node 3 is named unnamed-2. Owner pins node 3 at {x:-600,y:320}. Deleting node 2 globally matches its neutral unnamed-2 alias and removes node 3's owner-visible pin. Node 3 is still enrolled. Actual-name and neutral-alias meanings differ between accounts; matching both strings in every document loses an unrelated live host's saved position.
Failing real-SQLite test: review_258_deleting_a_neutral_alias_preserves_another_nodes_real_name_pin, crates/infraternal-server/src/mesh_api_tests/pins.rs:687. Expected saved position, received Null. 0 passed; 1 failed; 703 filtered out. Review commit
a252c93db, implementation unchanged. R3.log and the direct SQL replay receipt will be attached with final findings.Current counts: P0=0, P1=2, P2=1, P3=0. Required scripts/verify fast is running/queued on review head
a252c93db; all three regressions remain intentionally failing.R1.log
R2.log
R3.log
sql-check.log
findings.md
Review head
a252c93dbais pushed and clean; exactly three test-only commits (135 added lines). All three new native regressions have failed individually, and both P1 findings plus logs are posted above. Client suite: 120 pass, 0 fail; TypeScript check clean.The required scripts/verify fast has waited about 20 minutes for build-slot.sh; its redirected log is still empty, so no gate result is claimed. Both shared slots are occupied. Continuing to wait without starting another heavy command. No implementation changes, deployment or issue closure.
Review head updated to
81a0b901ec(pushed). The first full gate found a clippy assertion-style lint in the new rename regression's precondition. Commit81a0b901echanges only that assertion to the existing pin suite's length-comparison style; the retained-position failure and all implementation files remain unchanged.Stopped that obsolete gate's own memory scope (run-p315948-i8703710.scope, confirmed inactive) and restarted scripts/verify fast on the corrected head. No other job was stopped. Prior attempt retained as gate-attempt1.log; final-gate.log now belongs to the corrected head. Counts remain P0=0, P1=2, P2=1, P3=0.
Corrected-head validation (
81a0b901ec): fmt, CLI compile-out and workspace clippy passed. Server test result, verbatim:Only the three new review regressions failed. All 14 existing Mesh pin regressions passed: rollback/revision exhaustion, role and membership hiding, full-inventory readiness, bounded restart/idempotence, concurrent enrollment/pinning, ready empty inventory, deletion/replay/reopen, aliases, notifications and real 256-pin budget/checkpoint behavior. No baseline load exception is needed. scripts/verify fast continues through the remaining rows and static builds; final gate result is not yet available.
Fresh x86_64 static review image at
81a0b901ec: 21,444,304 bytes; exact declared cap, static linkage/trust/key-memory checks passed. Compared with the supplied fresh dev07c5da77breceipt (21,400,400 bytes), delta is +43,904 bytes. Recipe unchanged: scripts/static-cargo build --locked --release --package infraternal --target x86_64-unknown-linux-musl, on 8by64-compute02. Baseline was not rebuilt in this review.The >16 KiB written reason is present on #258 and in PROCESS section 7. No Cargo dependency, feature or release-profile change. New native sweep/notifier helpers have production callers; the retained client removal-set plumbing is inactive because the source emits no removed IDs (current cleanup arrives through normal canvas events). The aarch64 image is still compiling; final fast result remains pending.
Verdict: merge after fixes. New server-review findings: P0=0, P1=2, P2=1, P3=0.
Review branch
review-mesh-pins-server-258, head81a0b901eca8d170eefe120a8a23b27365bfa522(pushed; local/origin matched; clean before checkout removal). Target implementation4ad0f74b500201858f72754ba3702ec9d83cdef6against dev07c5da77b3e368d5cb97d9c47ea06fd3f807d975. Four test-only commits; one file, 135 added lines. Implementation unchanged.migrations/0031_mesh_canvas_pins.sql:41removes an unrelated live node's saved position. Production automatic naming produces node 2 namedunnamedand node 3 namedunnamed-2. Deleting node 2 globally matches itsunnamed-2neutral alias in the owner's document and removes node 3's pin, although node 3 remains enrolled. Failing test:review_258_deleting_a_neutral_alias_preserves_another_nodes_real_name_pin; commita252c93db.migrations/0031_mesh_canvas_pins.sql:35-42reveals hidden host deletion. A member deniedmesh.listsaves a guessed hostname through normal layout apply. Owner deletion emits a member-visible removal naming that hidden host and advances the member's revision. No previous host access is required. Failing test:review_258_hidden_host_deletion_does_not_answer_a_members_name_probe; commita6510f928.canvas_store/mesh_pins.rs:33treats a historical rename as deletion evidence. Rename preserves the document immediately, but the first startup sweep removes the old saved coordinates while the same node remains enrolled. Failing test:review_258_startup_sweep_preserves_a_renamed_enrolled_hosts_pin; commit7f153ac12. Commit81a0b901eadjusts only its precondition assertion for clippy; the retained-position failure is unchanged.All three tests are in
crates/infraternal-server/src/mesh_api_tests/pins.rs; full findings entries and receipts are attached. Both P1 findings were commented separately above. No implementation fixes, deployment or issue closure.Validation: all 14 existing native pin regressions pass, covering rollback, scope/membership hiding, restartability/idempotence/readiness, empty inventory and last-host cleanup, concurrent enrollment/pinning, replay/checkpoints, notifications and the real 256-pin limit. The earlier two P1 client test bodies are unchanged and pass. Client Mesh/model: 120 pass, 0 fail; Mesh protocol: 30 pass, 0 fail; TypeScript check exit 0. The TypeScript section inside fast is not reached after the intentional Rust test failure, so those client checks were run separately. No browser suite or runtime performance measurement was run in this review.
Final
scripts/verify fastoutput on the review head, verbatim summary; complete transcript attached:No baseline load exception was used. Every other executed Rust gate row passes. Fresh stripped static images on 8by64-compute02 match the exact caps: x86_64 21,444,304 bytes; aarch64 19,617,704 bytes. Against the supplied fresh dev receipts, deltas are +43,904 / +42,640 bytes. Baseline images were not rebuilt in this review. The >16 KiB written reason is present on #258 and in PROCESS section 7; no Cargo dependency, feature or release-profile change. New native sweep/notification helpers have production callers. Retained client removal-set plumbing has no producer and is inactive in the current server-driven path. The aarch64 key-memory runtime check was not executed on this x86_64 host, as the gate states.
Cleanup verified: requested CARGO_TARGET_DIR removed; unused temporary baseline checkout and temporary review checkout removed; obsolete and final review memory scopes inactive. Evidence remains outside the repository. Only the review branch was pushed.
final-gate.log
findings.md
size-review.txt
client.log
earlier-reviews.log
protocol.log
ts-check.log
cleanup.txt
R1.log
R2.log
R3.log
sql-check.log
Starting the final #258 fix round. Base mesh-pins-server-258
4ad0f74b50; review81a0b901ecmerged locally. The requested branch is already held by a clean retained checkout, so work is isolated at ~/wt-infraternal/mesh-pins-fix on mesh-pins-fix-258; any completed work would fast-forward origin/mesh-pins-server-258. Dev merge currently conflicts only in PROCESS size records and rust.sh caps. Read the client and server review record. Checking whether stable identity migration plus lazy account-local pruning meets all privacy and unchanged-review constraints before writing implementation, per the last-round stop rule. No production changes or credentials posted.Final-round stop: the proposed existence-only lazy cleanup is insufficient to close R258-S2's no-disclosure requirement. No implementation patch has been made.
Evidence: canvas accepts arbitrary graph IDs independently of Mesh visibility (contracts/wire.md:663; canvas_store.rs:270-284 checks ownership for open/split/target, not pin). The unchanged review test explicitly relies on an account denied mesh.list successfully saving a guessed name. Replacing that name with a guessable monotonic node ID does not change the privacy boundary.
With no cross-account write and no revision/event on deletion, a member can still poll its own snapshots. A guessed hidden-live ID remains on one load; after hidden deletion, the full-inventory existence predicate removes it on the next load. Comparing the two documents reveals exactly the hidden deletion. Keeping the revision constant does not conceal the changed document. Mapping an unauthorized guessed legacy name to a stable ID can also disclose the name's existence during migration itself.
A minimal SQLite model (not a production regression or a claim that a new implementation was tested) verifies the proposed predicate's observable behavior:
lazy-privacy-model.log
This is not a claim that stable identity or account-local cleanup is impossible. Both are useful. The missing rule is which pins may acquire an authoritative binding and which deletion evidence this particular account may observe. Full-inventory absence alone supplies neither authorization nor provenance. Simply hiding the unsolicited revision passes the current S2 test's narrow event assertion while retaining the disclosure through snapshots; that would not satisfy the brief.
Per the owner's last-round rule, stopping here for a written owner plan rather than adding another patch round. No credentials or production data were accessed.
Final-round finish: STOPPED for owner plan, not fixed or ready to merge. Remote mesh-pins-server-258 remains
4ad0f74b50. No implementation changes, new pushed commits, cap changes, deployment or issue closure.Written plan for the owner (not an approved implementation design):
8f88bf086, and run the final fast gate.Validation performed in this stopped run: source/contract review and the attached SQLite logical model (assertions passed). scripts/verify fast was NOT RUN; no gate output or new binary measurements are claimed. Last recorded branch image sizes on #258 remain 21,444,304 / 19,617,704 bytes (x86_64 / aarch64); supplied dev sizes are 21,420,592 / 19,592,504 bytes. These are historical receipts, not measurements from this run.
Cleanup: aborted the unresolved dev merge, removed my temporary mesh-pins-fix checkout and local mesh-pins-fix-258 branch (including the transient review merge), verified the original mesh-pins-server-258 checkout is clean, and verified ~/.cache/codex-scratch/mesh-pins-fix/target does not exist. No build, server or browser process was started. Evidence is retained outside the repository. All three findings remain open on the unchanged implementation head.
Starting owner-approved #258 v2 implementation. Branch mesh-pins-258-v2; base origin/dev f9d0a9a8fa (full SHA follows from checkout record). Reading all earlier review rounds and the stopped final-round plan before test-first changes. Pins remain in the ordered canvas document; no separate pins table, fixed count, name-keyed authoritative identity, or deletion-event pruning. No merge or deploy.
Design details before contract/code changes (#258 v2): base
f9d0a9a8f4. Current D235 is SSH identity/access; canvas ordered operations are D183/D248. D312 is read.Pin keys will be node: and tag-id:<32 lowercase random hex identity>. Tags gain an immutable, unique identity generated on insertion; renames keep it, delete/recreate allocates another. Existing name-keyed pins bind only against unambiguous labels in the writing account's full role-filtered inventory. New pin writes require visible stable keys (names, hidden keys and unknown keys receive the identical opaque refusal). Permanent retries are checked before admission and never re-resolve old names.
Dormant coordinates and first-observed-out-of-view Unix seconds remain internal entries in the account's canvas document, never in another table or exposed snapshot. On an account read/edit, one writer transaction reconciles against that account's full role-filtered inventory: move hidden pins to dormancy, restore within 30 days, otherwise drop at >=30 days. Legacy unresolved names follow the same clock. A normal account-local pin operation/revision records each change; visibility transitions checkpoint the wire projection so historical operation tails cannot disclose now-hidden IDs. No deletion hooks or existence lookup: missing and hidden take exactly the same path, including snapshots and replay. Clocks start when absence is observed, conservatively; no claim to know an unseen deletion time. Idle accounts are reconciled on next use.
Bounds: retain finite graph coordinates +/-100000 (200000-pixel span, about 500 cards across at 400 px/card; enough area for 10000 cards; matches existing tests). Raise the document hard cap to 2 MiB and canvas frame cap to document+envelope (below protocol's 4 MiB). A maximum stable pin encodes below 128 bytes; 10000 hosts + 2000 tags = 12000 * 128 = 1536000 bytes; 2 MiB leaves 561152 bytes for existing layout, dormant metadata and envelope headroom. Apply remains 8 KiB because it writes one pin, bootstrap is document cap+2048. No count limit. Larger histories fail bounded admission rather than allocate unbounded memory. Functional encoded-size evidence will use 10000 pins; runtime RSS/timings require orchestrator perf-VM execution, never this build VM.
Rejected: separate pins table, fixed per-view count, authoritative name keys, and pruning on deletion events. Earlier tests demanding guessed-name acceptance, immediate deletion cleanup, startup existence sweeps, or the 256 ceiling are explicitly superseded by the owner's new rules; their privacy/layout-retention invariants will be retained in replacement tests. Earlier client stale-response/scope regression bodies will be imported unchanged where their source interfaces remain compatible.
Completed first slice
a67977937(pushed): removed the fixed pin-count ceiling, retained finite +/-100000 coordinates, and raised the bounded canvas document/frame budgets. The scale regression failed on dev's fixed count, then passed; canvas crate tests 13/13 and touched-crate clippy passed. Subsequent batch-reconciliation coverage brings the current crate suite to 14/14.Implementation finding: replay must be reconciled as well as snapshots. The account-local visibility path now reduces ordinary per-key pin intents and checkpoints the resulting public document, cutting off older pin operation tails. Internal dormant entries carry only the account's previously held coordinates and its first observation time. No global deletion callback mutates documents. Batched pin reduction shares the ordinary pin reducer but validates the document once per boundary, avoiding quadratic validation scans when 10000 pins become hidden together.
The native red admission/tag tests are preserved in an isolated origin/dev checkout and queued through build-slot.sh; both host slots are currently occupied by other jobs. No native result is claimed yet. Current client Mesh/model suite: 102 passed, 0 failed; TypeScript check passed after installing this worktree's pinned dependencies. New tests cover hidden/unknown keys, rename, retention, full snapshot/stream equivalence, tag incarnation, legacy migration, two devices/retries, and 10000 real inventory rows.
Perf-VM request (no runtime numbers measured on this build host): after the native test binary is available, copy it to ~/infraternal-perf/mesh-pins-258-v2 and run through /usr/local/bin/perf-run.sh, with CARGO_TARGET_DIR pointed to that job directory, test filter mesh_api_tests::pins_v2::ten_thousand_visible_hosts_can_initialize_pins_within_wire_and_storage_bounds --exact --nocapture. Please collect peak RSS via the perf VM's measurement wrapper. The test creates and cleans only its own SQLite fixture and reports encoded initialization/snapshot/persisted bytes. Binary path/receipt will follow compilation. This distinguishes actual runtime memory from the analytical encoded-byte hard cap.
Native red-first evidence on isolated origin/dev
f9d0a9a8f4: guessed_hidden_names_and_ids_share_unknown_refusal failed with "accepted node:1"; tag_incarnation_survives_rename_but_not_recreation failed because the tag has no 32-character id. Result: 0 passed, 2 failed; BASELINE_RED_EXIT=101. The 10000-pin model regression separately failed on the old fixed count.Pushed support slices:
1f0fa34d1shares ordered pin reduction with batch reconciliation;0ade45fddvalidates private retention entries in the existing document;fd965e3f0wakes active canvas subscriptions from the host's existing visibility invalidations. Canvas crate: 15 passed, 0 failed; touched-crate clippy and formatting passed. No idle worker/timer or wire removal signal was added.Build finding: switching baseline/current checkouts in the one required CARGO_TARGET_DIR reused a stale dependency artifact (main server initially saw the old MeshTag and no pin_inventory). Invalidated the edited Mesh source before rebuilding; the current checkout now recompiles that crate. This was not counted as a code regression or validation pass. Static comparisons will explicitly clean only the affected packages in this job's target when switching source trees, so baseline images cannot reuse branch code.
Finding: a legacy tag name must not bind a tag recreated before the account's first canvas read. Migration 31 records private upgrade-boundary name provenance on existing tag incarnations; a rename retains it, while later creations have none. Legacy binding requires that provenance to equal the current visible name. This conservatively leaves renamed/unresolved names dormant and prevents recycled names from claiming an old position. Added schema-upgrade and full canvas import regressions; no deletion event touches a layout.
Native functional scale evidence from the current implementation: 10,000 real visible host rows with pins encode initialize=369089 bytes, public snapshot=409141, persisted document=409064; hard document cap=2097152, frame cap=2101248. This is encoded-size evidence, not a build-host runtime-memory measurement. The perf-VM RSS request remains outstanding.
Notification finding: Mesh observations carry liveness_deadline but cannot change pin identity or account visibility. The connected-canvas regression first failed because those heartbeat-only revisions woke pin reconciliation. The listener now consumes those notices without a full inventory scan; lag still forces a reload and other existing invalidations still wake it. Red evidence: red-liveness.log (0 passed, 1 failed, expected Pending). Green run queued in the native pins suite.
Perf-VM artifact is now available on the build host at /home/agent/.cache/codex-scratch/mesh-pins-258-v2/pins-native-tests (native test binary, copied outside the target before static comparison cleanup). This is a test-profile memory/functional scale run, not a production latency benchmark.
Please copy it to ~/infraternal-perf/mesh-pins-258-v2/pins-native-tests, then run on a perf VM:
/usr/local/bin/perf-run.sh -- env CARGO_TARGET_DIR=$HOME/infraternal-perf/mesh-pins-258-v2 ./pins-native-tests mesh_api_tests::pins_v2::ten_thousand_visible_hosts_can_initialize_pins_within_wire_and_storage_bounds --exact --nocapture --test-threads=1
Collect peak RSS, machine/load and artifact hash with the receipt. The executable creates only its own SQLite fixture and reports encoded bounds. Shared-build-host timings/RSS are not performance evidence. No perf-VM access is authorized for this implementation job, so the orchestrator must relay the run.
Size-bound finding: live pins near the document ceiling need room for future dormant wrappers. Red regression admission_reserves_retention_metadata_before_visibility_can_expand_storage accepted 28 views of 1000 visible IDs (live document below 2 MiB), even though adding retention metadata would exceed the cap. Red result: 0 passed, 1 failed. This could make a later visibility-reconciled read fail at save.
Admission now reserves the hypothetical fully dormant encoding: 41 extra bytes per live pin for {position,since} with a 19-digit timestamp, missing metadata container keys/commas, and clock/revision digit growth. It counts live entries without cloning positions or allocating one wrapper per pin. The same 2 MiB hard cap applies; no fixed count is reintroduced. 12000 * (128 + 41) = 2028000, leaving 69152 bytes for containers and other layout data. The 10000-host fixture remains well inside this bound (409064 live persisted bytes plus 410000 pin-wrapper bytes and small container/revision overhead). Added a partial/full visibility budget invariant test as well.
Resuming #258 v2 after the previous run stopped at a usage limit. Branch
mesh-pins-258-v2, base origin/devf9d0a9a8f4, resumed from55f52a239(four reviewed slices a67977937..fd965e3f0 plus one WIP snapshot). Worktree ~/wt-infraternal/mesh-pins-258-v2.Plan: review the WIP against the owner design of 2026-10-30, split the WIP snapshot into atomic commits (this branch's unreviewed history only; force-push only this branch), finish the remaining tests and bounds, measure both pinned static images against origin/dev, then run
scripts/verify faston the head.Note on numbering: on dev, D235 is SSH identity and access. The canvas document as an in-order operation log is D183 (with D248's intent-only layout changes). I follow D183/D248 for that rule; D312 (per-tab edits, the server is the only saved copy) is also respected.
Review of the stopped run's WIP (
55f52a239) against the owner design: it follows it (stable node:/tag-id: keys, visible-only admission with one refusal, private dormant positions in the same document, account-local reconciliation, no deletion hook, no new table or wire signal). Three findings, fixed before the split:tag:<name>pins bound only while the tag still carried its upgrade-time name, so a tag renamed after the upgrade but before the account's first read lost its position, against "a rename keeps the pin". Now it binds through the provenance migration 31 records (legacy_pin_name); tags created later still cannot claim it. Red first:legacy_tag_pin_follows_its_upgraded_incarnation_through_a_renamefailed on the WIP (left {}, expected the tag-id pin), passes now.BEGIN IMMEDIATE, and scanned the whole inventory, even when nothing changed. That serializes all canvas writers and blocks SQLite writers behind a 10,000-row scan. Reads now decide from a plain read snapshot and take the writer only when a pin actually changes.a_non_pin_edit_after_lost_visibility_cannot_replay_the_hidden_identitychecks that no snapshot or replay tail names the hidden ID after such an edit.Also fixed: 7 workspace clippy errors and 2 TypeScript errors in the WIP.
Pin suite now 20 passed, 0 failed; touched-crate clippy and fmt clean. 10,000 visible hosts with pins (functional encoded sizes, not timings): initialize=369089 bytes, snapshot=409141, persisted=409064; document cap 2097152, frame cap 2101248. With the 41-byte retention reserve per live pin the admitted worst case for this document is about 819 KB, under the cap.
red-legacy-rename.log
f3-pins.log
f3-scale.log
History rewritten and force-pushed (this branch only, lease on the WIP head
55f52a239):mesh-pins-258-v2is now0d877aeb28, rebased on origin/dev42ab33035(dev's two new commits are docs/decisions only). The WIP snapshot is gone; the final tree is byte-identical to the reviewed local state.1f55c0b1174f179d2804dd543438e86d348827c28fc583088fe4825d4756e110d877aeb2Each commit message names the rejected alternatives (separate pins table, fixed count, name keys, pruning on deletion events / global sweep) and lists the earlier #258 tests it supersedes, with the reason. Per-commit gate of the three new Rust commits: fmt 0, clippy (mesh + server, all targets) 0, mesh crate 26 passed, server mesh tests 34 / 36 / 50 passed, 0 failed. The tracer commit:
bun run checkclean, mesh/model unit tests 104 passed.Next: D243 static images (dev, then head, one at a time), then
scripts/verify faston the head.Paused for handover (orchestrator request). Head
mesh-pins-258-v2=6b42115839(an empty "WIP: paused for handover" commit on top of the reviewed split0d877aeb2). Nothing of this job is running; no uncommitted changes.Done
42ab33035, with three fixes (legacy tag pin follows its incarnation through a rename; reads take the writer only on a change; non-pin edits skip the inventory).bun run checkclean, mesh/model 104 passed.42ab33035, pinned static recipe on 8by64-compute02: x86_64 21,431,472, aarch64 19,605,896 bytes (both equal dev's caps).Next
/usr/local/bin/build-slot.sh ~/.cache/codex-scratch/mesh-pins-258-v2/size.sh head(it cleans the touched crates first; source remapping made a stale crate reuse possible earlier).scripts/verify.d/rust.shcaps and the docs/PROCESS.md §7 table; written reason here if growth is over 16 KiB.scripts/verify faston the head, quoted verbatim; finish comment; remove CARGO_TARGET_DIR (~/.cache/codex-scratch/mesh-pins-258-v2/target, ~9 GB) and the scratch baseline worktree (git worktree removeof ~/.cache/codex-scratch/mesh-pins-258-v2/baseline).Known failures: none open. Not yet run on this head: the full
scripts/verify fast, the Mesh Playwright suite, and the branch size builds. The migration-fixture tests did not run per commit (the filter matched no tests); the full gate covers them.Starting continuation on branch mesh-pins-258-v2, WIP head
6b42115839, base origin/dev42ab330358. The requested worktree path is absent locally; the exact branch still exists on origin. I am restoring it at the requested path, then pushing the pre-split backup before rewriting history.Finding with evidence: the restored branch already contains the eight atomic feature commits 1f55c0b11..0d877aeb2 on base
42ab33035; the only extra commit is6b4211583, an empty handover marker (git diff --stat HEAD^ HEADis empty). The requested backup ref wip/mesh-pins-258-pre-split now points to the exact original head6b42115839. I am dropping only that empty marker and rebasing the split commits onto the fetched current origin/dev.Blocked on the required build host. The exact branch was restored, the requested backup ref was pushed at
6b42115839, and the empty handover marker was dropped; local HEAD is0d877aeb28, rebased and up to date with fetched origin/dev42ab330358. The assigned host resolves to 10.69.69.218, but plain SSH fails withssh: connect to host infraternal-dev-01-compute01 port 22: No route to host(same result with the VPN FQDN and forced IPv4). Per the job brief, builds/tests must run there and linked-environment/alternate-SSH paths are excluded. Pin tests, both size builds, and scripts/verify fast have not run in this continuation; leaving mesh-pins-258-v2 unpushed pending host reachability.Progress: the requested 20 pin regressions passed on infraternal-dev-02-std through build-slot: 14 mesh_api_tests::pins_v2 + 5 canvas_store::mesh_pins + mesh_api_tests::tag_identity::tag_incarnation_survives_rename_but_not_recreation. The second tag identity migration test also passed (21 related Rust tests total). The two corrected float-vs-int expectations in pins_v2 were exercised.
bun run checkpassed andbun test src/canvas/mesh src/canvas/modelpassed 104/104. Next I am force-with-lease pushing the cleaned history; x86 size builds and scripts/verify fast remain on compute01.Update: compute01 is reachable again. The cleaned branch is pushed at
0d877aeb28; the backup ref remains at6b42115839. On dev-02 through build-slot, 20 core pin regressions passed (14 pins_v2, 5 canvas_store::mesh_pins, 1 tag-incarnation regression), the additional tag migration test passed,bun run checkpassed, and Mesh/model tests passed 104/104. Sequential x86_64/aarch64 static size builds are queued on compute01 through build-slot; the host is healthy and no size result is available yet.Update: compute01 is reachable, but at the one-hour mark all four build slots remain occupied by active jobs. The sequential x86_64/aarch64 static-size command is still queued through build-slot; no size measurements or final scripts/verify fast output are available yet. It remains queued on compute01 as required.
Round 1 review started. Branch: review-mesh-pins-258, based at target head
0d877aeb2(implementation merge base42ab330358). I’m reading the complete issue/decisions, reviewing concurrency, privacy, retention, migration, and resource bounds, then I’ll run requested size checks and scripts/verify fast on compute01.Round 1 finding — P2: dormant pin coordinates survive after the last graph view is removed.
Evidence: On compute01, the focused SQLite regression
dormant_pin_expires_after_its_graph_view_is_removedfailed atcrates/infraternal-server/src/mesh_api_tests/pins_v2.rs:167. At exactlysince + 30 days, the persisted document still contained_mesh.mesh["node:1"]with its position andsince, despiteviews: [].Cause:
crates/infraternal-server/src/canvas_store.rs:139-145returns fromreconcile_atwhenhas_graphis false;crates/infraternal-server/src/canvas_store/mesh_pins.rs:173-175also no-ops. With the final graph removed, the dormant entry never reaches expiry cleanup.Impact: hidden coordinates and identity remain in the account document past the promised 30-day retention period. The regression is committed on
review-mesh-pins-258at88439e647(review test only).Round 1 finding — P1: op replay exposes a hidden stable identity after the last graph view is removed.
Evidence: On dev-02 through build-slot,
replay_after_last_graph_removal_does_not_expose_a_newly_hidden_pinfailed atcrates/infraternal-server/src/mesh_api_tests/pins_v2.rs:200. After removing the account's Mesh role and then its final graph view,events(account, Some(pinned_revision - 1))returned a replay tail containingnode:1in the oldcanvas.layout.operation, followed by theview.removeoperation.Cause:
crates/infraternal-server/src/canvas_store.rs:91-95triggers read reconciliation only when the current document still contains a graph layout. The non-pinview.removepath appends an ordinary operation without checkpointing (canvas_store.rs:382-395), andmesh_pins::reconcileitself no-ops when no graph remains (canvas_store/mesh_pins.rs:173-175). Thus an old pin intent survives in the replay tail after visibility is lost.Impact: a lagging same-account device can receive an identity that is no longer in that account's role-filtered inventory. This violates the hidden-identity replay invariant and is P1. Regression test is on
review-mesh-pins-258, head2c335c62be5512212ae23946e848c0d6beae9654(test only).Reachability note for the P1 above: the Canvas socket's
publishcallsLayoutStore::events(account, sub.revision)atcrates/plugins/canvas/src/socket.rs:148-170. Itstokio::select!handles apply calls at lines 101-114 alongside Mesh visibility notices at 129-134. A pendingview.removecall can therefore commit before a pending visibility publish; the follow-up changes publish then reads from the subscriber's older cursor. Since the head has no graph,eventsskips reconciliation and returns the pin operation still in the tail. This is the two-device ordering represented by the regression.P1 regression update (same finding): the test now uses distinct writer and stale-reader
Storeinstances, with the reader applyingview.removefrom its pre-pin base revision. Re-run on dev-02 after commitda74aeefa6de81756cd5f89a11e2a40831565156compiled successfully and failed as expected atcrates/infraternal-server/src/mesh_api_tests/pins_v2.rs:205. The assertion output again contains the oldnode:1pin operation (revision 2) and the finalview.remove(revision 3). The test-only branch head is nowda74aeefa6de81756cd5f89a11e2a40831565156.Progress: Round-1 P1 replay leak and P2 retention-after-view-removal findings are posted above. The five
canvas_store::mesh_pinsunit tests pass on dev-02, including exact 30-day expiry and retention-budget cases. Review branchreview-mesh-pins-258is pushed atda74aeefa6de81756cd5f89a11e2a40831565156; compute01's worktree is on target0d877aeb2.Blocked on shared compute slots for the remaining evidence: the queued size job PID 308243 (process group 308234) is still waiting after 02:59:27.
/tmp/mesh-pins-258-v2-sizes.logstill contains onlybuild-slot: [17:43:23] all 4 slots busy, waiting...; no size row is available. I am leaving that job queued. Next: collect its size rows, runscripts/verify faston the target head, then measure the 10,000-entry inventory/reconciliation path on the perf VM.Round 1 progress: target
mesh-pins-258-v2remains0d877aeb280307bd05289c6e2a7fcb878bf06381; test-only review branchreview-mesh-pins-258isda74aeefa6de81756cd5f89a11e2a40831565156.The P1 replay leak and P2 retention-after-final-view-removal regressions are posted above. The required x86_64/aarch64 static-size job is still alive under build-slot (PID 308243, process group 308234);
/tmp/mesh-pins-258-v2-sizes.logremains atbuild-slot: [17:43:23] all 4 slots busy, waiting..., so there are no size rows yet. I’m checking whether removal of one graph view leaves its private dormant coordinates persisted while another graph view remains, and reviewing future timestamp handling.Next: finish the additional defect checks, collect the queued sizes, run
scripts/verify faston compute01, then measure the 10,000-entry scan/write path on the perf VM. Logs remain at/tmp/mesh-pins-258-v2-sizes.logand/tmp/mesh-pins-258-v2-size.shon compute01.Round 1 finding — P2: a future dormant timestamp extends retention after a clock rollback.
Location:
crates/infraternal-server/src/canvas_store/mesh_pins.rs:277,294-295;crates/plugins/canvas/src/model.rs:193-198.hidestores the wall-clock value directly assince. The document validator accepts every nonnegative i64, including a future timestamp. When the clock is corrected andnow < since,saturating_subreports zero elapsed time, so the hidden position remains until the skew has elapsed plus another 30 days.Regression:
mesh_api_tests::pins_v2::a_future_dormant_timestamp_does_not_extend_retention_after_clock_rollback, review commit3180f92bc(branch now035f6b7c6). On dev-02 through build-slot, the test failed atpins_v2.rs:153as expected: after simulating a 60-day forward clock jump when absence is first observed, then correcting time and reconciling at the 30-day boundary, persisted_mesh.mesh["node:1"]still held{position:{x:-600,y:320},since:1805184000}. Result: 0 passed, 1 failed.A wall-clock jump can therefore retain private coordinates beyond the stated 30-day period. The test is review-only; no implementation code changed.
Round 1 finding — P2: private dormant pin state is not persisted as cleared when one graph view is removed and another remains.
Location:
crates/infraternal-server/src/canvas_store/mesh_pins.rs:199,221;crates/infraternal-server/src/canvas_store.rs:144-145.reconcileremoves dormant state for view IDs no longer present, but itschangedresult only checks whether public pin intents were emitted. Removing a view's private-only state emits no intent. With another graph view present,reconcile_atreaches this path, seesfalse, and discards the modified document copy; each later read repeats the same unsaved cleanup.Regression:
mesh_api_tests::pins_v2::removing_one_graph_view_persists_private_pin_cleanup, review commit035f6b7c6. On dev-02 through build-slot it failed atpins_v2.rs:262; after themeshview was removed, a read with theothergraph still present left_mesh.mesh["node:1"]and its coordinates incanvas_heads. Result: 0 passed, 1 failed.The hidden coordinates remain stored indefinitely and can be associated with a later view reusing that ID. The test is review-only; no implementation code changed.
Round 1 stopped at the required D243 size threshold.
Target
mesh-pins-258-v2is unchanged at0d877aeb280307bd05289c6e2a7fcb878bf06381. The size script on compute01 emitted this x86 row:The recorded origin/dev
42ab33035baseline is 21,431,472 bytes, so the increase is 85,984 bytes (about 84 KiB), above the brief's 64 KiB stop threshold. I stopped the remaining ARM build in process group 308234 and verified no process in that group remained. No aarch64 row is available.Per the threshold rule, I did not run
scripts/verify fastor the 10,000-entry perf-VM measurement after this result. No gate pass or perf number is claimed. Those checks remain outstanding pending owner direction on the size overage.Review branch
review-mesh-pins-258is pushed at11fae094e282306c785c535b6616ef51564c0c46, test/report only. Verdict: request changes, P0=0, P1=1, P2=3, P3=0. The replay leak and three retention defects are documented above and infindings.md. No merge or issue closure.Starting J33 round 2 on branch
mesh-pins-258-v2, implementation head0d877aeb2; requested baseorigin/dev57491e918c91fbf44dd5b318da168e1b4ef40310. I have read the full #258 history, J8's implementation notes, J9's round-one findings, D183/D248/D312, the shared brief, and the D243 size record. Next: restore the requested r2 worktree, rebase, cherry-pick the four review regressions, then fix them failing-first. Required remote checks will use build-slot on dev-02 and compute01, with the scale measurement through perf-run.Round-two red evidence for P1 replay privacy:
mesh_api_tests::pins_v2::replay_after_last_graph_removal_does_not_expose_a_newly_hidden_pinfailed onclaude@infraternal-dev-02-stdthroughbuild-slotat test line 301. The stale reader received the oldnode:1pin operation at revision 2 followed byview.removeat revision 3. This reproduces the hidden-identity leak from J9's finding. Full run log:/home/claude/.cache/codex-scratch/mesh-pins-258-r2/evidence/pins-red.log.Round-two red evidence for P2 final-view retention:
mesh_api_tests::pins_v2::dormant_pin_expires_after_its_graph_view_is_removedfailed onclaude@infraternal-dev-02-stdthroughbuild-slotat test line 210. At exactlysince + 30 days, the persisted head still contained_mesh.mesh["node:1"]with its position and timestamp whileviewswas empty. Full run log:/home/claude/.cache/codex-scratch/mesh-pins-258-r2/evidence/pins-red.log.Round-two red evidence for P2 clock rollback retention:
mesh_api_tests::pins_v2::a_future_dormant_timestamp_does_not_extend_retention_after_clock_rollbackfailed onclaude@infraternal-dev-02-stdthroughbuild-slotat test line 153. After correcting the clock and advancing 30 days from the observation,_mesh.mesh["node:1"]still contained{position:{x:-600,y:320},since:1805184000}. Full run log:/home/claude/.cache/codex-scratch/mesh-pins-258-r2/evidence/pins-red.log.Round-two red evidence for P2 private-state persistence:
mesh_api_tests::pins_v2::removing_one_graph_view_persists_private_pin_cleanupfailed onclaude@infraternal-dev-02-stdthroughbuild-slotat test line 262. Removing themeshview whileotherremained left_mesh.mesh["node:1"]and its coordinates incanvas_heads. Full run log:/home/claude/.cache/codex-scratch/mesh-pins-258-r2/evidence/pins-red.log.Round-two P1 fix is committed at
9696f3810and pushed. A graphview.removenow reconciles the account's role-filtered inventory and uses the existing snapshot checkpoint, which clears the old replay tail before a stale cursor can receive it. The focused regression was red in the pre-fix pin suite (the tail containednode:1at revision 2 andview.removeat revision 3); after the fix,replay_after_last_graph_removal_does_not_expose_a_newly_hidden_pinpassed on dev-02 through build-slot (1 passed, 0 failed, exit 0). Workspacecargo fmt --all -- --checkalso passed. Green log:/home/kayg/.cache/codex-scratch/j33-mesh-pins-258/evidence/p1-replay-green.log.J33 continuation starting from mesh-pins-258-v2 at
9696f3810, rebased on origin/dev57491e918. I have re-read the crash-safety brief, repository contract, D183/D248/D312, the complete issue history and J9's findings.md. The four regressions are present and their original round-two red receipts are on #258; I am separating private-state cleanup from no-graph cleanup and clock validation, then will measure/reduce static growth and run the assigned gates.J33 R2 P2 fix — private state after removing one graph view: commit
f96bd1773reports private-state removal as a reconciliation change. That makes reconcile_at save/checkpoint the document instead of discarding the in-memory cleanup while the other graph remains. The J9 regression was red at the pre-fix head (reported above); the exact focused test now passes on dev-02 through build-slot: 1 passed, 0 failed, 477 filtered out. cargo fmt --all -- --check passed. Evidence: /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/private-cleanup-green.logJ33 R2 P2 fix — private coordinates after the final graph view is removed: commit
4324b3918makes events reconcile documents containing even when no graph layout remains. That path removes private state without reading Mesh inventory, then saves a snapshot; the deleted view cannot restore it, so retaining it until a timer/read after the 30-day deadline is unnecessary. The J9 regression reproduced onf96bd1773with and still persisted at the boundary. After the fix, final-view retention, P1 stale-reader replay, and one-of-two-view cleanup each pass on dev-02 through build-slot (1/1 each); cargo fmt --all -- --check passes. Evidence: /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/p2-final-view-green.logCorrection to my previous comment: shell quoting stripped the literal private-state field names. It should read: commit
4324b3918makes events reconcile documents containing the _mesh field even when no graph layout remains. The J9 regression reproduced onf96bd1773with views: [] and _mesh.mesh["node:1"] still persisted at the retention boundary. After the fix, final-view retention, P1 stale-reader replay, and one-of-two-view cleanup each pass on dev-02 through build-slot (1/1 each); cargo fmt --all -- --check passes. Evidence: /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/p2-final-view-green.logJ33 R2 P2 fix — clock rollback retention: commit
c8a78951dvalidates each dormant since value against the server time supplied to reconciliation. A future value is expired immediately; treating it as zero elapsed time extends retention by the prior clock skew, while clamping to corrected now would restart a full retention window. The J9 regression failed on4324b3918with the future timestamp still persisted after correction; it now passes on dev-02 through build-slot (1 passed, 0 failed, 477 filtered out). cargo fmt --all -- --check passed. Evidence: /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/future-clock-green.logJ33 progress: all four J9 fixes are committed/pushed through
c8a78951d; focused red/green receipts for the three P2 fixes and the P1 fix are recorded above. The compute01 base/head size-attribution script and the dev-02 focused pin/Mesh suite are both queued through their build-slot wrappers because all machine slots are occupied. Logs are outside the checkout at /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/size-attribution.log and /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/focused-tests.log. Next: collect attribution, cut the measured growth, then run perf-run and the final fast gate.Focused-suite finding after
c8a78951d: 14 pins_v2 tests pass, 4 fail. The failures are in stable_host_pin_survives_rename_and_ten_day_visibility_loss, scoped_role_narrowing_and_restoration_keep_host_and_tag_coordinates, two_devices_retries_and_visibility_changes_converge_without_resurrection, and the 10,000-host measurement. The test fixture uses NOW=1_800_000_000, while those paths call events(), which reconciles with the VM's real wall clock; the new future-since validation therefore sees the test's injected time as a rollback. The dedicated clock-rollback regression passes. I am aligning those tests' reads with the fixture clock and will rerun the suite; production behavior is unchanged.J33 follow-up: the 4 failures after
c8a78951dwere caused by mixed test clocks. On dev-02, the fixed fixture time NOW=1,800,000,000 was about 75 days ahead of server time (1,793,481,588); events() correctly uses server time, while those retention tests had injected NOW. I kept events()-based reads for normal tests, read persisted projections only after explicit reconcile_at(NOW) calls, and changed the two-device test to trigger visibility reconciliation through events() on the same clock as its pin writes. J9 regression bodies and production clock behavior are unchanged.Evidence: the adjusted pin suite on dev-02 through build-slot passed 18/18 with cargo fmt --check clean. The focused two-device test passed 1/1. Test-only commit
b644a673fis pushed on mesh-pins-258-v2.J33 progress on
mesh-pins-258-v2atb644a673f: the clock-fixture correction is pushed. Dev-02 checks are green: pins_v2 18/18; canvas-store pin tests 5/5; tag identity 2/2; Mesh plugin 26/26; canvas plugin 15/15; tracer Mesh/model 104/104; protocol 30/30; TypeScript check clean.Compute01 size attribution remains queued through build-slot for the aarch64 base because all four slots are busy. The x86 base artifact measured 21,489,448 bytes under the rebased Rust 1.99 shell, 57,976 bytes above the historical 21,431,472-byte cap. This is a baseline/toolchain discrepancy; base/head attribution is still in progress, and the job remains queued. Log: /home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/size-attribution.log.
J33 R2 progress on
mesh-pins-258-v2atb644a673f: the four J9 fixes remain committed and pushed. Dev-02 pin/Mesh validation is green: pins_v2 18/18; canvas-store pins 5/5; tag identity 2/2; Mesh plugin 26/26; canvas plugin 15/15; tracer Mesh/model 104/104; protocol 30/30; TypeScript check clean.Compute01 size attribution is still alive in
build-slotand waiting behind the shared four-slot limit. The freshorigin/devx86 image is 21,489,448 bytes with the Rust 1.99 dev shell, 57,976 bytes above the historical D243 cap. The base/head comparison, aarch64 row and symbol diff are still pending; I have not changed the cap. Log:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/size-attribution.log.J33 size-reduction work in progress is pushed at
5e900d8fc. Reconciliation now sends typed pin edits through the existing canvas reducer instead of constructing a temporary JSON object for each edit; persisted and wire JSON remain unchanged. This is a size hypothesis until the base/head symbol comparison completes.The targeted server pin, canvas plugin and Mesh plugin tests are queued on dev-02 through
build-slot; free disk is 8.8 GB, below its 25 GB threshold. Compute01's base/head attribution is still queued behind its four shared slots. Current measured row: fresh base x86_64 is 21,489,448 bytes with the Rust 1.99 dev shell. No post-change size, perf or final-gate result is claimed. Evidence logs:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/typed-pin-edits-tests.logand/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/size-attribution.log.Typed pin-edit reduction checks passed on
claude@infraternal-dev-02-stdthroughbuild-slotatd799159e2: J9 pin suite 18/18, canvas plugin 15/15, Mesh plugin 26/26. The initial compile exposed staleVec<Value>helper signatures; these were corrected before the passing run. Full output:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/typed-pin-edits-tests-rerun.log.This remains a size hypothesis until the base/head static and symbol comparison completes on compute01. Its aarch64 base is still queued behind the four shared slots; the current log has only the x86 base row.
J33 progress at
d799159e2onmesh-pins-258-v2: all four J9 fixes remain committed and pushed; pin/server, canvas and Mesh suites passed on dev-02 (18/18, 15/15, 26/26). The typedPinEditWIP routes reconciliation through the existing canvas reducer and keeps stored/wire JSON unchanged; its test rerun also passed.The matched base/head static attribution is queued through
build-sloton compute01. The current dev-shell base x86_64 binary is 21,489,448 bytes; this differs from the older 21,431,472-byte baseline, so I’m using same-toolchain measurements for the size decision. Current evidence/log:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/size-attribution.log.Next: finish base and pre-WIP attribution on both architectures, compare
d799159e2against the same base, then runscripts/verify faston compute01 and the 10,000-entry pin measurement throughperf-run. No final size or perf result claimed yet.Correction to the preceding size progress note: the 21,489,448-byte x86 value came from plain
cargo bloat, not the shippingscripts/static-cargopath, so it was not comparable to the ratcheted gate. I stopped that run before any head artifact was built. The replacement comparesscripts/static-cargo buildartifacts from base57491e918and headd799159e2, withnm -S --size-sort, on both architectures. No size conclusion is claimed until that matched run finishes.Matched size progress:
scripts/static-cargo buildonorigin/dev57491e918produced an x86_64 stripped static binary of 21,440,296 bytes with Rust 1.99.0. That is 8,824 bytes above the historical x86 cap 21,431,472, so the fast size check already has a base discrepancy; the cap is unchanged. Base aarch64 and headd799159e2on both arches remain queued through compute01build-slot. Exact-build log and symbol artifact path:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/size-attribution.log.J33 size-attribution retry on
mesh-pins-258-v2atd799159e27dc4a0e4cd51c41a0498acc47e8eb68, based onorigin/dev57491e918c91fbf44dd5b318da168e1b4ef40310.Correction: the matched
scripts/static-cargobase x86_64 image is 21,440,296 bytes, 8,824 bytes above the historical D243 ceiling of 21,431,472. The earlier 21,489,448 figure was from plaincargo bloatand was not a comparable artifact. The cap is unchanged; a baseline gate failure still needs confirmation on unmodifiedorigin/devif the final gate hits it.No J33 size process was active on compute01. I restarted base / pre-typed-edit / current-head attribution for x86_64 and aarch64, including the pinned
scripts/auth-toolchainZig setup and one target directory. The run is queued throughbuild-slotat position 10. No head-size, final-gate, or perf result is claimed yet. Runner:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/size-attribution-runner.sh; log:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/matched-size-attribution-run.log.J33 R2 progress:
mesh-pins-258-v2remains clean and pushed atd799159e27dc4a0e4cd51c41a0498acc47e8eb68on base57491e918c91fbf44dd5b318da168e1b4ef40310. Dev-02 pin/Mesh test results remain green as recorded above.Compute01 matched attribution is still queued through
build-slot(currently position 6, five live tickets ahead; all four slots occupied). No J33 static build has started; free disk is about 174 GB. The runner now checks the pinned Zig toolchain per source, cleans only affected release packages when switching base / pre-WIP / head, reuses the previously matched base x86 artifact by SHA, and records nm symbol tables for both targets. Logs and scripts remain under/home/claude/.cache/codex-scratch/j33-mesh-pins-258/.Next: collect the two-architecture size table and symbol breakdown, then run
scripts/verify fastand the 10,000-entry perf-VM measurement if D243's stop threshold permits. No final size, gate, or perf result is claimed.Correction to the size-attribution status: the first queued attempt acquired compute01 slot 2/4, then exited before a build because the
nix develop -c build-slot bash -lc …nesting reset PATH in the login shell (rustc: command not found). No static build started. The build-slot wrapper removed its ticket and released the slot; the compute01 worktree is clean and restored tod799159e27dc4a0e4cd51c41a0498acc47e8eb68.The launch now exports the job
CARGO_TARGET_DIRand build settings before Nix, then runsbuild-slot nix develop -c bash -c …so the Nix toolchain PATH survives. I have requeued the matched base / pre-WIP / head matrix; the failed attempt remains in/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/matched-size-attribution-run.log. No size result is claimed.J33 round 2 progress on
mesh-pins-258-v2atd799159e27dc4a0e4cd51c41a0498acc47e8eb68, based on the task's pinned57491e918c91fbf44dd5b318da168e1b4ef40310.The four J9 fixes and typed
PinEditsize-reduction WIP are pushed. Dev-02 rerun evidence is green: pins 18/18, canvas 15/15, Mesh 26/26 (/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/typed-pin-edits-tests-rerun.log).Compute01's matched base / pre-WIP / head static attribution remains queued via
build-slot; its live ticket is now position 2 with one older ticket ahead. No new static artifact or size conclusion is available yet. The matched x86 base artifact remains 21,440,296 bytes, 8,824 over the historical 21,431,472 cap; the cap is unchanged. Next: finish both architectures and nm diffs, then run the requested fast gate and perf-VM measurement if D243's stop line allows.Size-attribution method correction for J33: the first matched run completed the unstripped base aarch64 build and symbol table, then stopped because the host GNU
stripcould not recognize that architecture. It produced no aarch64 size row; the unstripped artifact and nm data are preserved.I verified LLVM
llvm-strip21.1.8 handles the aarch64 artifact. On the same base x86 image, LLVM strip measures 21,439,960 bytes versus GNU strip's 21,440,296 bytes, a 336-byte tool difference. The rerun therefore uses one LLVM stripper for both architectures and reuses the completed base aarch64 artifact. The historical ceilings remain unchanged. Rerun log:/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/matched-size-attribution-run3.log.J33 progress: branch
mesh-pins-258-v2remains pushed atd799159e27dc4a0e4cd51c41a0498acc47e8eb68on the pinned57491e918c91fbf44dd5b318da168e1b4ef40310; dev-02 results remain pins 18/18, canvas 15/15, Mesh 26/26.The corrected LLVM-strip attribution runner is
/home/claude/.cache/codex-scratch/j33-mesh-pins-258/size-attribution-runner.sh; launch log is/home/claude/.cache/codex-scratch/j33-mesh-pins-258/evidence/size/matched-size-attribution-run3.log. Its build-slot ticket is still live at position 12. The completed base aarch64 unstripped binary and nm table are preserved and will be reused. The guarded final-gate/release-test-binary job is queued after it and exits without building if either architecture exceeds the 64 KiB stop line. No final sizes or gate/perf result are available yet.Starting J47 round-2 review. Review branch:
review-mesh-pins-258-r2, based on currentorigin/devf4b61cd6c3f52078cad7573c5367d7a6e75f84f0; target under review:mesh-pins-258-v2d799159e27dc4a0e4cd51c41a0498acc47e8eb68(original base57491e918). Rebase check completed cleanly: the target's 22 commits replayed onto current dev without conflicts. The target worktree remains untouched. I’m checking the four J9 findings and the same privacy, retention, clock, concurrency, and encoded-size boundaries, then will run the assigned remote gates and perf measurement.J47 round-2 finding (reproduced on dev-02 through build-slot):
P2 — Removing the last graph does not retire its private pin state before view-ID reuse. If a member loses visibility, reads once so the pin moves into private retention, removes the final graph, then re-adds a graph with the same ID before any read and regains visibility, the next read restores the old pin.
Regression
mesh_api_tests::pins_v2::removed_final_graph_does_not_resurrect_private_pins_on_view_id_reusefailed atpins_v2.rs:279: expected{}, got{"node:1":{"x":-600.0,"y":320.0}}. The removal transaction checkpoints the public log, but leaves the dormant_mesh.meshentry; the no-graph cleanup only runs on a later read. Review branchreview-mesh-pins-258-r2, current heada9531fec5; the reproduction is being committed there.The rebase onto
origin/devf4b61cd6cis clean. I’m continuing with the x86 gate, both architecture size comparisons, and the perf-VM inventory measurement.J47 progress: the regression is now committed and pushed to
review-mesh-pins-258-r2at1378b4a24; the target remains unchanged. The x86 build-slot run is queued at position 7. Its log is/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/size-fast-r2.log.The aarch64 focused run passed
pins_v218/18, tag identity 2/2, Mesh 26/26, and canvas 15/15. The 10,000-entry test reported on that shared build host: pin initialization 143.856 ms, unchanged inventory scan 98.542 ms, visibility-loss reconcile 178.704 ms. Those timings are only build-host smoke numbers; the perf-VM measurement is still pending.Additional evidence for the round-2 P2: this ID reuse is the normal product path.
apps/tracer/src/canvas/mesh/offer.ts:15-24,31-34removes the built-inmeshview when access becomes unavailable and addsmeshView(...)again when access returns;meshViewalways uses IDmesh(view.ts:9-10). So a quick grant loss/regrant can trigger the same sequence without a hand-crafted client. The old position then returns after access is restored, even though the user’s prior view removal should have retired its private state.Correction to my previous product-path note:
offerMeshViewremoves and recreates the local Mesh view with IDmesh, but its revoke branch does not callcx.store.changed(); I cannot claim that this path by itself sends a persistedview.remove. It confirms the built-in ID is reused, not the ordering of persisted layout operations. The server regression independently reproduces the publicview.removethenview.addsequence with no intervening read. The finding is that a persisted final-view removal is not an atomic cleanup boundary: a same-ID add can race the lazy no-graph cleanup and restore state the fix says is unrestorable.J47 round-2 P3 gate finding:
scripts/verify faston the rebased target reports thefmtrow failed.cargo fmt --all --checkshows a formatting diff incrates/plugins/canvas/src/reducer.rs:325around the newPinEdit.positionvalidation. No implementation change was made on the target. Log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/size-fast-r2.log.J47 round 2 progress (2026-11-01): review branch
review-mesh-pins-258-r2is now at9efe8d051; targetd799159e2is untouched. The rebase check matched all 22 commits one-to-one onorigin/devf4b61cd6c. J9's four round-one regressions pass on dev-02 (pins_v218/18, tag identity 2/2, Mesh 26/26, Canvas 15/15).The new P2 regression is reproduced on the target: removing the final graph then re-adding its view ID before a read restores the private pin. Test commit
1378b4a24; expected{}, got{"node:1":{"x":-600.0,"y":320.0}}. The test log is/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/final-view-reuse-red.logon dev-02. The candidate fast gate is still active on compute01 (PID 3616466); log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/size-fast-r2.log. Next: collect the final gate and both size deltas, then run the 10,000-entry measurement viaperf-runand post the final verdict. D243 size is report-only per the owner's direction.J47 round 2 update: perf-01 measurement is complete and recorded on review branch
review-mesh-pins-258-r2at1945c014c. The candidate server test binarya9531fec5passed the 10,000-entry test (1/1): initialization 344.706 ms, unchanged inventory scan 226.047 ms, visibility-loss reconciliation 363.812 ms; persisted size 409,064 B.perf-runsnapshots were quiet before and after; steal was 7/1160 jiffies. Evidence is under/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/perf/on perf-01.The x86
scripts/verify fastprocess on compute01 remains active (PID 3616466); current output is in/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/size-fast-r2.log. Candidate size rows and final gate output remain pending. D243 size is report-only per the owner's direction. The target branch remains untouched.J47 progress: review branch
review-mesh-pins-258-r2is pushed at219aaf7a1; targetmesh-pins-258-v2remains unchanged atd799159e2. The current-dev rebase is clean:range-diffmaps all 22 target commits one-to-one ontof4b61cd6c.The J9 regressions are green on dev-02 at the implementation head: pins_v2 18/18, tag identity 2/2, Mesh 26/26, Canvas 15/15. The new P2 test is red on the target: removing the final graph, regranting access and reusing its view ID before any read restores its dormant position.
The compute01 fast gate finished with
VERIFY_EXIT=1: fmt failed, two oversized Mesh subscription assertions receivedmesh unavailableinstead ofplugin unavailable, and the script still reports its old D243 size cap as failed. Sizes are 21,527,152 B (+83,328) x86_64 and 19,700,088 B (+70,848) aarch64; D243 is report-only by the owner's 2026-11-01 direction. Full log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/size-fast-r2.log.The 10,000-entry perf-run is complete: writer-lock initialization 344.706 ms, unchanged inventory scan 226.047 ms, visibility-loss reconciliation 363.812 ms; evidence is under
/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/perf/. I am finishing the current-dev baseline run for the two refusal assertions, then I will post the final P0-P3 findings and verdict.J47 update: the focused comparison of the two refusal assertions against unmodified
origin/devf4b61cd6cwas held at compute01 queue position 8 for over 20 minutes. I canceled only that queued ticket; the candidate checkout was restored toa9531fec5. The architecture-neutral baseline test is now running on the assigned dev-02 test VM throughbuild-slot(PID 1466357). Log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/current-dev-refusal-tests-dev02.log. Review head remains219aaf7a1; the target remains unchanged.J47 baseline-check update: the first dev-02 launcher exited before compilation because
nix developran outside the worktree; it produced no test result. I corrected the launcher to run from/home/claude/worktrees/review-mesh-pins-258-r2and restarted thef4b61cd6ccomparison throughbuild-slot(PID 1469743). Retry log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/current-dev-refusal-tests-dev02-retry.log. The earlier failed launcher log is retained separately. Candidate restoration is part of the script.Correction to the baseline progress: the first successful dev-02 invocation selected
0 testsbecause its filter omitted theauth::testsmodule; its exit 0 is not a result. I corrected it to the exact qualified path from the candidate gate (auth::tests::socket_tests::review_subscription_refusal) and restarted throughbuild-slotat PID 1510225. Exact-run log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/current-dev-refusal-tests-dev02-exact.log. The candidate worktree is restored by the launcher after the run.Baseline comparison update: the exact module filter is correct, but running only
-p infraternal-serverwith its default features does not match thecargo test --workspacefeature union used by the fast gate. The current-dev package-only run selected all three tests but failed two with the reverse expectation (remote disabled); it is not a valid comparator. I am rerunningf4b61cd6cwith--features remote, which is enabled by the workspace's defaultinfraternalpackage, throughbuild-sloton dev-02 (PID 1517527). Log:/home/claude/.cache/codex-scratch/j47-mesh-pins-258-r2/evidence/current-dev-refusal-tests-dev02-workspace-features.log.J47 round-two review complete. Verdict: request changes. Counts: P0=0, P1=0, P2=1, P3=2.
Review branch
review-mesh-pins-258-r2is pushed at7ef6ea156. The targetmesh-pins-258-v2remains unchanged and clean atd799159e2.Round-one findings: all four J9 regressions pass on the current candidate:
pins_v218/18, tag identity 2/2, Mesh 26/26, Canvas 15/15. The replay checkpoint, final-view retention, future-sinceexpiry, and sibling-view cleanup fixes are covered by9696f3810,4324b3918,c8a78951d, andf96bd1773respectively.P2 — private pins return after final graph-view ID reuse. On the rebased candidate, removing the final graph, restoring access, and adding a graph with the same ID before any read restores the dormant pin. The regression committed on this review branch,
removed_final_graph_does_not_resurrect_private_pins_on_view_id_reuse, fails with expected{}and got{"node:1":{"x":-600.0,"y":320.0}}. The red test log is attached.The requested risk sweep is covered by the passing
pins_v2cases: hidden and unknown pin guesses receive the same opaque refusal; snapshots and replay cursors after visibility loss contain no hidden identity and match the deletion case; the 10-day and exact 30-day retention boundaries and future timestamps after clock rollback are exercised; concurrent device writes/retries converge; 10,000 pins fit the document/frame bounds and multi-view retention admission rejects before persisted state exceeds its cap.P3 — two gate regressions.
cargo fmt --all --checkreports formatting atcrates/plugins/canvas/src/reducer.rs:325. Two refusal tests expectplugin unavailablebut receivemesh unavailable; both stop at that assertion before checking later subscription lifecycle behavior. The feature-matched refusal tests pass 3/3 on unmodifiedorigin/devf4b61cd6cwith--features remote, confirming the candidate regressions. No separate lifecycle defect is established.Rebase:
git range-diff 57491e918..d799159e2 f4b61cd6c..a9531fec5matched all 22 commits one-to-one; the rebased candidate's merge base isf4b61cd6c.Gate:
scripts/verify fastran on compute01 at rebased candidatea9531fec5. Verbatim final summary excerpt (full log attached):Both binaries are static (
PT_INTERP: absent). The static-build row reports the legacy D243 cap failure; the owner removed those caps on 2026-11-01, so sizes are report-only. The two actionable gate failures are fmt and the refusal assertions. TypeScript checks were not reached after the Rust gate failed.Size: x86_64 21,527,152 B (+83,328 B); aarch64 19,700,088 B (+70,848 B).
10,000-entry measurement: on perf-01 through
perf-run, the test passed 1/1. Input 369,089 B; snapshot 409,141 B; persisted document 409,064 B. Pin initialization under writer lock: 344.706 ms; unchanged inventory scan without writer lock: 226.047 ms; visibility-loss reconciliation: 363.812 ms. No process exceeded 5% CPU before or after; steal was 7/1160 jiffies. Measurement and before/after snapshots are attached.Attachments include the final findings, round-one green tests, the new red regression, current-dev baseline, complete fast-gate log, and perf evidence. Issue remains open.
Starting J59 round 3 on branch mesh-pins-258-v2-j59. Starting tip:
d799159e2; original base:57491e918; rebase target: origin/devf4b61cd6c, following the 22-commit one-to-one replay recorded in J47 round 2. I will reproduce the P2 and both P3s before fixing them, then measure the 10,000-entry path and run the requested gates.J59 progress (branch mesh-pins-258-v2-j59, starting tip
d799159e2). The rebase onto origin/devf4b61cd6cis clean; range-diff maps all 22 commits one-to-one, matching candidatea9531fec5.Findings traced:
The J47 P2 regression is staged test-first in this worktree. Its compute01 build-slot ticket is queued at position 12; no implementation edits have started.
J59 P2 reproduction complete on the rebased
mesh-pins-258-v2-j59candidate. The focused test ran on dev02 through~/infraternal-ops/build-slotand failed as expected:removed_final_graph_does_not_resurrect_private_pins_on_view_id_reuseexpected{}, got{"node:1":{"x":-600.0,"y":320.0}}. Log:/home/claude/.cache/codex-scratch/j59-mesh-pins-258/logs/p2-red.log.The remove transaction reconciles pins before
view.remove, then checkpoints without retiring that view's_meshstate; cleanup only happens on a later read. I’m fixing removal as the view-incarnation boundary and will rerun this exact test before proceeding.J59 P2 fix complete. Removing a graph view now removes that view's
_meshstate in the same canvas transaction, after visibility reconciliation and before the removal checkpoint. A reused ID therefore starts without the old incarnation's private pins; sibling graph state remains untouched.Red-to-green evidence on dev02, through
build-slot: the exact regression failed before the fix with expected{}, got the savednode:1position, then passed after the fix (1 passed, 0 failed; 752 filtered out). Logs:/home/claude/.cache/codex-scratch/j59-mesh-pins-258/logs/p2-red.logandp2-green.log.J59 reproduced the refusal ordering regression on the candidate (dev02,
--features remote, throughbuild-slot).review_subscription_refusalis 1 passed, 2 failed: both oversized tests gotmesh unavailablewhere the existing contract expectsplugin unavailable; saturation still passes. Log:/home/claude/.cache/codex-scratch/j59-mesh-pins-258/logs/refusal-red.log.Cause: Canvas raised
PluginDescriptor.max_frame_lenfrom the shared 64 KiB subscription-input bound toMAX_DOCUMENT + 4096to carry larger layout frames. The dispatcher also used that outbound limit to admit opaque subscription filters, so the filters passed the shared refusal branch and reached Mesh's plugin-specific refusal. The prior behavior is exercised by these existing tests and J47's feature-matchedorigin/devrun passed 3/3; there is no documented change to the refusal response. I’ll keep subscription input bounded independently of larger Canvas event frames and preserve the tests.J59 P3 refusal-order fix complete. Subscription ingress now keeps its 64 KiB frame bound independently of provider
max_frame_len, which can also bound large emitted Canvas snapshots. Oversized requests therefore still hit the shared multi-provider refusal; Canvas keeps its larger frame capacity for layout traffic. No refusal tests were changed because the priorplugin unavailablebehavior is covered by the existing tests and the feature-matchedorigin/devbaseline.Red-to-green evidence on dev02:
review_subscription_refusalchanged from 1 passed / 2 failed (mesh unavailablevsplugin unavailable) to 3 passed / 0 failed. Logs:/home/claude/.cache/codex-scratch/j59-mesh-pins-258/logs/refusal-red.logandrefusal-green.log.J59 P3 formatting fix complete. The original candidate failed
cargo fmt --all --checkatcrates/plugins/canvas/src/reducer.rs:325exactly as J47 reported. I applied rustfmt's expected line wrap; the same command now exits 0 on dev02. Red output is in/home/claude/.cache/codex-scratch/j59-mesh-pins-258/logs/fmt-red.log; the green log is empty atfmt-green.log.J59 performance regression test is red on the unchanged writer path: the 10,000-host initialization calls inventory once while holding the writer lock (
inventory_under_writer = 1, expected 0). The test fails on that assertion before the visibility-loss assertion. Log:/home/claude/.cache/codex-scratch/j59-mesh-pins-258/logs/perf-lock-red.log.J47's
perf-runbaseline measured initialization at 344.706 ms with inventory under the writer lock, unchanged inventory scan at 226.047 ms, and visibility-loss reconciliation at 363.812 ms. I’m moving scans to a read snapshot and will reuse them only whilemesh_state.revisionstill matches in the immediate writer transaction; a changed revision will force a fresh scan.J59 progress — branch
mesh-pins-258-v2-j59, clean rebase basef4b61cd6c, current committed headf06c6f248._meshstate in the same transaction, after visibility reconciliation and before checkpointing.removed_final_graph_does_not_resurrect_private_pins_on_view_id_reusepasses.reducer.rs:325, are applied; remotecargo fmt --all -- --checkpasses.plugin unavailable. Both reviewed refusal tests pass in the feature-matched run.perf-runcomparison is still pending.Dev02 evidence:
pins_v219/19, Canvas store tests 9/9, refusal suite 6/6, revision-fence test 1/1. Compute01scripts/verify fastis queued throughbuild-slot; log:~/.cache/codex-scratch/j59-mesh-pins-258/logs/verify-fast.log.J59 progress update — performance slice committed and pushed as
51cc2816donmesh-pins-258-v2-j59(WIP checkpoint; base remainsf4b61cd6c). Compute01 is on this exact commit. The dev02 functional and format evidence is in my previous update.scripts/verify fastis still queued throughbuild-slot; its log remains~/.cache/codex-scratch/j59-mesh-pins-258/logs/verify-fast.log. I will finalize the commit message and post the perf-01perf-runcomparison after the gate and benchmark complete.Correction to the previous progress note: the checkpoint is now
331de6ad6(amended only to correct the reconciliation snapshot doc comment; no behavior or test changes). Compute01'sscripts/verify fastremains queued at position 9 viabuild-slot.Compute01 gate is still queued in
build-slotat position 9; at the latest check the filesystem had 12 GB free, below the 25 GB start threshold, and this J59 gate has not started. I’m leaving it queued for shared capacity rather than bypassing the slot or removing another job’s data. Log:~/.cache/codex-scratch/j59-mesh-pins-258/logs/verify-fast.log.Compute01 clippy found
used_underscore_bindingatcanvas_store.rs:191: the writer guard was explicitly dropped before retry. I renamed that guard towriterand amended the WIP checkpoint; current branch head isb8b8741587070d73f9802cc5c4a6006b0040fdcf. The in-flight gate is still finishing against its prior checkout (331de6ad6); I will rerunscripts/verify faston the corrected head. Log:~/.cache/codex-scratch/j59-mesh-pins-258/logs/verify-fast.log.J59 progress — performance change is now finalized and pushed with lease as
83ac55afaonmesh-pins-258-v2-j59. The previously queued compute01 gate is running against stale checkpoint331de6ad6; I will let it finish, then fetch the final head and rerunscripts/verify fastthrough build-slot. The 10,000-entry perf-01 before/after run is next; current evidence is the dev02 smoke comparison in the prior update.J59 progress — final branch head is
83ac55afa2cb64d733f808bc8f338219985b1e10onmesh-pins-258-v2-j59, rebased onf4b61cd6c. The stale gate on331de6ad6completed: tests, fmt, SSH/shim fixtures, cargo-deny and architecture checks passed; clippy failed only on the_writerguard warning fixed in the current head. Static-size checks reported x86_64 21,539,120 B (+95,296 B) and aarch64 19,710,712 B (+81,472 B) against the legacy caps; these are report-only per the brief. The final gate is queued through build-slot on compute01 (log:~/.cache/codex-scratch/j59-mesh-pins-258/logs/verify-fast-final.log). The 10,000-entry binary was copied from that run; its only source difference from the final head is the guard variable rename (no behavior or test changes). Theperf-runcomparison is waiting on the shared perf lock (output:~/.cache/codex-scratch/j59-mesh-pins-258/evidence/perf-after/measurement.log).J59 performance finding complete. The 10,000-entry test passed 1/1 through
perf-runoninfraternal-perf-01-backup01; the before/after snapshots report no process above 5% CPU and the run saw 4/1219 steal jiffies. Evidence:/home/claude/.cache/codex-scratch/j59-mesh-pins-258/evidence/perf-after/measurement.logand pairedperf-run-20261101T130747-157254.before.txt/.after.txt.Comparison with J47's
perf-runbaseline: initialization writer-lock time 344.706 ms -> 89.513 ms (74.0% lower; current initialization total 356.040 ms); unchanged inventory scan 226.047 ms -> 233.316 ms (3.2% higher, still outside the writer lock); visibility-loss reconciliation total 363.812 ms -> 295.311 ms (18.8% lower; current writer-lock time 124.072 ms). Input/snapshot/persisted sizes remain 369,089 / 409,141 / 409,064 bytes. The measured binary was from stale checkpoint331de6ad6; its only code difference from current head is the_writertowriterlocal-name fix, with no behavior or test changes. The corrected final gate on83ac55afais still queued on compute01.J59 gate queue update: compute01 fell to 18 GB free and build-slot would not start at its 25 GB threshold. After the stale run completed, I removed only J59's 36 GB
~/worktrees/j59-mesh-pins/targetcache; compute01 now has 51 GB free. The final gate is requeued on the unchanged final head83ac55afa2cb64d733f808bc8f338219985b1e10and will rebuild into that target, which will be deleted after verification. Current log:~/.cache/codex-scratch/j59-mesh-pins-258/logs/verify-fast-final.log.Starting J59b in worktree , branch . Checkout starts at ; current is . I found J59's pushed progress branch at ; I will carry its fixes onto current dev in this worktree, reproduce each regression red first, split the P2, refusal, format, and lock-cost changes into atomic commits, then measure 10k before/after, run the final gate on compute01 through build-slot, and clean up targets. Estimate: 3–4 hours including shared VM queue time.
Starting J59b in worktree ~/Developer/Worktrees/infraternal-j59b, branch mesh-pins-258-v2-b. Checkout starts at
d799159e27; current origin/dev isa26615c50e. I found J59 progress branch mesh-pins-258-v2-j59 at83ac55afa2. I will carry its fixes onto current dev in this worktree, reproduce each regression red first, split the P2, refusal, format, and lock-cost changes into atomic commits, then measure 10k before/after, run the final gate on compute01 through build-slot, and clean up targets. Estimate: 3-4 hours including shared VM queue time.Correction: the preceding J59b start note was malformed by shell interpolation. Use the complete follow-up immediately below as the branch, base, plan, and estimate. No repository work was done before posting the scoped plan.
Rebase finding: current origin/dev uses 0031_terminal_startup_hints.sql, while the Mesh tag identity migration also used version 0031. The feature-matched test on dev-02 failed red through build-slot: enrollment::migration_tests::canvas_layout_migration_upgrades_production_v27_and_fresh_schema_in_order compared [1..31, 31] with [1..31] (0 passed, 1 failed, 757 filtered). I will renumber the Mesh migration to 0032 and update the migration-chain assertions so deployed 0031 remains unchanged.
J59b progress: the 26 J59 commits replay one-to-one onto current origin/dev
a26615c50e. I added and pushed060ce633bto resolve the new migration-version collision: Mesh tag identity is now 0032, and production/fresh-chain assertions include current dev migration 0031. The red migration-chain test reproduced the duplicate [1..31,31] sequence; the corrected feature-matched check is included in the final compute01 gate, queued through build-slot.J59b progress at
060ce633b: source and migration updates are pushed on mesh-pins-258-v2-b. The required scripts/verify fast run is detached on compute01 through build-slot and is waiting behind other queued jobs; its log is /home/claude/.cache/codex-scratch/j59b/logs/verify-fast.log. I will wait for completion on this head before updating the requested mesh-pins-258-v2 branch.Compute01 gate launcher correction: the first attempt exited at scripts/verify line 108 with
bun: command not foundand VERIFY_EXIT=127. The nested login shell reset the Nix dev-shell PATH, so this is not a gate result. I am switching the launcher to a non-login shell inside nix develop and will rerun scripts/verify fast on060ce633bthrough build-slot.J59b queue update: corrected scripts/verify fast is waiting at build-slot position 5 on compute01, with four jobs ahead; the flake PATH check confirmed bun and cargo are present under the non-login nix develop shell. The run is detached at
060ce633band its log is /home/claude/.cache/codex-scratch/j59b/logs/verify-fast-final.log.J59b gate finding on compute01 at
060ce633b: clippy reportstoo_many_lines(103/100) inten_thousand_visible_hosts_can_initialize_pins_within_wire_and_storage_bounds, plus twocast_precision_losserrors for its nanosecond counters at lines 687 and 690. I’m extracting the 10k inventory setup and formatting millisecond output from integer microseconds; the whole gate has continued into workspace tests.J59b clippy fix committed and pushed as
bc8ee023d911a5ed65e4a610cf442c701a731963. It extracts the 10k inventory fixture setup and formats timings from integer microseconds. The old compute01 fast run is still compiling tests on060ce633b; it is not the final result. The correctedscripts/verify iterateis detached on dev-02 through build-slot (PID 3970095), log/home/claude/.cache/codex-scratch/j59b/logs/verify-iterate.log; after it finishes I will run the final fast gate on compute01.Correction: the first dev-02
iteratelauncher acquired a slot but exited before running the gate becausenix developstarted in/home/claude, which has noflake.nix. It produced no verification result. Log:/home/claude/.cache/codex-scratch/j59b/logs/verify-iterate.log. I am relaunching with the worktree as the Nix working directory.J59b
scripts/verify iterateon dev-02 atbc8ee023dreports fmt, clippy, compile-out, SSH helper, fixtures, cargo-deny and architecture PASS. The test row exits 101 oninfraternal/tests/cli_envelope.rs::bare_infraternal_is_the_overview_and_points_to_help: expected exit 0, received 5 (the other 7 tests in that binary pass). This CLI case is outside #258. I am reproducing the exact test on unmodified currentorigin/devbefore classifying it.Cross-check: the pre-fix compute01 workspace run at
060ce633bran the samecli_envelopebinary and passed all 8 tests, includingbare_infraternal_is_the_overview_and_points_to_help. So the dev-02 failure has not reproduced on compute01. The exact unmodified-origin/devcomparison is queued on dev-02 through build-slot; no #258 source change is being made for this unrelated test.The pre-fix compute01 fast run completed on
060ce633b: fmt, tests, SSH/shim fixtures, cargo-deny, architecture, and static builds passed; clippy was the only failed row. That run passed all 8cli_envelopetests. The compute01 worktree is now detached atbc8ee023d911a5ed65e4a610cf442c701a731963; finalscripts/verify fastis detached through build-slot (PID 3322482), log/home/claude/.cache/codex-scratch/j59b/logs/verify-fast-final.log. The dev-02 comparison of its isolated CLI test onorigin/devremains queued.Baseline comparison complete: the exact
bare_infraternal_is_the_overview_and_points_to_helptest fails on untouchedorigin/deva26615c50e76ed86f36d25aa094283cf840d5320on dev-02 through build-slot with the same assertion (left: Some(5), expectedSome(0)). Log:/home/claude/.cache/codex-scratch/j59b/logs/cli-baseline-dev.log. This is a pre-existing dev-02 test/environment failure; the same binary test passed 8/8 in the compute01 run. No unrelated CLI change is included.J59b rebase and final gate update. Rebased the 28 J59 commits onto current origin/dev
65d9861914e8cd4a734d533d64ed1f4ea5c34119; the branch head isd1e37648679d97373b20819cc8d9bbee463bf049. Two test-only conflicts incrates/plugins/canvas/src/model.rswere resolved by retaining both the new session-name pin test and the Mesh 10k/dormant-state tests.git diff --check origin/dev...HEADis clean. The compute01scripts/verify fastrun is queued through build-slot; log:/home/claude/.cache/codex-scratch/j59b/logs/verify-fast-rebased.log.J59b queue update: the final compute01 gate remains queued via build-slot (runner PID 3573255; log
/home/claude/.cache/codex-scratch/j59b/logs/verify-fast-rebased.log).build-slot --statusstill shows all four compute01 slots occupied and 46 GB free. No gate output is available yet; I am waiting for the scheduler to start the run.Finished J59b. Updated
mesh-pins-258-v2with a lease after the compute01scripts/verify fastgate passed. Final head:d1e37648679d97373b20819cc8d9bbee463bf049(rebased on65d9861914e8cd4a734d533d64ed1f4ea5c34119). The J59b compute01 targets were removed after the run.Gate output from compute01, verbatim summary (
VERIFY_EXIT=0):Static sizes: x86_64 21,741,456 bytes, +297,632 vs baseline 21,443,824; aarch64 19,875,432 bytes, +246,192 vs baseline 19,629,240. Both are report-only under D243.
10,000-entry
perf-runcomparison on perf-01: initialization writer-lock time 344.706 ms → 89.513 ms (−74.0%); unchanged inventory scan outside the lock 226.047 ms → 233.316 ms (+3.2%); visibility-loss reconciliation 363.812 ms → 295.311 ms total (−18.8%), with 124.072 ms in the writer lock after the change. The measured binary differs from the J59 source head only by the guard variable rename; the migration and timing-formatting follow-ups do not change the measured path.Review fixes carried forward: graph-view ID reuse retires dormant pins transactionally; subscription refusal retains the shared ingress limit; formatting is clean. Red-to-green evidence and the writer-lock regression measurements are recorded above in the J59 progress comments and attachments.
J75 round-3 independent review started. Detached worktree infraternal-j75 at
d1e3764867; base/current origin/dev65d9861914. Plan (about 50 minutes): read all #258 history and J47/J59/J59b evidence; inspect dormant-pin retirement, refusal bounds, revision-checked preparation and original pruning; measure pinned static-size delta against current dev on compute01, attributing growth; post numbered findings or APPROVE. Tests only to confirm a finding; no code changes intended, gate not applicable under BRIEF-COMMON.J75 progress: reviewed the full issue history, J47 findings and J59/J59b fixes. Dormant state retirement, independent subscription ingress/refusal, and formatting fixes are present; the raw
d1e376486head-gate log confirms all reviewed regressions passed. Fresh current-dev/head static builds and x86 linker maps remain queued on compute01 (J75 worktree ~/worktrees/j75; one target ~/.cache/codex-scratch/j75/target; log ~/.cache/codex-scratch/j75/evidence/size.log). One additional concurrency hypothesis needs a focused test: reconcile_at retries on global Mesh revisions, including liveness-only changes, so steady heartbeats may prevent reconciliation from committing. A deterministic connection-release test, without a timing assertion, is prepared on review-mesh-pins-258-r3; it will run sequentially after the measurements in the same slot, with a before-writer-change control. This is not yet a confirmed finding. No implementation edits or merge.J75 measurement checkpoint: fresh shipping-recipe current dev
65d9861914is x86_64 21,642,416 B and aarch64 19,794,088 B. Fresh targetd1e3764867x86_64 is 21,741,456 B, a true current-dev delta of +99,040 B. Both source builds use Rust 1.99.0, pinned scripts/static-cargo, one target directory and the same compute01 slot. The x86 baseline map build reproduces its shipping byte size. The target x86 map, target ARM row, and the focused heartbeat-churn regression/control remain pending in the active run; no verdict yet. The build queue plus paired builds have exceeded the initial 50-minute estimate; remaining work is roughly 15–20 minutes. Log/target paths remain those in the preceding J75 update. No implementation edits or push.J75 independent review, round 3 (final). verdict: request changes. P0=0, P1=0, P2=1, P3=0.
target:
mesh-pins-258-v2atd1e37648679d97373b20819cc8d9bbee463bf049; freshly fetchedorigin/dev:65d9861914e8cd4a734d533d64ed1f4ea5c34119. review branchreview-mesh-pins-258-r3remains at the target SHA, clean, with no production changes, pushes, or merge.P2: bound retries so liveness updates cannot starve pin reconciliation.
crates/infraternal-server/src/canvas_store.rs:187(retry at line 192). whenever reconciliation needs to change pins, any Mesh revision change between preparation and the immediate transaction discards all prepared work and loops without a retry limit or fallback. the checked revision is global (canvas_store/mesh_pins.rs:90); ordinarymesh.node.observeupdates increment it even though they change only liveness/RTT (crates/plugins/mesh/src/api.rs:998, revision bump at line 1614). consequently, ongoing observations, including observations unrelated to the account's visible pins, can repeatedly invalidate cleanup after deletion or lost access.events()awaits this reconciliation atcanvas_store.rs:103, so a required cleanup can prevent a canvas snapshot from returning while observations continue. this is a progress regression, not evidence of a stale write or disclosure.evidence: attached
liveness-churn-regression.patchuses real SQLite and a one-connection release hook to put a liveness-only revision commit between preparation and writer acquisition. it revokes visibility after saving a pin, with no subsequent visibility or Canvas changes. on the exact candidate, the test fails:reconciliation never committed during 16 deterministic connection releases with liveness-only revision changes; it completed only after churn stopped. after stopping churn the same pending future finishes and the pin is pruned. the identical regression passes with the three affected source files restored from685106788, immediately before writer-lock commitcf418c5ad, retaining the candidate's migrations. no wall-clock threshold is asserted. candidate:0 passed; 1 failed; control:1 passed; 0 failed; runner:J75_RUN_EXIT=0. consider bounded optimistic retries followed by fresh reconciliation under the writer transaction, or a token scoped to mutations that can change pin visibility/identity. preserve the existing revision fences.round-2 findings: fixed. dormant state is retired transactionally on graph removal (
canvas_store.rs:473,mesh_pins.rs:29), covered byremoved_final_graph_does_not_resurrect_private_pins_on_view_id_reuse. subscription ingress uses its own 64 KiB bound (plugins.rs:65, checks at 762/780), independent of the larger Canvas event cap, and retainsplugin unavailable; the three existing refusal tests pass in the exact-head author gate. formatting also passes there. i inspected the raw J59b gate log, not only its issue summary.writer race review: no lost-update or stale-apply defect found. reconciliation checks both Canvas and Mesh revisions under
BEGIN IMMEDIATE; a mismatch rolls back and retries. initialization invalidates prepared work on a changed Canvas revision (line 348), changed Mesh revision (368 onward), or repairs (402), and recomputes before applying (419). the finding above concerns the unbounded reconciliation retry, not removal of those checks.original #258 case: the server reconciles against the authoritative unpaged, role-filtered inventory before snapshots/replay, including an empty inventory when hosts disappeared before page load. offline hosts remain inventory members. no additional pruning regression found; the deletion/access-loss, retention, identity-recreation, replay and graph-removal tests pass in the inspected exact-head gate.
static size, freshly built sequentially on compute01 with the same pinned
scripts/static-cargorecipe, Rust 1.99.0 and Zig 0.15.2:both are stripped static ELF images of the expected architecture. the old 21,443,824-byte baseline is not used for this comparison. growth is explained, report-only, with no size finding. x86 text grows 81,344 bytes: Canvas store +45,316, Mesh plugin +13,331, B-tree helpers +21,712, and smaller positive/negative changes. unwind/exception tables add 13,060, rodata 4,096, remaining sections/layout net 540. the largest new symbols are pin inventory (+15,712) and reconciliation (+10,029). matched LLD maps reproduce the shipping size; the head map image is byte-identical to the preserved shipping image. aarch64 text adds 67,456, unwind/exception tables 13,312, data.rel.ro 576. no Cargo dependency, feature, release-profile or toolchain change contributes. detailed map/section attribution and build receipts are attached.
review validation: only the focused finding-confirmation test and its control were run; no broad review gate rerun, per the task. the attached regression is an evidence patch, not a production edit. both worktrees are restored clean, the unused dev02 worktree was removed, compute01's J75 target was deleted, and all J75 runs have exited.
J59b's
scripts/verify fastat the exact target head, author gate, not a new J75 run, verbatim summary (VERIFY_EXIT=0):no new P0/P1 finding. issue remains open.
Starting the J75 P2 fix on
mesh-pins-258-v2-bat exact reviewed targetd1e37648679d97373b20819cc8d9bbee463bf049. I will add the attached deterministic liveness-churn regression and run it red, bound optimistic reconciliation retries and recompute under the writer lock on the final attempt, then run the focused test and 10k perf measurement. I will make one atomic commit, run the fullscripts/verify fastgate on compute01 through build-slot, and push the fix tomesh-pins-258-v2. Estimate: 1–2 hours plus shared VM/perf lock wait.J75 regression reproduced on the exact reviewed head
d1e37648679d97373b20819cc8d9bbee463bf049, before production edits. I applied the attached test only and ran it on compute01 through build-slot. Result:0 passed; 1 failed; 758 filtered out, exit 101, with the expected assertion:reconciliation never committed during 16 deterministic connection releases with liveness-only revision changes; it completed only after churn stopped. Log:/home/claude/.cache/codex-scratch/j59b/logs/j75-red.log. I am now implementing two optimistic attempts followed by one fresh preparation under the writer lock.J75 regression is green on compute01 after the bounded-retry fix:
1 passed; 0 failed; 758 filtered out(exit 0), log/home/claude/.cache/codex-scratch/j59b/logs/j75-green.log.reconcile_atnow keeps two optimistic snapshot/revision-fence attempts. After both are invalidated, it obtains the canvas writer mutex, startsBEGIN IMMEDIATE, then reads fresh canvas state and role-filtered Mesh inventory, reconciles, serializes, and commits in that transaction. This blocks subsequent liveness-only writers only on the fallback path while retaining both revision fences on the common optimistic path. Next: measure the existing 10k fixture on perf-run, run full verify fast on compute01, and push one atomic commit.J75 writer-lock measurement complete on infraternal-perf-01-backup01 under
perf-run(cpus 1–3, 6 GiB). The 10,000-visible-host fixture passed 1/1. Initialization writer-lock time is61.725 ms, compared with J59's89.513 ms; initialization total is310.781 ms. Unchanged inventory scan outside the writer lock is215.510 ms. Visibility-loss reconciliation is194.602 mstotal with23.752 mswriter-lock time. Input/snapshot/persisted sizes remain369,089 / 409,141 / 409,064bytes. The before/after perf snapshots report 1 steal jiffy out of 787. Evidence files are attached.Finished J75's final review fix for #258.
Head:
30f384adf9The regression passes. Reconciliation permits two optimistic revision-fenced attempts, then recomputes under the writer mutex so liveness churn cannot starve snapshots.
Gate:
scripts/verify faston compute01 through build-slot and the Nix dev shell, exit 0. The complete raw output is attached asj75-final-verify-fast-2.log(7,931 lines, 541,661 bytes). Its final output lines are:10k writer-lock measurements: initialization held the lock for 61.725 ms, versus 89.513 ms before the preparation change. Visibility-loss reconciliation took 194.602 ms total, with 23.752 ms under the writer lock.
Static artifacts from the gate: x86_64 21,745,456 bytes (baseline 21,443,824; +301,632); aarch64 19,878,392 bytes (baseline 19,629,240; +249,152). The gate reports both deltas under the amended report-only D243 policy.