From 6c2fa0894567a0a6c55b5a0e28e6eef6fcc3ce89 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 19 Aug 2026 20:12:55 -0500 Subject: [PATCH 1/2] Sync delta specs for the last two completed changes Apply the redirect-shared-temp-to-session-scratch delta to session-cwd and tool-approval-gates. The OpenSpec CLI applied both files. Merge the surface-reminder-schedule-failures delta into netclaw-scheduling by hand. PR #2024 already corrected that requirement against the merged code, so a programmatic apply would undo those corrections. Keep the corrected text and add the scheduling-failure content: - An execution failure and a scheduling failure share one ConsecutiveFailures count. - A successful reschedule alone does not reset the count. - An unattended reschedule site emits ReminderScheduleFailed at Warning severity, and ReminderAutoDisabled at Critical severity on the threshold. - The set_reminder create path and update path return the error to the caller and emit no alert. Drop three stale delta claims. The merged code disables a reminder. It does not set a "paused" status and it does not write tasks.json. ReminderExecutionActor has no ExecutionTimeoutSeconds constant, so the one-hour absolute limit stands. --- openspec/specs/netclaw-scheduling/spec.md | 87 ++++++- openspec/specs/session-cwd/spec.md | 85 +++++-- openspec/specs/tool-approval-gates/spec.md | 257 +++++++++++++++++++++ 3 files changed, 410 insertions(+), 19 deletions(-) diff --git a/openspec/specs/netclaw-scheduling/spec.md b/openspec/specs/netclaw-scheduling/spec.md index 503f396d8..3c8d7e1c9 100644 --- a/openspec/specs/netclaw-scheduling/spec.md +++ b/openspec/specs/netclaw-scheduling/spec.md @@ -333,7 +333,11 @@ when listing tasks. ### Requirement: Failure handling and guardrails The reminder manager SHALL store consecutive failures in each reminder -definition. A successful execution SHALL reset the count. +definition. An execution failure and a scheduling failure SHALL increment the +same count. A successful execution SHALL reset the count. A successful +reschedule alone SHALL NOT reset the count. The post-fire reschedule of a cron +reminder runs before that occurrence executes. A reset at that point erases a +pending execution-failure count. The manager SHALL disable a reminder when the count reaches `FailurePauseThreshold`. The disabled definition SHALL remain available for @@ -356,6 +360,28 @@ is acceptable. Each execution SHALL have a one-hour absolute limit. A known timeout SHALL count as a failed attempt. +A scheduling failure is a failure to compute or install the next occurrence at +an unattended reschedule site. The two unattended sites are the post-fire +reschedule of a recurring reminder and the startup reconcile restore loop. +Causes include an unresolvable `CRON_TZ` time zone, a cron expression with no +future occurrence, and an uninitialized reminder client. + +At an unattended site, the manager SHALL do all of the following: + +- increment the reminder's `ConsecutiveFailures` count; +- emit an `OperationalAlert.ReminderScheduleFailed` alert at Warning severity; +- disable the reminder when the count reaches `FailurePauseThreshold`, emit an + `OperationalAlert.ReminderAutoDisabled` alert at Critical severity, and post a + channel notice. + +The manager SHALL NOT evaluate an unresolvable time zone in UTC. The manager +SHALL NOT skip a failed reschedule without a report. A fire at the wrong time is +worse than a missed fire. + +The create path and the update path (`set_reminder`) SHALL return a scheduling +error to the caller. Those paths SHALL NOT emit a scheduling-failure alert, +because the caller already sees the error. + #### Scenario: Consecutive failures disable a reminder - **GIVEN** a reminder has one fewer failure than `FailurePauseThreshold` @@ -384,6 +410,65 @@ count as a failed attempt. - **THEN** the execution is cancelled and reported as a failure - **AND** the failure is counted toward `FailurePauseThreshold` +#### Scenario: Post-fire reschedule failure is surfaced + +- **GIVEN** a recurring reminder fires +- **AND** the manager cannot compute its next occurrence +- **WHEN** the manager attempts the post-fire reschedule +- **THEN** the manager increments the reminder's `ConsecutiveFailures` count +- **AND** the manager emits an `OperationalAlert.ReminderScheduleFailed` alert +- **AND** the current occurrence still executes + +#### Scenario: Reconcile schedule failure is surfaced + +- **GIVEN** an enabled reminder whose next occurrence is not computable at startup +- **WHEN** the reconcile restore loop attempts to reschedule it +- **THEN** the manager increments the reminder's `ConsecutiveFailures` count +- **AND** the manager emits an `OperationalAlert.ReminderScheduleFailed` alert +- **AND** the manager does not skip the reminder without a report + +#### Scenario: Consecutive scheduling failures disable a reminder + +- **GIVEN** a reminder has one fewer scheduling failure than `FailurePauseThreshold` +- **WHEN** the manager reports the next scheduling failure +- **THEN** the manager disables the reminder +- **AND** the manager emits an `OperationalAlert.ReminderAutoDisabled` alert at + Critical severity +- **AND** the manager posts a channel notice + +#### Scenario: A successful execution resets scheduling failures + +- **GIVEN** a reminder has two consecutive scheduling failures +- **AND** its schedule recovers, so the reminder fires again +- **WHEN** that occurrence executes successfully +- **THEN** the manager saves a zero failure count + +#### Scenario: A successful reschedule alone does not reset the count + +- **GIVEN** a cron reminder has a failure count above zero +- **WHEN** the post-fire reschedule of an occurrence succeeds +- **THEN** the manager keeps the current failure count +- **AND** only a later successful execution resets it + +#### Scenario: An unresolvable time zone never falls back to UTC + +- **GIVEN** a cron reminder with an unresolvable `CRON_TZ` time zone +- **WHEN** the manager attempts a reschedule at an unattended site +- **THEN** the manager schedules no occurrence +- **AND** the manager does not evaluate the reminder in UTC +- **AND** the manager reports the failure through the count and a + `ReminderScheduleFailed` alert + +#### Scenario: One bad startup does not disable many reminders + +- **GIVEN** many enabled reminders whose schedules all fail once at startup +- **AND** `FailurePauseThreshold` is greater than one +- **WHEN** the reconcile restore loop runs +- **THEN** the manager increments each affected count by one +- **AND** the manager disables no reminder because of one startup failure +- **AND** the manager emits an `OperationalAlert.ReminderScheduleFailed` alert + for each affected reminder + ### Requirement: Execution history CLI command The CLI SHALL provide a `netclaw reminder history ` subcommand that diff --git a/openspec/specs/session-cwd/spec.md b/openspec/specs/session-cwd/spec.md index b35ad0d84..0dc7012bd 100644 --- a/openspec/specs/session-cwd/spec.md +++ b/openspec/specs/session-cwd/spec.md @@ -176,38 +176,46 @@ the approval policy depends on. ### Requirement: Shell tool failure-path hint for cwd outside safe spaces -`ShellTool` SHALL include a one-line hint in the tool result returned -to the model when a call is denied because its cwd is outside both -`session_dir` and `project_dir`. The hint SHALL suggest -`set_working_directory ` with the path that triggered the denial, -in a format recognizable to the agent so it can self-correct without a -roundtrip through the user. +`ShellTool` SHALL include a one-line remediation hint in the tool result returned to the model when a call is denied because its cwd is outside both `session_dir` and `project_dir` and a safe correction is available. -The hint SHALL only be emitted when the denial reason is "cwd outside -safe spaces" and `set_working_directory` is in the audience's tool -exposure list. The hint SHALL NOT be emitted for hard-deny-list refusals -or for `ToolPathPolicy` denials (those have different remediation paths). +For a non-temp cwd, the hint SHALL suggest `set_working_directory ` only when that tool is exposed and the same filesystem policy used by `set_working_directory` accepts the exact path without substitution. For a Personal cwd equal to the captured platform temporary root, the hint SHALL instead identify the exact session directory as private scratch and SHALL NOT suggest declaring the platform temporary root. Team and Public shell calls retain their existing earlier denial boundary, and Public results SHALL retain existing path redaction. -#### Scenario: Denial in foreign tree includes set_working_directory hint +The hint SHALL NOT be emitted for hard-deny-list refusals, `ToolPathPolicy` denials, an unavailable session scratch path, or a foreign non-temp cwd that `set_working_directory` would reject. + +#### Scenario: Denial in declarable foreign tree includes set_working_directory hint - **GIVEN** a Personal session with `project_dir` not set +- **AND** the shared directory policy accepts `~/repos/bar/` - **WHEN** the agent invokes `shell_execute` with cwd `~/repos/bar/` - **AND** the user denies the resulting prompt -- **THEN** the tool result includes a hint pointing at - `set_working_directory ~/repos/bar/` +- **THEN** the tool result includes a hint pointing at `set_working_directory ~/repos/bar/` + +#### Scenario: Denied platform-temp retry retains scratch recommendation + +- **GIVEN** an agent received the session-scratch correction for the platform temporary root +- **AND** it repeated the original call unchanged to request ordinary approval +- **WHEN** the user denies that approval +- **THEN** the tool result identifies the exact session directory as private scratch +- **AND** it does not suggest `set_working_directory` for the platform temporary root + +#### Scenario: Undeclarable foreign tree has no project declaration hint + +- **GIVEN** a non-temp cwd is outside the roots accepted by `set_working_directory` +- **WHEN** the user denies the resulting shell prompt +- **THEN** the tool result does not suggest declaring that cwd #### Scenario: Hint is not emitted for hard-deny refusals - **GIVEN** a hard-deny-list block on the command - **WHEN** `shell_execute` returns the deny error -- **THEN** the result does NOT include a `set_working_directory` hint +- **THEN** the result does NOT include a working-directory remediation hint -#### Scenario: Hint is not emitted when set_working_directory is unavailable +#### Scenario: Hint is not emitted when remediation tools are unavailable -- **GIVEN** a Public session where `set_working_directory` is not in - the tool exposure list +- **GIVEN** a Public session where `set_working_directory` is not exposed +- **AND** no private session-scratch correction is available - **WHEN** a shell call is denied for cwd-outside-safe-space -- **THEN** the result does NOT include a `set_working_directory` hint +- **THEN** the result does NOT include a working-directory remediation hint ### Requirement: set_working_directory expands the approval safe space @@ -348,3 +356,44 @@ The context SHALL be derived from the child run's existing bound session scope. - **THEN** its project scope and project instructions update through the existing contract - **AND** its bound `session_dir` remains unchanged +### Requirement: Session directory is the private shell scratch location + +The system SHALL identify the existing per-session directory as the private scratch location for disposable shell artifacts. Personal and Team model-visible working-context and correction text SHALL provide its absolute path when the agent needs an alternative to the platform temporary root. Public contexts SHALL retain existing path redaction and SHALL NOT receive the private absolute session path. The system SHALL NOT create a second scratch directory, silently substitute the path, or imply that session-directory cleanup occurs as part of this behavior. + +#### Scenario: Shell without project scope defaults to session scratch + +- **GIVEN** a session has no declared project directory +- **AND** its session directory is `/home/user/.netclaw/sessions/example` +- **WHEN** the agent invokes `shell_execute` without an explicit working directory +- **THEN** the shell working directory is `/home/user/.netclaw/sessions/example` +- **AND** the working context identifies that directory as session scratch + +#### Scenario: Scratch recommendation uses the existing session directory + +- **GIVEN** a correction recommends private scratch +- **WHEN** the correction is rendered for the agent +- **THEN** it names the exact existing session directory +- **AND** it does not name a newly created `scratch` child directory + +#### Scenario: Public context does not receive private scratch path + +- **GIVEN** a Public parent agent or subagent +- **WHEN** it evaluates a platform-temp shell call +- **THEN** it does not receive the private session-directory path +- **AND** existing Public path-redaction behavior remains + +#### Scenario: Personal and Team headless context nudges scratch use + +- **GIVEN** a Personal or Team headless session +- **WHEN** its working context is assembled +- **THEN** the context identifies the exact session directory as private scratch for disposable artifacts +- **AND** it states that an explicitly required platform-temp path must be preserved +- **AND** it does not imply that approval prompts or automatic cleanup exist + +#### Scenario: No cleanup is implied + +- **GIVEN** an agent writes a disposable artifact under the session directory +- **WHEN** the current session ends +- **THEN** this capability does not delete or schedule deletion of that artifact +- **AND** retention remains unchanged until a separate cleanup capability is specified + diff --git a/openspec/specs/tool-approval-gates/spec.md b/openspec/specs/tool-approval-gates/spec.md index 854da6eba..0175dbeb4 100644 --- a/openspec/specs/tool-approval-gates/spec.md +++ b/openspec/specs/tool-approval-gates/spec.md @@ -2102,3 +2102,260 @@ current-shell brace groups. - **THEN** Netclaw does not authorize the visible safe verb - **AND** Netclaw offers no persistent approval candidate +### Requirement: Platform temporary scope receives a session-scratch correction + +After tool exposure, hard deny, protected-path, and shell-analysis checks, the system SHALL return a typed session-scratch correction instead of immediately requesting approval when a Personal shell call explicitly authors the platform temporary root through the typed `WorkingDirectory` or an eligible Bash leading directory transition, every policy-relevant occurrence remains within that root, the session directory is a valid nonempty normalized path, interactive approval is available, and the ordinary result would otherwise request approval. The session directory SHALL NOT need to exist before the correction because replacement execution owns its creation. An inherited project, session, subagent, or default cwd SHALL NOT establish this authored intent. The correction SHALL identify the exact session directory and ask the agent to author a replacement call there. It SHALL execute nothing, record no grant, change no working context, and SHALL NOT rewrite the original call. Team and Public shell calls SHALL retain their existing earlier denial boundary and SHALL NOT receive this correction or the private session path. + +An internal immutable policy value SHALL capture the platform temporary root once when shell approval policy is constructed, using the resolved shell environment's path style. Matching SHALL use platform path rules and SHALL NOT use executable-specific parsing. This capability SHALL NOT add a public `ShellExecutionEnvironment` member. + +For Bash causal-directory advice, the system SHALL consume ShellSyntaxTree's exact leading `IsCwdAttribution` and `CommandOccurrence.WorkingDirectory` facts directly. Because the correction grants and executes nothing, it SHALL NOT require the parent causal-approval intent's pre-existing grant coverage. Actual execution, safe-policy coverage, and folder-grant decisions SHALL retain those authority preconditions, and Netclaw SHALL NOT add a second `cd` parser. Native PowerShell causal directory mutation remains ineligible. + +The system SHALL resolve the captured platform temporary root to its final filesystem target at startup. Every relevant cwd and authored filesystem path SHALL remain beneath that canonical target without a descendant symbolic link, junction, or reparse point. An attribute or target-resolution failure SHALL suppress the correction. + +Platform-temp correction SHALL take precedence over undeclared-project correction. The undeclared-project correction SHALL treat the platform temporary root as ineligible, and one shell attempt SHALL return at most one correction. + +#### Scenario: Explicit POSIX temporary working directory receives correction + +- **GIVEN** the platform temporary root is `/tmp` +- **AND** the session directory is `/home/user/.netclaw/sessions/example` +- **WHEN** a complete shell call requests `WorkingDirectory=/tmp` +- **AND** ordinary policy would request user approval +- **THEN** the agent receives a `SessionScratchSuggested` correction before the user approval surface +- **AND** the correction names `/home/user/.netclaw/sessions/example` +- **AND** the original call is not executed or rewritten + +#### Scenario: Fresh session scratch need not exist yet + +- **GIVEN** a fresh session has a valid normalized session-directory path +- **AND** that directory has not yet been created on disk +- **WHEN** its first shell call explicitly authors the platform temporary root +- **AND** every other correction condition passes +- **THEN** the system emits `SessionScratchSuggested` +- **AND** replacement shell execution creates the session directory through the existing shell cwd path + +#### Scenario: Static causal directory change receives correction + +- **GIVEN** the platform temporary root is `/tmp` +- **WHEN** the agent authors `cd /tmp && diagnostic-command > result.log && head result.log` +- **AND** every policy-relevant effective directory remains `/tmp` +- **AND** ordinary policy would request approval +- **THEN** the correction asks the agent to author the temporary-artifact operation under the session directory +- **AND** no executable-specific rule for `diagnostic-command` or `head` is required +- **AND** the advice does not require prior grant coverage for `cd` or the first action +- **AND** later execution still requires ordinary authority + +#### Scenario: Windows temporary working directory receives correction + +- **GIVEN** the native Windows shell environment captured `C:\\Users\\user\\AppData\\Local\\Temp` as its platform temporary root +- **WHEN** a complete PowerShell call requests that exact working directory +- **AND** ordinary policy would request approval +- **THEN** the agent receives the same typed correction with its Windows session-directory path + +#### Scenario: Native PowerShell causal directory remains strict + +- **GIVEN** the native Windows shell is PowerShell +- **WHEN** the agent authors `Set-Location $env:TEMP; diagnostic-command` or `cd $env:TEMP; diagnostic-command` +- **THEN** the system does not emit the session-scratch correction +- **AND** normal approval or deny behavior remains + +#### Scenario: Platform temp is never proposed as project scope + +- **GIVEN** a reviewed-safe shell call whose exact cwd is the platform temporary root +- **AND** both scope-correction predicates would otherwise be eligible +- **WHEN** policy selects an agent correction +- **THEN** it returns only `SessionScratchSuggested` +- **AND** it does not recommend `set_working_directory` for the platform temporary root + +#### Scenario: Dynamic temporary directory remains strict + +- **WHEN** the parser cannot prove the effective directory for `cd "$TMPDIR" && diagnostic-command` +- **THEN** the system does not emit the session-scratch correction +- **AND** normal approval or deny behavior remains + +#### Scenario: Dynamic identity remains on ordinary path + +- **WHEN** an authored call is `cd /tmp && "$tool"` +- **OR** command substitution controls command identity or flow +- **THEN** the system does not emit the session-scratch correction +- **AND** normal approval or deny behavior remains + +#### Scenario: Unresolved redirect remains on ordinary path + +- **WHEN** an authored platform-temp call has a redirect target the parser cannot resolve +- **THEN** the system does not emit the session-scratch correction +- **AND** normal approval or deny behavior remains + +#### Scenario: Complete prompt-worthy work may receive advice + +- **GIVEN** every command identity, control-flow edge, cwd, and redirect is complete and static +- **AND** the call would prompt because it writes, mutates, or performs a network action +- **WHEN** its explicitly authored execution scope is the platform temporary root +- **THEN** it may receive the advice-only session-scratch correction +- **AND** a replacement or intentional retry still receives complete ordinary authorization + +#### Scenario: Mixed incomplete batch remains on ordinary path + +- **GIVEN** one candidate is reviewed safe +- **AND** another candidate has incomplete identity, control flow, cwd, or redirect facts +- **WHEN** policy evaluates the batch +- **THEN** it does not emit the session-scratch correction +- **AND** the incomplete candidate cannot hide behind the reviewed-safe candidate + +#### Scenario: Public parent and subagent retain path redaction + +- **GIVEN** a Public parent agent or subagent +- **WHEN** it submits a platform-temp shell call +- **THEN** the system does not emit `SessionScratchSuggested` +- **AND** it does not disclose the private session-directory path +- **AND** normal Public policy remains + +#### Scenario: Inherited temp project does not imply authored intent + +- **GIVEN** a recovered parent session has `ProjectDirectory=/tmp` +- **OR** a subagent inherits `/tmp` as its cwd +- **WHEN** it submits a shell call without an explicit `WorkingDirectory` or Bash leading transition +- **THEN** the system does not emit `SessionScratchSuggested` +- **AND** normal policy evaluates the inherited scope + +#### Scenario: External authored path prevents correction + +- **GIVEN** a call runs under the platform temporary root +- **AND** an authored absolute path resolves outside that root +- **WHEN** policy evaluates the call +- **THEN** the system does not emit the session-scratch correction +- **AND** normal approval or deny behavior remains + +#### Scenario: POSIX symlink escape prevents correction + +- **GIVEN** `/tmp/outside` is a symbolic link to `/etc` +- **WHEN** a platform-temp call references `/tmp/outside/passwd` or redirects to `/tmp/outside/result` +- **THEN** the system does not emit the session-scratch correction +- **AND** normal approval or deny behavior remains + +#### Scenario: Windows reparse escape prevents correction + +- **GIVEN** a descendant of the Windows temporary root is a junction or reparse point outside that root +- **WHEN** a platform-temp call references that descendant +- **THEN** the system does not emit the session-scratch correction + +#### Scenario: Link inspection failure prevents correction + +- **WHEN** the system cannot resolve the platform temporary root or inspect a relevant descendant's attributes +- **THEN** it does not emit the session-scratch correction + +#### Scenario: Hard deny and protected path retain precedence + +- **GIVEN** a shell call runs under the platform temporary root +- **WHEN** the call triggers hard deny or protected-path policy +- **THEN** the system denies the call +- **AND** it does not emit the session-scratch correction + +#### Scenario: Replacement receives full authorization + +- **GIVEN** the agent receives a session-scratch correction +- **WHEN** it authors a replacement call under the named session directory +- **THEN** the system evaluates the replacement as a new call through every normal authorization stage +- **AND** the correction does not guarantee automatic execution + +#### Scenario: Headless execution retains existing temporary-directory behavior + +- **GIVEN** a headless, scheduled, webhook, benchmark, or other noninteractive run +- **WHEN** an authored shell call requires the platform temporary root or an absolute path beneath it +- **THEN** the system does not emit the session-scratch correction +- **AND** it does not rewrite or remove the authored temporary path +- **AND** the existing noninteractive authorization result remains unchanged + +#### Scenario: Personal or Team headless model guidance prefers session scratch + +- **GIVEN** a Personal or Team headless session announces its exact session directory as scratch +- **AND** a task requests disposable artifacts without requiring a platform path +- **WHEN** the agent authors its shell call +- **THEN** it uses the announced session directory rather than the platform temporary root +- **AND** no interactive correction or approval prompt is involved + +#### Scenario: Public headless context retains path redaction + +- **GIVEN** a Public headless session +- **WHEN** its working context is assembled +- **THEN** the exact private session path is not disclosed +- **AND** the platform-temp correction is not emitted + +#### Scenario: Headless task with explicit temp requirement preserves intent + +- **GIVEN** a headless or benchmark task explicitly requires the platform temporary directory +- **WHEN** the agent authors its shell call +- **THEN** it preserves the required platform-temp path +- **AND** Netclaw does not redirect, defer, or prompt +- **AND** existing noninteractive policy decides allow or deny + +### Requirement: Intentional platform-temp retry reaches ordinary approval + +The system SHALL prevent correction loops with actor-owned, non-persistent correction keys for the active user turn. A key SHALL cover canonical shell, command text, explicit working-directory presence and value, resolved temporary scope, background mode, and timeout. It SHALL deliberately exclude rationale because rationale does not alter execution. The actor SHALL arm a key only after the correction result is committed to model history. Identical calls in one parallel batch SHALL all remain first attempts. A later equivalent tool iteration SHALL atomically consume one armed key, suppress that correction once, and expose exactly `Once` and `Deny`. The system SHALL NOT offer session, folder, or global persistence for this retry and SHALL NOT write it to an actor grant or approval store. + +The actor SHALL clear keys on turn completion, cancellation, failure, passivation or recovery, and before a new user turn. A consumed key SHALL NOT suppress an unlimited sequence of retries. + +#### Scenario: Equivalent retry requests one-time approval + +- **GIVEN** the agent received a session-scratch correction for a platform-temp call +- **WHEN** the agent repeats an equivalent call unchanged during the active turn +- **THEN** the system does not repeat the same correction +- **AND** it requests ordinary user approval when that is the underlying policy result +- **AND** the approval choices are exactly `Once` and `Deny` +- **AND** approval executes the agent-authored call exactly +- **AND** no session or persistent grant is recorded + +#### Scenario: Parallel duplicate first attempts all receive correction + +- **GIVEN** one model batch contains two equivalent eligible platform-temp calls +- **WHEN** the parent or subagent pipeline evaluates them concurrently +- **THEN** both calls receive first-attempt corrections +- **AND** neither call reaches approval based on the other call's uncommitted result + +#### Scenario: Later iteration consumes correction key once + +- **GIVEN** a correction result is committed to model history +- **WHEN** a later tool iteration repeats the equivalent call +- **THEN** the actor consumes the armed key and exposes `Once` and `Deny` +- **AND** a subsequent equivalent attempt has no residual execution or grant authority + +#### Scenario: Execution-meta change is not an unchanged retry + +- **GIVEN** a correction key was armed for a foreground call with one timeout +- **WHEN** a later call changes background mode, timeout, command text, or explicit cwd presence or value +- **THEN** it does not consume that correction key +- **AND** it receives a complete first-attempt policy evaluation + +#### Scenario: Rationale-only change remains equivalent + +- **GIVEN** a correction key was armed for a platform-temp call +- **WHEN** a later call changes only `_rationale` +- **THEN** rationale does not prevent equivalence +- **AND** the execution semantics still receive the bounded retry behavior + +#### Scenario: Correction key does not persist + +- **GIVEN** a platform-temp correction occurred in an earlier turn +- **WHEN** a later turn submits the same call +- **THEN** no persisted correction key grants authority or bypasses policy +- **AND** the call receives the current turn's complete policy evaluation + +#### Scenario: Lifecycle boundaries clear correction keys + +- **WHEN** a turn completes, cancels, fails, passivates, recovers, or a new user turn begins +- **THEN** every armed or consumed scratch-correction key from the prior lifecycle is cleared + +### Requirement: Parent and subagent scratch corrections are equivalent + +The parent session pipeline and subagent pipeline SHALL consume the same typed session-scratch correction before they invoke their respective user or parent approval bridges. + +#### Scenario: Parent agent is corrected before user prompt + +- **WHEN** a parent agent submits an eligible platform-temp call +- **THEN** it receives the correction before a user approval prompt is created + +#### Scenario: Subagent is corrected before parent bridge + +- **WHEN** a subagent submits an eligible platform-temp call +- **THEN** it receives the same correction before a parent approval request is created +- **AND** the parent user is not prompted for that first attempt + From 4fdd43c29041771d130bf9d601b20f8f49420aa3 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 19 Aug 2026 20:13:01 -0500 Subject: [PATCH 2/2] Archive the last two completed OpenSpec changes Move each change to openspec/changes/archive/2026-08-19-/. The code of both changes is merged on dev. - surface-reminder-schedule-failures: PR #1886. - redirect-shared-temp-to-session-scratch: PRs #1890, #1925, #1926, #1945, and #1956. Tick task 4.3 of redirect-shared-temp-to-session-scratch. The full pr_validation suite ran green on Windows against current dev. Leave the other boxes unticked. The maintainer accepts tasks 4.5 and 4.6 of surface-reminder-schedule-failures as guaranteed by construction. The maintainer accepts task 6.4 of that change and task 4.4 of redirect-shared-temp-to-session-scratch as an eval-credentials gap. --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/session-cwd/spec.md | 0 .../specs/tool-approval-gates/spec.md | 0 .../tasks.md | 2 +- .../.openspec.yaml | 0 .../2026-08-19-surface-reminder-schedule-failures}/design.md | 0 .../2026-08-19-surface-reminder-schedule-failures}/proposal.md | 0 .../specs/netclaw-scheduling/spec.md | 0 .../2026-08-19-surface-reminder-schedule-failures}/tasks.md | 0 11 files changed, 1 insertion(+), 1 deletion(-) rename openspec/changes/{redirect-shared-temp-to-session-scratch => archive/2026-08-19-redirect-shared-temp-to-session-scratch}/.openspec.yaml (100%) rename openspec/changes/{redirect-shared-temp-to-session-scratch => archive/2026-08-19-redirect-shared-temp-to-session-scratch}/design.md (100%) rename openspec/changes/{redirect-shared-temp-to-session-scratch => archive/2026-08-19-redirect-shared-temp-to-session-scratch}/proposal.md (100%) rename openspec/changes/{redirect-shared-temp-to-session-scratch => archive/2026-08-19-redirect-shared-temp-to-session-scratch}/specs/session-cwd/spec.md (100%) rename openspec/changes/{redirect-shared-temp-to-session-scratch => archive/2026-08-19-redirect-shared-temp-to-session-scratch}/specs/tool-approval-gates/spec.md (100%) rename openspec/changes/{redirect-shared-temp-to-session-scratch => archive/2026-08-19-redirect-shared-temp-to-session-scratch}/tasks.md (98%) rename openspec/changes/{surface-reminder-schedule-failures => archive/2026-08-19-surface-reminder-schedule-failures}/.openspec.yaml (100%) rename openspec/changes/{surface-reminder-schedule-failures => archive/2026-08-19-surface-reminder-schedule-failures}/design.md (100%) rename openspec/changes/{surface-reminder-schedule-failures => archive/2026-08-19-surface-reminder-schedule-failures}/proposal.md (100%) rename openspec/changes/{surface-reminder-schedule-failures => archive/2026-08-19-surface-reminder-schedule-failures}/specs/netclaw-scheduling/spec.md (100%) rename openspec/changes/{surface-reminder-schedule-failures => archive/2026-08-19-surface-reminder-schedule-failures}/tasks.md (100%) diff --git a/openspec/changes/redirect-shared-temp-to-session-scratch/.openspec.yaml b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/.openspec.yaml similarity index 100% rename from openspec/changes/redirect-shared-temp-to-session-scratch/.openspec.yaml rename to openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/.openspec.yaml diff --git a/openspec/changes/redirect-shared-temp-to-session-scratch/design.md b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/design.md similarity index 100% rename from openspec/changes/redirect-shared-temp-to-session-scratch/design.md rename to openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/design.md diff --git a/openspec/changes/redirect-shared-temp-to-session-scratch/proposal.md b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/proposal.md similarity index 100% rename from openspec/changes/redirect-shared-temp-to-session-scratch/proposal.md rename to openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/proposal.md diff --git a/openspec/changes/redirect-shared-temp-to-session-scratch/specs/session-cwd/spec.md b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/specs/session-cwd/spec.md similarity index 100% rename from openspec/changes/redirect-shared-temp-to-session-scratch/specs/session-cwd/spec.md rename to openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/specs/session-cwd/spec.md diff --git a/openspec/changes/redirect-shared-temp-to-session-scratch/specs/tool-approval-gates/spec.md b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/specs/tool-approval-gates/spec.md similarity index 100% rename from openspec/changes/redirect-shared-temp-to-session-scratch/specs/tool-approval-gates/spec.md rename to openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/specs/tool-approval-gates/spec.md diff --git a/openspec/changes/redirect-shared-temp-to-session-scratch/tasks.md b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/tasks.md similarity index 98% rename from openspec/changes/redirect-shared-temp-to-session-scratch/tasks.md rename to openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/tasks.md index a59adb056..1b226f8c7 100644 --- a/openspec/changes/redirect-shared-temp-to-session-scratch/tasks.md +++ b/openspec/changes/archive/2026-08-19-redirect-shared-temp-to-session-scratch/tasks.md @@ -27,6 +27,6 @@ - [x] 4.1 Update working-context and consumer guidance to state that `{session_dir}` is private scratch and that cleanup is not yet automatic. - [x] 4.2 Run strict OpenSpec validation for this change and the parent structured-approval change. -- [ ] 4.3 Run focused policy, actor, shell-environment, and eval assertion tests on Linux; run native Windows coverage for path and PowerShell behavior. +- [x] 4.3 Run focused policy, actor, shell-environment, and eval assertion tests on Linux; run native Windows coverage for path and PowerShell behavior. - [ ] 4.4 Run the full required build, tests, headers, formatting, Slopwatch, and eval gates for every changed system-guidance artifact. - [x] 4.5 Record automated session-directory cleanup as explicit future scope without implementing deletion in this pull request. diff --git a/openspec/changes/surface-reminder-schedule-failures/.openspec.yaml b/openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/.openspec.yaml similarity index 100% rename from openspec/changes/surface-reminder-schedule-failures/.openspec.yaml rename to openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/.openspec.yaml diff --git a/openspec/changes/surface-reminder-schedule-failures/design.md b/openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/design.md similarity index 100% rename from openspec/changes/surface-reminder-schedule-failures/design.md rename to openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/design.md diff --git a/openspec/changes/surface-reminder-schedule-failures/proposal.md b/openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/proposal.md similarity index 100% rename from openspec/changes/surface-reminder-schedule-failures/proposal.md rename to openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/proposal.md diff --git a/openspec/changes/surface-reminder-schedule-failures/specs/netclaw-scheduling/spec.md b/openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/specs/netclaw-scheduling/spec.md similarity index 100% rename from openspec/changes/surface-reminder-schedule-failures/specs/netclaw-scheduling/spec.md rename to openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/specs/netclaw-scheduling/spec.md diff --git a/openspec/changes/surface-reminder-schedule-failures/tasks.md b/openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/tasks.md similarity index 100% rename from openspec/changes/surface-reminder-schedule-failures/tasks.md rename to openspec/changes/archive/2026-08-19-surface-reminder-schedule-failures/tasks.md