Skip to content

Commit fe5a917

Browse files
committed
refactor(session): resolve root session implicitly
1 parent cce7c6a commit fe5a917

11 files changed

Lines changed: 516 additions & 268 deletions

docs/SmokeTests.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ the change that introduces it; do not assume one here, and do not invent a new
285285
any; bounded serialized examples for each tool response; any type-check output
286286
from `deno task check`.
287287
- **Common failure signatures:** Missing tool registration; schema drift;
288-
acceptance of missing `root_session_id`; placeholder or shape-invalid
288+
acceptance of caller-supplied `root_session_id`; placeholder or shape-invalid
289289
responses; type drift between schemas and runtime handlers.
290290
- **Release-gate severity:** Critical.
291291

@@ -475,9 +475,10 @@ the change that introduces it; do not assume one here, and do not invent a new
475475
deno task check
476476
```
477477

478-
- **Expected result:** PASS. `session_*` calls receive canonical
479-
`root_session_id`; risky native tools such as `WebFetch` are denied or guided
480-
toward the correct `session_*` replacement; `Task` guidance remains MCP-first;
478+
- **Expected result:** PASS. `session_*` calls rely on canonical root-session
479+
resolution from runtime context rather than caller-supplied `root_session_id`;
480+
risky native tools such as `WebFetch` are denied or guided toward the correct
481+
`session_*` replacement; `Task` guidance remains MCP-first;
481482
`tool.execute.after` stays attribution-only.
482483
- **Artifacts/evidence to save:** Full test output; routing outcome assertions;
483484
denial/guidance messages; attribution metadata assertions.

docs/superpowers/plans/2026-03-20-context-mode-mcp-first-implementation.md

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ enforcement-hook rewrite.
238238
- `session_fetch_and_index`
239239
- `session_stats`
240240
- `session_doctor`
241-
2. Every request schema must require `root_session_id`.
241+
2. Superseded by later runtime contract changes: public request schemas no
242+
longer accept `root_session_id`; canonical root-session identity is resolved
243+
implicitly from runtime context.
242244
3. Every response schema must include `status` and enough metadata to attribute
243245
results later in hooks.
244246
4. Add a runtime module in `src/services/session-mcp-runtime.ts` that:
@@ -278,7 +280,7 @@ Write failing tests first in `src/services/session-mcp-runtime.test.ts` and
278280
`src/index.test.ts` covering:
279281

280282
- runtime registers exactly the 8 `session_*` tools
281-
- each tool schema rejects calls without `root_session_id`
283+
- each tool schema rejects caller-supplied `root_session_id`
282284
- initial stub handlers return minimal valid responses for all 8 registered
283285
tools
284286
- response payloads are capped to the exact 32 KB response budget
@@ -481,12 +483,13 @@ shared across parent/child sessions.
481483
### 7.3 Implementation requirements
482484

483485
1. Reuse `SessionManager` as the only canonical lineage authority.
484-
2. `tool.execute.before` must inject `root_session_id` into every `session_*`
485-
call using canonical resolution from `src/session.ts`.
486-
3. The `session_*` runtime must reject mismatched or missing `root_session_id`
487-
after schema validation; it must not invent a second lineage model.
488-
4. All corpus/artifact/stats writes must use `root_session_id`, never the raw
489-
child session ID.
486+
2. `tool.execute.before` must preserve canonical root-session context for every
487+
`session_*` call using canonical resolution from `src/session.ts`.
488+
3. The `session_*` runtime must resolve canonical root-session identity from
489+
runtime context; callers must not supply `root_session_id`, and the runtime
490+
must not invent a second lineage model.
491+
4. All corpus/artifact/stats writes must use the canonical root session ID,
492+
never the raw child session ID.
490493
5. Parent and child sessions must read from the same root corpus namespace.
491494
6. Temporary-root sessions must remain supported until later migration work in
492495
Task 6.
@@ -498,10 +501,11 @@ Write failing tests first in `src/session.test.ts`,
498501
covering:
499502

500503
- parent and child `session_*` calls share one root corpus namespace
501-
- `tool.execute.before` injects `root_session_id` on `session_*` calls
504+
- `tool.execute.before` keeps `session_*` calls rooted in canonical session
505+
context without mutating public args
502506
- native tool calls do not receive `root_session_id`
503-
- the runtime rejects `session_*` calls when `root_session_id` is absent or
504-
mismatched
507+
- the runtime rejects caller-supplied `root_session_id` and resolves canonical
508+
root identity from context
505509

506510
### 7.5 Verification commands
507511

@@ -623,7 +627,8 @@ model toward `session_*` tools and attributes outcomes cleanly.
623627
### 9.3 Implementation requirements
624628

625629
1. Keep `session_*` calls simple in `tool.execute.before`:
626-
- inject canonical `root_session_id`
630+
- preserve canonical root-session context without injecting public
631+
`root_session_id` args
627632
- allow the call to proceed
628633
2. Rewrite native-tool policy so it is explicitly secondary:
629634
- `WebFetch` -> deny with direct guidance to `session_fetch_and_index`
@@ -643,7 +648,8 @@ model toward `session_*` tools and attributes outcomes cleanly.
643648

644649
Write failing tests first in the existing hook/routing test files covering:
645650

646-
- `session_*` calls are allowed with injected `root_session_id`
651+
- `session_*` calls are allowed with canonical root-session context and without
652+
caller-supplied `root_session_id`
647653
- `WebFetch` is denied toward `session_fetch_and_index`
648654
- data-heavy `Bash` is routed toward `session_execute`
649655
- `Task` prompt rewriting adds MCP-first routing guidance
@@ -839,7 +845,7 @@ This cleanup is mandatory and not optional follow-up polish.
839845
enforcement layer only.
840846
2. Retain `src/handlers/tool-before.ts` and `src/handlers/tool-after.ts`, but
841847
narrow them to:
842-
- `root_session_id` injection for `session_*`
848+
- canonical root-session context handling for `session_*`
843849
- native fallback enforcement
844850
- routing attribution metadata
845851
3. Retain `src/session.ts` as lineage authority and extend it for corpus/state

docs/superpowers/plans/2026-03-20-context-mode-mcp-first.md

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,16 @@ in this repository.
209209

210210
### 5.1 Tool suite and exact role
211211

212-
| Tool | Role | Primary inputs | Primary outputs | Notes |
213-
| ------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------------- |
214-
| `session_execute` | Run one bounded sandbox execution task | command/script, runtime, intent, timeout, `root_session_id` | bounded result, summary, optional artifact/index handle | primary replacement for raw data-heavy Bash workflows |
215-
| `session_execute_file` | Run one bounded sandbox file-processing task | path(s), processing intent, runtime/handler, `root_session_id` | findings, summary, optional artifact/index handle | primary replacement for raw file-dump analysis |
216-
| `session_batch_execute` | Combine multiple execute/search sub-operations into one call | list of execute/search/file subrequests, `root_session_id` | bounded multi-result response + handles | sequential in v1; no hidden parallelism |
217-
| `session_index` | Normalize and locally index supplied content into the hot-tier corpus | content or pre-normalized text, source metadata, `root_session_id` | corpus id, chunk count, query hints | local-only indexing; no Graphiti involvement |
218-
| `session_search` | Query the local indexed corpus for the canonical root session | query or query list, optional corpus filters, `root_session_id` | ranked bounded snippets + corpus/chunk refs | searches only local session-scoped indexed data |
219-
| `session_fetch_and_index` | Fetch a URL in sandbox, normalize it, then index it locally | url, fetch options, content-type hint, `root_session_id` | corpus id, summary, query hints | primary replacement for native `WebFetch` |
220-
| `session_stats` | Show local context-savings and tool/index activity for the root session | optional scope, `root_session_id` | counters, byte ratios, corpus counts, queue depth | in scope |
221-
| `session_doctor` | Diagnose MCP/plugin/hot-tier health | optional checks, `root_session_id` | health report for Redis, hooks, cache, Graphiti connectivity | in scope |
212+
| Tool | Role | Primary inputs | Primary outputs | Notes |
213+
| ------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------- |
214+
| `session_execute` | Run one bounded sandbox execution task | command/script, runtime, intent, timeout | bounded result, summary, optional artifact/index handle | canonical root session resolves implicitly from runtime context |
215+
| `session_execute_file` | Run one bounded sandbox file-processing task | path(s), processing intent, runtime/handler | findings, summary, optional artifact/index handle | canonical root session resolves implicitly from runtime context |
216+
| `session_batch_execute` | Combine multiple execute/search sub-operations into one call | list of execute/search/file subrequests | bounded multi-result response + handles | sequential in v1; no hidden parallelism; canonical root resolves implicitly |
217+
| `session_index` | Normalize and locally index supplied content into the hot-tier corpus | content or pre-normalized text, source metadata | corpus id, chunk count, query hints | local-only indexing; no Graphiti involvement |
218+
| `session_search` | Query the local indexed corpus for the canonical root session | query or query list, optional corpus filters | ranked bounded snippets + corpus/chunk refs | searches only local session-scoped indexed data |
219+
| `session_fetch_and_index` | Fetch a URL in sandbox, normalize it, then index it locally | url, fetch options, content-type hint | corpus id, summary, query hints | primary replacement for native `WebFetch` |
220+
| `session_stats` | Show local context-savings and tool/index activity for the root session | optional scope | counters, byte ratios, corpus counts, queue depth | in scope |
221+
| `session_doctor` | Diagnose MCP/plugin/hot-tier health | optional checks | health report for Redis, hooks, cache, Graphiti connectivity | in scope |
222222

223223
### 5.2 Scope decision for `session_upgrade`
224224

@@ -240,10 +240,12 @@ replacement milestone, the validation bar, or the migration work.
240240
The following defaults are mandatory unless later superseded by a narrower
241241
implementation plan:
242242

243-
1. Every `session_*` tool must accept `root_session_id`.
244-
2. In OpenCode, the plugin must populate `root_session_id` in
245-
`tool.execute.before` for every `session_*` call using canonical root-session
246-
resolution from `src/session.ts`.
243+
1. Every public `session_*` tool request resolves the canonical root session
244+
implicitly from runtime context; callers must not pass `root_session_id`.
245+
2. In OpenCode, the plugin/runtime must preserve canonical root-session context
246+
for every `session_*` call using canonical root-session resolution from
247+
`src/session.ts`, without mutating the public request contract to require
248+
`root_session_id`.
247249
3. `session_*` tools are session-scoped by default; they do not create
248250
indefinite project-wide local corpora.
249251
4. If a full result exceeds the bounded response budget, the tool must
@@ -523,14 +525,14 @@ architecture” to “enforcement + continuity around the MCP-first runtime.”
523525

524526
### 7.1 Hook responsibilities
525527

526-
| Hook | Required role in the new model |
527-
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
528-
| `tool.execute.before` | populate canonical `root_session_id` on `session_*` calls; enforce fallback from risky native tools toward `session_*`; never become the main execution engine |
529-
| `tool.execute.after` | capture bounded tool events, context-savings stats, artifact refs, and routing outcomes; never rewrite large raw output after the fact as the primary mechanism |
530-
| `chat.message` | assemble local `<session_memory>` from events, snapshot, and cached persistent memory; schedule async refresh decisions only |
531-
| `experimental.chat.messages.transform` | prepend the prepared `<session_memory>` envelope to the last user message |
532-
| `experimental.session.compacting` | inject the same prepared local continuity envelope into compaction |
533-
| `event` | capture user/assistant/session lifecycle events, maintain canonical root-session lineage state, schedule snapshot rebuilds and async Graphiti drain |
528+
| Hook | Required role in the new model |
529+
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
530+
| `tool.execute.before` | preserve canonical root-session context for `session_*` calls and enforce fallback from risky native tools toward `session_*`; never become the main execution engine |
531+
| `tool.execute.after` | capture bounded tool events, context-savings stats, artifact refs, and routing outcomes; never rewrite large raw output after the fact as the primary mechanism |
532+
| `chat.message` | assemble local `<session_memory>` from events, snapshot, and cached persistent memory; schedule async refresh decisions only |
533+
| `experimental.chat.messages.transform` | prepend the prepared `<session_memory>` envelope to the last user message |
534+
| `experimental.session.compacting` | inject the same prepared local continuity envelope into compaction |
535+
| `event` | capture user/assistant/session lifecycle events, maintain canonical root-session lineage state, schedule snapshot rebuilds and async Graphiti drain |
534536

535537
### 7.2 Hook interaction sequence
536538

@@ -544,7 +546,7 @@ architecture” to “enforcement + continuity around the MCP-first runtime.”
544546
545547
3. tool call selected by the model
546548
a. tool.execute.before
547-
- if tool is session_*: inject canonical root_session_id and allow
549+
- if tool is session_*: route using canonical session context and allow
548550
- if tool is risky native fallback: redirect/deny toward session_*
549551
- if tool is safe bounded native fallback: allow
550552
b. tool runs
@@ -582,7 +584,9 @@ continuity concept. The new architecture must reuse that logic.
582584
Rule:
583585

584586
- the plugin is authoritative for canonical root-session identity in OpenCode
585-
- `tool.execute.before` must add `root_session_id` to all `session_*` tool calls
587+
- `tool.execute.before` / runtime wiring must preserve canonical root-session
588+
context for all `session_*` tool calls without exposing `root_session_id` as a
589+
required public request field
586590
- `tool.execute.after` and `event` must attribute all resulting continuity
587591
events, stats, corpora, and artifacts to that same canonical root session
588592

@@ -929,8 +933,8 @@ The implementation/tasks must explicitly prevent these drift modes.
929933
3. **Child-session split brain**\
930934
Symptom: child `session_*` calls create separate corpora or stats outside the
931935
root session.\
932-
Prevention: plugin-injected `root_session_id` is mandatory for all
933-
`session_*` calls; no alternative local-session namespace is allowed.
936+
Prevention: canonical root resolution from runtime context is mandatory for
937+
all `session_*` calls; no alternative local-session namespace is allowed.
934938

935939
4. **Temporary-root orphaning**\
936940
Symptom: artifacts indexed before lineage resolution remain under obsolete

0 commit comments

Comments
 (0)