mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
subagent: carry inherited policy overrides in the child session header
Review fix (ds-review-bot critical #2 on #623): the first-turn event stamp had a durability hole no turn anchoring can close — an idle SessionStart- style injection persists a complete one-shot turn before any prompt turn opens, so a crash in that window left a resumable-looking child with no inherited policy, falling back to a possibly wider deployment default. The captured overrides now ride the child's creation meta into its immutable SessionHeader (sandboxMode/approvalPolicy, neutral strings at the session boundary — the delegationDepth precedent), durable from the moment the session exists: no listener ordering can starve the baseline and no crash window can lose it. overrideOf(session) on both policy services resolves fold(events past header.seedLength) ?? header baseline, validating against the closed vocabulary on read; stampOverride and the prompt-submit listener machinery are deleted. The header field rides both persistence backends (JSONL header line; SQLite sessions columns, SCHEMA_VERSION 11 — pre-release, no migration). pty-local reads through overrideOf so PTY spawns see the baseline too. Red-first: header-durability-before-any-turn test (the injection crash window shape), baseline/seed-boundary/closed-vocabulary contract tests in both service suites; the real-wall suite (race, veto, fork stale-seed, grandchild) re-anchored on header assertions and green. The Agent Note's Alternatives now records the superseded event-stamping iteration with the review evidence; bilingual docs updated.
This commit is contained in:
@@ -301,15 +301,17 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers
|
||||
private writeRow(meta: SessionHeader): void {
|
||||
this.db.prepare(`
|
||||
INSERT INTO sessions
|
||||
(id, version, created_at, cwd, parent_session, seed_length, delegation_depth, incarnation, revision)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)
|
||||
(id, version, created_at, cwd, parent_session, seed_length, delegation_depth, incarnation, revision, sandbox_mode, approval_policy)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
version = excluded.version,
|
||||
created_at = excluded.created_at,
|
||||
cwd = excluded.cwd,
|
||||
parent_session = excluded.parent_session,
|
||||
seed_length = excluded.seed_length,
|
||||
delegation_depth = excluded.delegation_depth
|
||||
delegation_depth = excluded.delegation_depth,
|
||||
sandbox_mode = excluded.sandbox_mode,
|
||||
approval_policy = excluded.approval_policy
|
||||
`).run(
|
||||
meta.id,
|
||||
meta.version,
|
||||
@@ -319,6 +321,8 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers
|
||||
meta.seedLength ?? null,
|
||||
meta.delegationDepth ?? null,
|
||||
randomUUID(),
|
||||
meta.sandboxMode ?? null,
|
||||
meta.approvalPolicy ?? null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import type { SessionEvent, SessionId, SessionHeader, SurfaceOp } from '@deepsee
|
||||
* layout; orthogonal to a session's own `version` (which versions the EVENT
|
||||
* vocabulary, stored per session in the `sessions` row).
|
||||
*/
|
||||
export const SCHEMA_VERSION = 10
|
||||
export const SCHEMA_VERSION = 11
|
||||
|
||||
/** SQLite application id protecting unrelated databases from persistence writes. */
|
||||
export const SESSION_PERSISTENCE_SQLITE_APPLICATION_ID = 0x44534850
|
||||
@@ -41,6 +41,10 @@ export interface SessionRow {
|
||||
/** Monotonic log-change token incremented in each mutating transaction. */
|
||||
revision: number
|
||||
delegation_depth: number | null
|
||||
/** The inherited sandbox-mode delegation baseline, or NULL. */
|
||||
sandbox_mode: string | null
|
||||
/** The inherited approval-policy delegation baseline, or NULL. */
|
||||
approval_policy: string | null
|
||||
}
|
||||
|
||||
/** An `events` table row: one `SessionEvent` mapped 1:1 (`data` is JSON text). */
|
||||
@@ -124,7 +128,9 @@ function configureDatabase(db: DatabaseSync, path: string, journalMode: JournalM
|
||||
seed_length INTEGER,
|
||||
delegation_depth INTEGER,
|
||||
incarnation TEXT NOT NULL,
|
||||
revision INTEGER NOT NULL
|
||||
revision INTEGER NOT NULL,
|
||||
sandbox_mode TEXT,
|
||||
approval_policy TEXT
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
@@ -181,6 +187,8 @@ export function rowToMeta(row: SessionRow): SessionHeader {
|
||||
...row.parent_session !== null ? { parentSession: row.parent_session as SessionId } : {},
|
||||
...row.seed_length !== null ? { seedLength: row.seed_length } : {},
|
||||
...row.delegation_depth !== null ? { delegationDepth: row.delegation_depth } : {},
|
||||
...row.sandbox_mode !== null ? { sandboxMode: row.sandbox_mode } : {},
|
||||
...row.approval_policy !== null ? { approvalPolicy: row.approval_policy } : {},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user