Repository navigation
Retire a conversation idle for retire_after - #73
Merged
Merged
Conversation
storage.retention.retire_after is the second level of retention. A conversation idle that long has everything of it removed, its metadata too, and is retired: it is never collected again, even when its runtime resumes it. It is read on the same clock as metadata_only_after, the header time of the newest landed file, and is at least as long. It needs metadata_only_after set, and equal to it a conversation is retired with no metadata-only step first. Either rule broken is a configuration error. Only both settings off keeps everything. A pass retires at its end, after the send, before level 1, and gives no level 1 to an idle or a retired session. A session is retired once its chain covers its files, its metrics are derived when the pipeline derives them, and no removal of its files is in progress, asked under its locks. The steps keep a crash or a power loss from losing anything, or landing the session again: - The marker _retired/<session>, an empty file, is written and synced, the errors checked, before anything is deleted. Every attempt that deletes anything writes it again. - Each metrics request the receiver does not have is written again from its receipt and synced, a request already there included. - The session's directory and its conversation's are renamed under _removed/ and deleted. Both directories of each rename are synced, the errors checked, before anything moved is deleted. - The requests the receiver has are deleted. The root, _conversations, _removed and the spool are synced on every attempt before push.state and metrics.state forget the session, and the provider's table marks its lines retired. A session's owner stays in push.state while a request of it waits in the spool, so the request goes to that owner only. Every pass finishes a retirement left unfinished before anything lands, whatever the settings say then, and asz parse and asz push do the same first. The pass line counts retired=, the startup says what each level does, and the page drops a retired conversation from memory, also one another process retired.
wu-sheng
force-pushed
the
retention-retire-after
branch
from
October 17, 2026 13:08
5092e97 to
2c196f2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the second level of retention.
storage.retention.retire_after,-1and off by default, is how long a conversation may be idle before everything of it is removed, its metadata too, and it is retired. A retired conversation is never collected again, even when its runtime resumes it, so the setting should be longer than the runtime keeps its own history. The writers already pass a retired session over (#72). This change retires sessions, and documents both.What changes
retire_aftersits besidemetadata_only_after, on the same clock: the header time of the newest landed file. It is at leastmetadata_only_after, which must be set too. With both equal, a conversation is retired with no metadata-only step first. Either rule broken is a configuration error. Only both settings off keeps everything.asz.yamlspells it out.retire_afteris never given level 1. It is retired once its chain covers its files, its metrics are derived when the pipeline derives them, and no removal of its files is in progress. That is asked under the session's locks. Sending is not waited for._retired/<session-id>, an empty file, is written and synced, the errors checked, before anything is deleted. Every attempt that deletes anything writes it again._removed/and deleted there. Both directories of each rename are synced, the errors checked, before anything moved is deleted.storage.RemoveDirDurabledoes this; the scenario remover keepsRemoveDir._conversations/,_removed/and the spool are synced on every attempt before the state forgets the session.push.stateandmetrics.stateforget the session. The provider's table marks its linesretired._langsmith/open.jsonis not changed.push.statewhile a request of it waits in the spool, so the request goes to that owner only.asz parseandasz pushdo the same first.retired=. The startup says what each level does:asz.yaml, the configuration page, the storage root (layout, provider states, Retirement, What travels, A scenario root), the command-line page, the scenario guide, the Claude Code, Kiro and LangSmith pages, the changelog (also for Write nothing of a retired session again #72), and CLAUDE.md's invariants.Tests
tests/chain:tests: a LangChain conversation retired, itsopen.jsonunchanged, and a later turn not collected.internal/view: the list drops a conversation another process retired.cmd/asz: a pass retires and counts it, the page drops it, recovery is counted,asz parseandasz pushfinish a retirement first, and the startup lines.internal/config: the two levels together.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.