policy: scope seed-boundary slicing to delegation children

Review fix (ds-review-bot on #623): the unconditional slice regressed the
public SessionStore.fork path — a generic fork child gets seedLength but no
policy baseline, so slicing discarded its seed-carried sandbox/approval
switches and silently widened it to the deployment defaults (a forked
read-only/never parent produced a workspace-write/ask child).

overrideOf now branches on baseline presence: with a header baseline (a
delegation child) the fold covers only own post-seed switches — the
baseline captured from the parent's FULL log subsumes seed history; without
one, the whole log — seeded switches ARE the replayed inherited truth. The
permission preset fold scopes the same way. Red-first: generic-fork
seed-carried override tests in both policy suites.
This commit is contained in:
kingwl
2026-07-26 23:06:15 +08:00
parent b02d3e4c03
commit 99f5fab7bc
17 changed files with 78 additions and 41 deletions

View File

@@ -644,4 +644,15 @@ describe('delegation inheritance (overrideOf over the header baseline)', () => {
expect(() => ctx.approval.overrideOf(child)).toThrow(/approvalPolicy/)
})
it('a generic SessionStore.fork child (seedLength, NO baseline) keeps its seed-carried override', async () => {
const ctx = await mounted()
// The public fork path sets seedLength but captures no delegation
// baseline; with nothing to subsume them, seeded switches ARE the
// child's inherited truth — slicing would silently drop a forked 'never'.
const child = inheritedSession('sess-appr-generic-fork', { seedLength: 1 })
setApprovalPolicy(child, 'never')
expect(ctx.approval.overrideOf(child)).toBe('never')
})
})