diff --git a/docs/cordis-catalog/services.md b/docs/cordis-catalog/services.md index 9501a86c6b..0bd8a8c4a0 100644 --- a/docs/cordis-catalog/services.md +++ b/docs/cordis-catalog/services.md @@ -245,7 +245,7 @@ list(): Session[] fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Session ``` -Source: [`packages/core/session/src/index.ts:604`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts:607`](../../packages/core/session/src/index.ts) ## `ctx.skills` — `SkillService` diff --git a/docs/rfc/implemented/simplification/2026-07-12-simplify-session-log-representation.md b/docs/rfc/implemented/simplification/2026-07-12-simplify-session-log-representation.md index a1dfb5eafb..dc51986e79 100644 --- a/docs/rfc/implemented/simplification/2026-07-12-simplify-session-log-representation.md +++ b/docs/rfc/implemented/simplification/2026-07-12-simplify-session-log-representation.md @@ -10,7 +10,7 @@ The session log maintains two representations that cost more machinery than thei The request-header subsystem implements a custom system/tool delta codec and transmission-decision layer even though its contract says deltas are an encoding optimization, not a reconstructability requirement. Retaining the initial/resume full snapshot at each loop-instance boundary, then writing a canonical full `request/header` whenever that instance's assembled header changes, preserves replay while deleting `SystemDelta`, `ToolsDelta`, round-trip fallback, and the durable `request/header-delta` variant. Codec-only vocabulary disappears with the codec, not because its individual arms were invalid. -This proposal deliberately retains append and replacement `sourceEventSeqs`, crash-repair provenance, and all `SessionStartSource` variants: implemented RFCs give those fields an audit/interception role that zero current readers does not overturn. +The implementation retains append and replacement `sourceEventSeqs`, crash-repair provenance, and all `SessionStartSource` variants because those fields have an audit/interception role that zero current readers does not overturn. ## Decision diff --git a/packages/core/session/src/index.ts b/packages/core/session/src/index.ts index 11451811c3..2850286cde 100644 --- a/packages/core/session/src/index.ts +++ b/packages/core/session/src/index.ts @@ -214,6 +214,9 @@ function assertSessionEventEnvelope(value: Record, index: numbe /** Reject request-header vocabulary removed with the legacy delta codec. */ function assertSupportedRequestHeader(type: string, data: unknown, location: string): void { + if (type === 'request/header-delta') { + throw new Error(`${location} uses unsupported legacy request/header-delta format`) + } if (type === 'request/header' && data !== null && typeof data === 'object' && !Array.isArray(data) && (data as Record)['reason'] === 'fallback') { diff --git a/packages/core/session/tests/request-header.spec.ts b/packages/core/session/tests/request-header.spec.ts index 8bc2a4bf6c..da84ea239c 100644 --- a/packages/core/session/tests/request-header.spec.ts +++ b/packages/core/session/tests/request-header.spec.ts @@ -62,11 +62,17 @@ describe('foldRequestHeader', () => { }) describe('legacy request-header format', () => { - it('rejects a v0 seed containing request/header-delta', () => { + it('rejects request/header-delta in seeds and untyped appends', () => { const legacy = [{ type: 'request/header-delta', seq: 0, time: 1, data: { config: CONFIG }, }] as unknown as SessionEvent[] expect(() => new Session(SessionId('legacy'), legacy)).toThrow(/unsupported legacy request\/header-delta/) + + const session = new Session(SessionId('legacy-append-delta')) + const appendLegacy = session.append.bind(session) as (type: string, data: unknown) => SessionEvent + expect(() => appendLegacy('request/header-delta', { config: CONFIG })) + .toThrow(/unsupported legacy request\/header-delta/) + expect(session.events).toHaveLength(0) }) it('rejects the removed fallback reason in seeds and untyped appends', () => { diff --git a/packages/session-persistence/session-persistence/tests/persistence.spec.ts b/packages/session-persistence/session-persistence/tests/persistence.spec.ts index 5d0ba2c607..f8ea43fd05 100644 --- a/packages/session-persistence/session-persistence/tests/persistence.spec.ts +++ b/packages/session-persistence/session-persistence/tests/persistence.spec.ts @@ -185,7 +185,7 @@ describe('SessionPersistence service registration', () => { await fiber.dispose() }) - it('rejects a legacy header delta buffered by a pre-change live producer', async () => { + it('rejects a legacy header delta from a pre-change live producer', async () => { const ctx = new Context() await ctx.plugin(SessionStore) const fiber = await ctx.plugin(MemoryPersistence) @@ -193,10 +193,9 @@ describe('SessionPersistence service registration', () => { // Model the runtime shape available to JavaScript or a hot-loaded plugin // compiled against the obsolete event vocabulary. const appendLegacy = session.append.bind(session) as (type: string, data: unknown) => SessionEvent - appendLegacy('request/header-delta', { config: { model: 'legacy' } }) - - await expect(ctx.sessions.flush(session)) - .rejects.toThrow(/unsupported legacy request\/header-delta event at seq 0/) + expect(() => appendLegacy('request/header-delta', { config: { model: 'legacy' } })) + .toThrow(/unsupported legacy request\/header-delta format/) + expect(session.events).toHaveLength(0) await fiber.dispose() })