Skip to content

fix(gc): guard cleanup by observed generation - #125

Merged
myobie merged 1 commit into
mainfrom
schickling-assistant/2026-07-30-generation-guarded-gc
Jul 30, 2026
Merged

fix(gc): guard cleanup by observed generation#125
myobie merged 1 commit into
mainfrom
schickling-assistant/2026-07-30-generation-guarded-gc

Conversation

@schickling-assistant

@schickling-assistant schickling-assistant commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Problem

pty gc decides from a session snapshot, but residual sweep and permanent
respawn previously called unowned cleanupAll(name) later. A same-name
replacement created after the snapshot could therefore have its files removed
or be overwritten by the stale gc pass.

Goal

Cleanup and respawn apply only when the on-disk session is still the exact
generation that gc observed.

Decisions

  • Hold the existing per-name creation lock across compare, cleanup, and
    replacement publication.
  • Compare the opaque generation token for current records.
  • For legacy records without a generation, require exact metadata equality;
    any intervening update suppresses the action.
  • Return a skipped result for stale observations rather than treating them as
    failures. The next reconciliation pass observes the current generation.
  • Base this directly on merged refactor: make session observation pure #124/current main so the diff contains only
    generation-CAS hardening and its CLI-fallback lock handoff.

Verification

From the branch based directly on current main:

npm run typecheck
npm run build
npm test -- --run tests/gc-generation-guard.test.ts tests/list-purity.test.ts tests/list-liveness-budget.test.ts tests/list-live-session-race.test.ts tests/list-filters.test.ts tests/gc.test.ts tests/gc-parent-child.test.ts tests/gc-permanent.test.ts tests/spawn-bundle-fallback.test.ts --reporter=dot --maxWorkers=1

Test Files  9 passed (9)
Tests       66 passed (66)

The focused regressions prove replacement generations suppress residual cleanup
and permanent respawn, unchanged legacy metadata permits cleanup, changed
legacy metadata suppresses cleanup, and bundled CLI fallback retains the CAS
lock through replacement socket publication.

Hosted checks at exact head 00e67384a0cd3b366ad1dbe8e33908d85d486b37:

  • Nix/build run 30552078809: passed
  • Test/vitest run 30552074825: passed

Complexity

One internal compare-and-swap cleanup primitive and one lock-held cleanup
helper centralize the ordering. Bundled CLI fallback receives a one-hop lock
owner PID, validates the live lock, and scrubs the control value before daemon
or session environment inheritance. No new dependency, daemon, or persisted
session field is introduced.

Concerns

Holding the per-name lock through spawnDaemon intentionally serializes
same-name creation until the replacement socket is published. Lock scope is
per session name, not fleet-wide.

Friction & bottlenecks

Node ESM module namespace exports cannot be spied on under Vitest. The tests
therefore exercise two explicitly internal, non-client-API CAS primitives
directly. No runtime bottleneck was observed.

Follow-ups

  • Apply the same observation-token discipline to gc orphan-kill and abandoned
    reap as a separate lifecycle-policy change; this PR intentionally covers
    residual sweep and permanent respawn only.

References

agent-session-id: dev3.dotfiles-cos-misc-agent-runtime-simplification
agent-tool: Codex
agent-tool-version: 0.145.0
agent-model: gpt-5.6-sol
agent-runtime-profile: /home/schickling/.config/coding-agents/profile.json
agent-skills-manifest: /nix/store/nk9iml2841l1yjjg0f6f0d3y60zkg1nn-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@4a0515f
@myobie
myobie force-pushed the schickling-assistant/2026-07-30-generation-guarded-gc branch from 1bcc72b to 00e6738 Compare July 30, 2026 14:30
@myobie
myobie changed the base branch from schickling-assistant/2026-07-30-pure-session-observation to main July 30, 2026 14:30
@myobie
myobie marked this pull request as ready for review July 30, 2026 14:38

@myobie myobie left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved exact head 00e6738. Independent patch walk confirms generation/legacy compare-and-swap semantics, stale-observation zero-mutation behavior, and lock ownership through bundled fallback publication. Focused 66/66 plus hosted Vitest/Nix are green.

@myobie
myobie merged commit c23812e into main Jul 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants