Skip to content

Commit dce75e3

Browse files
docs(policies): replace three session policies with one falsifiable spec (#308)
Merge PR #308
1 parent 9192dfe commit dce75e3

4 files changed

Lines changed: 204 additions & 1876 deletions

File tree

‎docs/policies/session-chaining-policy.md‎

Lines changed: 0 additions & 147 deletions
This file was deleted.
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Session Management Policy
2+
3+
**Version:** 3.0.0
4+
**Status:** ACTIVE
5+
**Last Updated:** 2026-08-10
6+
**Supersedes:** `session-chaining-policy.md`, `session-memory-policy.md`, `session-pruning-policy.md` (1,876 lines combined)
7+
**Design record:** the architecture this policy governs is specified in the session-management remediation blueprint (ADR). This document states the *rules*; the blueprint states the *design*.
8+
9+
---
10+
11+
## 0. Why this document replaced three others
12+
13+
The three superseded policies described a system that was never built. Between them they named
14+
fourteen scripts — `session-loader.py`, `session-search.py`, `auto-save-session.py`,
15+
`session-auto-save-daemon.py`, `session-pruning-daemon.py`, `archive-old-sessions.py`,
16+
`session-start.sh`, `session-chain-manager.py`, `clear-session-handler.py` and others. None of them
17+
existed on disk. The real implementation was a different shape entirely: an MCP server and a
18+
LangGraph node.
19+
20+
Because the spec and the code never described the same system, drift between them was undetectable
21+
by construction. Every defect found in the 2026-08 audit was downstream of that.
22+
23+
This policy is therefore written to be **falsifiable**: §7 names real module paths and marks each
24+
one's status, so a reader can check the claim rather than trust it. Section 4's invariant **I6**
25+
makes keeping that section honest a rule rather than a courtesy.
26+
27+
---
28+
29+
## 1. Purpose
30+
31+
Session management provides continuity across Claude Code sessions: it restores what previous work
32+
established, accumulates what the current run does, and persists a summary that the next run can
33+
use. It is the state-persistence layer beneath the workflow engine, not a part of it.
34+
35+
---
36+
37+
## 2. Scope — what session management owns
38+
39+
| Concern | Description |
40+
|---|---|
41+
| **Identity** | Resolving and publishing the one session ID every component agrees on |
42+
| **Chaining** | Parent/child links, related-session links, tags, and the index over them |
43+
| **Accumulation** | Per-request records: prompt, task type, skill, model, complexity, cwd |
44+
| **Summary** | A finalized, human-readable record produced once per session |
45+
| **Project memory** | The cumulative per-project summary that makes the next session cheaper |
46+
| **Retention** | Pruning and archival of sessions past their useful life |
47+
48+
---
49+
50+
## 3. Out of scope
51+
52+
Session management **must never import or call** git, GitHub, PR, Jira, or any other SDLC
53+
integration. Those are Level 2 pipeline steps and own their own lifecycles.
54+
55+
This is a hard architectural boundary, not a style preference. The superseded
56+
`session-memory-policy.md` carried an entire `Git Auto-Commit Integration` section that ran
57+
`git add -A` / `commit` / `push` from the session layer, and a session schema with
58+
`repos_committed` and `commit_hashes` fields. That coupling is removed and must not return.
59+
60+
**The one permitted direction — inbound, opaque, one-way.** The SDLC layer MAY write metadata
61+
*into* the session store: `issue_id`, `agent_id`, failure reasons, and similar references. The
62+
session layer stores and returns these values without interpreting them and without any dependency
63+
on the layer that produced them. This is what allows the question *"which agent failed in which
64+
session?"* to be answered without coupling.
65+
66+
Also out of scope: the LangGraph graph topology, and re-registering the hooks that ADR-017
67+
unregistered.
68+
69+
---
70+
71+
## 4. Invariants
72+
73+
These must hold at all times. A change that violates one is a defect regardless of what it enables.
74+
75+
**I1 — Restore before anything else.**
76+
The session node is the first substantive node after the Level 0 pre-flight guard, and its first
77+
action is to restore: session identity, then chain context, then project summary. No downstream
78+
node may run before restore completes. Nodes that fan out after it are entitled to assume restored
79+
context is present.
80+
81+
**I2 — Identity is keyed to Claude Code's own session UUID.**
82+
Where Claude Code supplies a session UUID, that value is canonical and is stored verbatim so a
83+
session can be joined to its transcript. A synthetic ID may be minted only when no Claude session
84+
exists, and must be **marked as synthetic**. A UUID is never truncated into an ID: a truncated
85+
UUID is not a join key, it only looks like one.
86+
87+
**I3 — Every write goes through the locked entry point.**
88+
Session state is written by concurrent agents. All mutations of shared session JSON must use the
89+
mutually-exclusive read-modify-write path, never a bare read-then-write. An unlocked
90+
last-writer-wins save exists and is legitimate for single-writer files; it is not permitted for
91+
the chain index or the accumulator. Losing a write silently while reporting success is the failure
92+
mode this prevents.
93+
94+
**I4 — Finalize is idempotent and fires from two independent triggers.**
95+
The Stop hook fires per Claude session; the pipeline terminal node fires per run. These are **not**
96+
symmetric redundancy — only the terminal node covers every run, and only the Stop hook covers a
97+
session that ends without a pipeline run. Both must be able to finalize the same session without
98+
producing a double record, and the check-and-write must be a single locked transaction.
99+
100+
**I5 — The session layer never depends on the SDLC layer.** See §3.
101+
102+
**I6 — Spec and implementation must name each other.**
103+
Any module implementing this policy is listed in §7 with its status. Any module listed in §7 must
104+
exist at the stated path, or be explicitly marked as planned with the phase that delivers it.
105+
Naming a component that does not exist is the specific failure that made the superseded policies
106+
worthless.
107+
108+
---
109+
110+
## 5. Data model
111+
112+
The on-disk contract. Locations are canonical; a component reading or writing session state
113+
elsewhere is a defect.
114+
115+
| Artifact | Location | Purpose |
116+
|---|---|---|
117+
| Session directory | `{memory}/logs/sessions/{session_id}/` | Everything belonging to one session |
118+
| Session pointer | `{memory}/.current-session.json` | The active session ID |
119+
| Chain index | one file, under `{memory}/logs/` | Nodes, parent/child/related edges, tags, tag index |
120+
| Accumulator | `{session_dir}/session-summary.json` | Per-request records and aggregates |
121+
| Session summary | `{session_dir}/session-summary.md` | Finalized human-readable record |
122+
| Project summary | per project | Cumulative context restored at session start |
123+
| Archives | grouped by `YYYY-MM` | Compressed sessions past the retention window |
124+
125+
**The chain index is a derived cache.** It must be rebuildable from the session directories. It is
126+
never the only copy of anything that matters.
127+
128+
**Field ownership must be explicit.** Every field is either session-owned or inbound-opaque (§3).
129+
Inbound-opaque fields are stored and returned unmodified and are never interpreted by this layer.
130+
131+
---
132+
133+
## 6. Lifecycle
134+
135+
```
136+
RESTORE identity -> chain context -> project summary (I1, first node)
137+
|
138+
ACCUMULATE one record per request (I3)
139+
|
140+
CHECKPOINT explicit save points only (I3)
141+
|
142+
FINALIZE summary + project summary update (I4, idempotent)
143+
|
144+
PRUNE archive past the retention window
145+
```
146+
147+
**Checkpoints are explicit, not continuous.** Saving on every node transition is prohibited — the
148+
overhead is real and the value is not. Only declared checkpoint points write. The set of
149+
checkpoints and their per-run cost are specified in the blueprint, which is required to state that
150+
cost as a measured number.
151+
152+
**Restore is bounded.** Restored context is capped. An unbounded project summary cannot serve as a
153+
cheap restore and must not be allowed to grow into one.
154+
155+
---
156+
157+
## 7. Component map
158+
159+
Per invariant **I6**, this section is the falsifiable claim. Status is as of 2026-08-10.
160+
161+
| Component | Path | Status |
162+
|---|---|---|
163+
| Session identity resolution | `hooks/session_context.py` | **Working** — single authority; also provides `FileLock`, `atomic_write_text`, `locked_json_update` |
164+
| Session MCP surface | `mcp-session-mgr` (separate repo) | **Live** — this is the server Claude actually runs |
165+
| Session store (shared logic) | to be extracted | **Planned** — blueprint Phase 2 |
166+
| Atomic/locked IO | to be extracted | **Planned** — blueprint Phase 1 |
167+
| Level 1 session node | `langgraph_engine/context_sync/session_loader.py` | **Partial** — creates the session; does not yet restore (I1) |
168+
| Pruning | `langgraph_engine/context_sync/architecture/session_pruner.py` | **Present, non-functional** — collects files, but sessions are directories |
169+
| In-engine MCP server copy | `src/mcp/session_mcp_server.py` | **Being retired** — superseded by the standalone |
170+
171+
**Two implementations existed.** The in-engine copy and the standalone repo diverged by over 1,300
172+
lines while both remained live: Claude's MCP tool calls reached one, the engine's in-process
173+
imports reached the other. Authority is now split **by layer** — shared logic is canonical in the
174+
engine, the MCP surface is canonical in the standalone — and the in-engine server is retired.
175+
176+
**The generator is destructive.** `scripts/tools/create_mcp_repos.py` overwrites `server.py` and
177+
replaces `base/` in existing repos. All 13 target repos have evolved past their generated state
178+
(75 commits, ~29 merged PRs). It must not be run until it is made non-destructive.
179+
180+
---
181+
182+
## 8. Retention
183+
184+
- Keep the most recent sessions regardless of age.
185+
- Archive beyond the retention window, grouped by month, compressed.
186+
- **Never archive a project summary.**
187+
- Archival is one layout. A second, incompatible layout is a defect, not an alternative.
188+
- Pruning must be verified against the real directory-per-session layout before it is trusted —
189+
a pruner that silently archives nothing looks identical to one with nothing to do.
190+
191+
---
192+
193+
## 9. Governance
194+
195+
This file is the single source of truth for session-management policy. It lives in the repository
196+
so that policy and code change together and in one place.
197+
198+
The three superseded policies previously existed in two locations — this repository and
199+
`~/.claude/policies/01-sync-system/session-management/` — with no synchronisation between them.
200+
The unversioned copies are retired **only after this document is committed**.
201+
202+
Changes to session-management behaviour update this file in the same change as the code. A
203+
component named here that does not exist, or a component that exists and is not named here,
204+
violates **I6** and is a defect in this document.

0 commit comments

Comments
 (0)