Skip to content

Write nothing of a retired session again - #72

Merged
wu-sheng merged 1 commit into
mainfrom
retention-retire
Oct 17, 2026
Merged

wu-sheng merged 1 commit into
mainfrom
retention-retire

Conversation

@wu-sheng

Copy link
Copy Markdown
Member

A retired session is one whose marker _retired/<session> is in the root: an empty file named by its id. Nothing makes one yet. The level that retires a session (storage.retention.retire_after) comes in the next change, together with its docs and changelog entry, so no setting exists before its behavior. This change makes every writer leave a retired session alone first. A session retired once is then never collected, derived, parsed or sent again, whatever is left of it on disk.

What changes

  • The marker. storage.Retired and storage.RetiredSessions read _retired/. A marker that cannot be read is an error, never taken for no marker. A writer that meets one changes nothing of that session in that pass.
  • Every writer checks it before it creates a session or chain directory, or takes a lock that would create one:
    • Claude Code, the change recorder and Kiro pass over a retired source session. Lost-source marking skips it.
    • Provider bodies of a retired session are marked retired in seen.state and never read again. A response is attributed through a retired request too. A marker that cannot be read leaves seen.state as it was.
    • LangSmith: a run whose conversation is decided and retired never waits. It is remembered in that conversation. Its later updates, and runs inside it, are then known to be retired too, after a restart and after the run above it is forgotten. A run whose conversation is not decided yet waits as before.
    • asz parse, the metrics deriver and an SD-format scenario build do nothing for a retired id. A marker the deriver cannot read keeps the first pass's look-back.
    • asz push sends no landed file of a retired session. It still reads each round under a retired session's conversation directory by the session in the round's header. Spooled metrics requests still go.
    • asz repack and the scenario runner refuse a root holding a retired session, and a destination where the session is retired. The runner copies only into a new directory.
  • What a person sees. The pass log says each retired session once per process:
      retired: <session>: found and not collected; a retired session is never collected again
    
    asz sources names them for every adapter, and asz verify counts them.

Tests

  • tests/chain, TestARetiredSessionIsNeverWrittenAgain: all-kinds and provider-bodies-long, each with what is left of the session in four states: everything but its index, its directory alone, its chain alone, and nothing. The provider's seen.state is lost each time, and the sources grow. Nothing under the session or chain changes, no file of it is sent, and every spooled metrics request reaches the receiver.
  • tests/chain, TestARoundOfALiveSessionUnderARetiredDirectoryIsSent, and TestRepackRefusesARetiredSession for direct calls and unreadable markers.
  • Each collector, given new evidence of a retired id: Claude Code, Kiro, the provider (its fast path, a leftover directory, an unreadable marker then recovery), and LangSmith (a run naming the conversation inside a missing parent, a threadless call, a sparse update, an update before its start, an unassigned conversation, a restart, the defer limit, a call that outlives its function, an unreadable marker).
  • The metrics deriver, an SD scenario build, the runner's copy (source and destination), the storage marker reads, and the pass log (exactly once per process), asz sources and asz verify.

Each new guard was proven by reverting it. make test, the JSON v1 step (GOEXPERIMENT=nojsonv2), make scenarios, lint, and the Windows build and vet pass.

A retired session is one whose marker _retired/<session> is in the root:
an empty file named by its id. Nothing makes one yet. The level that
retires a session comes in its own change, with its setting and its
docs. This change makes every writer leave a retired session alone
first, so a session retired once is never collected, derived, parsed
or sent again, whatever is left of it.

Each writer checks the marker before it creates a session or a chain
directory, or takes a lock that would create one. A marker that cannot
be read is an error, never taken for no marker, and the writer changes
nothing of that session in that pass.

- Claude Code, the change recorder and Kiro pass over a retired source
  session, and lost-source marking skips it.
- Provider bodies of a retired session are marked retired in seen.state
  and never read again. A marker that cannot be read leaves seen.state
  as it was.
- LangSmith: a run whose conversation is decided and retired never
  waits. It is remembered in that conversation, so its later updates,
  and runs inside it, are known to be retired too, also after a restart
  and after the run above it is forgotten.
- parse, the metrics deriver and the SD scenario build do nothing for a
  retired id. A marker the deriver cannot read keeps the first pass's
  look-back.
- push sends no landed file of a retired session. It still reads each
  round under a retired session's directory by the session the round's
  header names, and spooled metrics requests still go.
- repack and the scenario runner refuse a root holding a retired
  session, and a destination where the session is retired. The runner
  copies only into a new directory.
- The pass log says each retired session once per process, asz sources
  names them for every adapter, and asz verify counts them.
@wu-sheng wu-sheng added this to the 0.6.0 milestone Oct 17, 2026
@wu-sheng wu-sheng added the bug Something isn't working label Oct 17, 2026
@wu-sheng
wu-sheng merged commit c001d1f into main Oct 17, 2026
24 checks passed
@wu-sheng
wu-sheng deleted the retention-retire branch October 17, 2026 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant