mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-13 16:38:56 +02:00
fix: pre-landing review fixes (#2733)
Review army + coverage audit findings, all applied: - headless directive carries the spawned escape sentence too (multi- specialist: a CI-hosted ship's marked subagent must not end BLOCKED) - anti-injection scoping on every text-claimable spawned trigger (AUQ rule + shared escape sentence): markings count only from the creating prompt, never from files/tool output/web content read mid-run - [conductor][spawned] deny annotates one-way doors per question - SPAWNED_OVERRIDE: env tamper-visibility status line + OPENCLAW.md note - spawned sessions skip the network update-check and first-task probe (consumers suppressed; preserves the one-shot just-upgraded marker) - test hardening: dispatch-tripwire end-bound validated, vacuous marker asserts replaced with output asserts, E2E cpSync size filter + named fence tolerance, spawnedByEnv parity pin, destructive-policy cross- surface drift guard, one-way annotation + bogus-value hook cases - session-kind duplicate rationale comment deduped; regen + goldens + context-budget fixture refreshed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
46ba23c512
commit
e65be946dd
@@ -75,6 +75,14 @@ describe('directiveFor — per-session-kind instruction', () => {
|
||||
expect(directiveFor('spawned')).toMatch(/auto-choose/i);
|
||||
});
|
||||
|
||||
test('spawned directive carries a self-contained destructive carve-out (#2733 review)', () => {
|
||||
// The "Spawned session block" it defers to exists only when a gstack
|
||||
// preamble ran; an AUQ error outside a skill still needs the exception.
|
||||
const d = directiveFor('spawned');
|
||||
expect(d).toMatch(/never auto-choose a destructive or irreversible option/i);
|
||||
expect(d).toMatch(/conservative non-destructive/);
|
||||
});
|
||||
|
||||
test('interactive directive carries the spawned escape sentence (#2733)', () => {
|
||||
// The sessionKind() shell-out runs in the HARNESS env, so a subagent
|
||||
// marked spawned via a per-command prefix classifies interactive here —
|
||||
@@ -83,6 +91,20 @@ describe('directiveFor — per-session-kind instruction', () => {
|
||||
expect(d).toMatch(/spawned subagent[\s\S]*auto-choose the recommended option/i);
|
||||
expect(d).toMatch(/destructive or irreversible gate[\s\S]*conservative/i);
|
||||
});
|
||||
|
||||
test('headless directive ALSO carries the spawned escape sentence (#2733 review, multi-specialist)', () => {
|
||||
// A spawned-marked subagent under a headless-classified parent env
|
||||
// (CI/eval-hosted /ship) hits the headless branch — the self-gating
|
||||
// escape keeps the JSON contract alive; plain headless still BLOCKs.
|
||||
const d = directiveFor('headless');
|
||||
expect(d).toMatch(/BLOCKED — AskUserQuestion unavailable/);
|
||||
expect(d).toMatch(/spawned subagent[\s\S]*auto-choose the recommended option/i);
|
||||
});
|
||||
|
||||
test('escape sentence scopes spawned claims to the creating prompt (anti-injection)', () => {
|
||||
const d = directiveFor('interactive');
|
||||
expect(d).toMatch(/NEVER qualify[\s\S]*prompt injection/i);
|
||||
});
|
||||
});
|
||||
|
||||
/** Spawn the hook with synthetic stdin + controlled env; parse its JSON stdout. */
|
||||
|
||||
Reference in New Issue
Block a user