review pass: purge stale enforcement language after the axis decoupling
Self-review findings, all prose/metadata (no behavior change): the package description still claimed hard (execution) enforcement; the RFC Problem framing still defined plan mode as a read-only tool policy; integration/mode/snapshot-suite comments still referenced the removed sandbox clamp and cap; the header-fallback explanation said 'front-of-list insertion' where the actual mechanism is a non-tail insertion the append-only tools delta cannot express (exit_plan_mode sits mid-list alphabetically); AGENTS.md's layout line and the RFC's 'policy state/listener' phrasing move to collaboration-state wording.
This commit is contained in:
@@ -10,7 +10,7 @@ The `default` mode is the absence of policy: no section, no extra tool. An agent
|
||||
|
||||
## What a mode carries
|
||||
|
||||
**The guidance section.** A `system-prompt/assemble` listener renders the mode's `section` text as the `mode:policy` section (order 50) while the mode is in force, and shows the `exit_plan_mode` tool IFF the folded mode is `plan` — on the wire and, under the registry's Code Mode, in the `tools:sdk` section alike. Every transition therefore surfaces as an attributable `request/header` event on the next step (entering plan adds the exit tool, a front-of-list insertion with no delta form → the full fallback snapshot; the approved exit removes exactly that tool and the section, a pure removal → one `request/header-delta`).
|
||||
**The guidance section.** A `system-prompt/assemble` listener renders the mode's `section` text as the `mode:policy` section (order 50) while the mode is in force, and shows the `exit_plan_mode` tool IFF the folded mode is `plan` — on the wire and, under the registry's Code Mode, in the `tools:sdk` section alike. Every transition therefore surfaces as an attributable `request/header` event on the next step (entering plan adds the exit tool at its canonical alphabetical position — a non-tail insertion the append-only tools delta cannot express → the full fallback snapshot; the approved exit removes exactly that tool and the section, a pure removal → one `request/header-delta`).
|
||||
|
||||
**Deliberately absent: enforcement.** A mode never gates execution, filters the toolset, or touches the sandbox/approval knobs — those are independent axes the user switches separately (a deployment that wants a hard read-only floor while planning flips the sandbox-mode option beside the mode picker, in either order; neither disturbs the other). A per-mode tool allow/deny list is likewise out: which tools a mode admits is an effects question — a per-tool read-only/mutating classification the harness does not yet have — parked until tool definitions declare their effects (the plan-mode RFC's deferred item). The config vocabulary is exactly `{ section }`, and an unknown key (a `tools` list or an `access` cap included) fails loud at load.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@deepseek-ai/dsh-mode",
|
||||
"description": "Session modes for the DeepSeek Harness: plan mode as logged per-agent policy state with soft (prompt) and hard (execution) enforcement",
|
||||
"description": "Session modes for the DeepSeek Harness: plan mode as a logged per-agent collaboration state with a guidance section and a user-reviewed exit",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -82,9 +82,9 @@ describe('plan mode through the agent loop', () => {
|
||||
expect(header.data.header.tools?.map(tool => tool.name)).toEqual(['exit_plan_mode', 'read', 'write'])
|
||||
expect(header.data.header.system).toContain('plan mode')
|
||||
|
||||
// No general tool gate: the write RUNS — plan's non-shell restraint is
|
||||
// the section's guidance (the shell restraint is the sandbox clamp,
|
||||
// pinned in mode.spec). The mode itself stays plan throughout.
|
||||
// No tool gate: the write RUNS — plan restrains by the section's
|
||||
// guidance alone (enforcement lives on the independent sandbox/approval
|
||||
// axes). The mode itself stays plan throughout.
|
||||
const result = findEvent(log, 'tool/result')
|
||||
expect(result.data.isError).toBe(false)
|
||||
expect(foldMode(log)).toBe(PLAN_MODE)
|
||||
@@ -115,8 +115,10 @@ describe('plan mode through the agent loop', () => {
|
||||
{ type: 'text', text: 'The user switched this session to plan mode.' },
|
||||
])
|
||||
// The header change is logged as a FULL fallback snapshot, not a delta:
|
||||
// adding exit_plan_mode reorders the canonical tool list (it sorts
|
||||
// first), and a pure reordering is inexpressible in the delta encoding.
|
||||
// the tools delta can only APPEND additions, while the canonical
|
||||
// (alphabetical) order places exit_plan_mode before read/write — a
|
||||
// non-tail insertion the writer's round-trip guard rejects, so it
|
||||
// falls back.
|
||||
const second = findEvent(log, 'request/header', 'last')
|
||||
expect(second.data.reason).toBe('fallback')
|
||||
expect(second.data.header.tools?.map(tool => tool.name)).toEqual(['exit_plan_mode', 'read', 'write'])
|
||||
|
||||
@@ -350,10 +350,10 @@ describe('the soft layer', () => {
|
||||
|
||||
it('leaves foreign post-next() additions alone in plan mode (no general tool filtering)', async () => {
|
||||
// A foreign listener that post-processes await next(): the mode filter
|
||||
// wraps outside it (prepend) but hides only the exit tool outside plan
|
||||
// and the bash trio under an unhonorable cap — a foreign addition
|
||||
// survives, because which tools a mode admits is deliberately not this
|
||||
// plugin's decision (the effects question stays parked; module doc).
|
||||
// wraps outside it (prepend) but hides only the exit tool outside plan —
|
||||
// a foreign addition survives, because which tools a mode admits is
|
||||
// deliberately not this plugin's decision (the effects question stays
|
||||
// parked; module doc).
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry)
|
||||
@@ -388,8 +388,8 @@ describe('the soft layer', () => {
|
||||
agent.session.append('mode/set', { mode: PLAN_MODE })
|
||||
const assembly = await ctx.systemPrompt.assemble({ agent })
|
||||
expect(assembly.tools.map(tool => tool.name)).toEqual(['run_code'])
|
||||
// The SDK documents the full binding set plus the exit — plan mode no
|
||||
// longer prunes capabilities; its restraint is the section + the sandbox.
|
||||
// The SDK documents the full binding set plus the exit — a mode never
|
||||
// prunes capabilities; it restrains by the section's guidance alone.
|
||||
const sdk = assembly.sections.find(section => section.name === 'tools:sdk')?.text ?? ''
|
||||
expect(sdk).toContain('read(args:')
|
||||
expect(sdk).toContain('write(args:')
|
||||
|
||||
Reference in New Issue
Block a user