Skip to content

Apply 17 verified re-review findings; decouple snapshots from git#1

Closed
ralphite wants to merge 117 commits into
claude/agent-runner-design-a70zjwfrom
main
Closed

Apply 17 verified re-review findings; decouple snapshots from git#1
ralphite wants to merge 117 commits into
claude/agent-runner-design-a70zjwfrom
main

Conversation

@ralphite

@ralphite ralphite commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Durability: process-group-confirmed cancellation (orphan writers would
dirty barriers), interruptible waiting states, credential redaction
before persisting activity results. Workspace snapshots move behind a
SnapshotStore interface with opaque refs — shadow-repo (separate
GIT_DIR/GIT_WORK_TREE, invisible to the user's repo) is just the
default backend, archive-copy or none also valid; explicit exclude
policy and pinned snapshots. Effect pipeline: EffectResolved split by
durability point (gates before ActivityStarted, post-hooks ride
ActivityCompleted), reserve-then-settle budgets, bash command-pattern
rules + honest path-rule scope, realpath-based matching. Provider:
provider-neutral call pairing via harness call ids with assembly
reordering, opaque thought-signature persistence, abnormal
finish-reason loop policy, weakened credential claim backed by
redaction. Trust model: executable config only from spec/user/local
layers, project-layer hooks require explicit trust, memory files
untrusted. Multi-agent: frozen rules intersection at spawn, tree-level
budget aggregation, depth/fanout caps. Sessions: CheckpointBarrier
event records the {stream→seq} cut vector + snapshot refs; fork
materializes its own worktree via ForkedFrom genesis. MCP: fully
qualified tool names, unlabeled tools treated as execute-class.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd

claude added 30 commits July 2, 2026 07:58
Durability: process-group-confirmed cancellation (orphan writers would
dirty barriers), interruptible waiting states, credential redaction
before persisting activity results. Workspace snapshots move behind a
SnapshotStore interface with opaque refs — shadow-repo (separate
GIT_DIR/GIT_WORK_TREE, invisible to the user's repo) is just the
default backend, archive-copy or none also valid; explicit exclude
policy and pinned snapshots. Effect pipeline: EffectResolved split by
durability point (gates before ActivityStarted, post-hooks ride
ActivityCompleted), reserve-then-settle budgets, bash command-pattern
rules + honest path-rule scope, realpath-based matching. Provider:
provider-neutral call pairing via harness call ids with assembly
reordering, opaque thought-signature persistence, abnormal
finish-reason loop policy, weakened credential claim backed by
redaction. Trust model: executable config only from spec/user/local
layers, project-layer hooks require explicit trust, memory files
untrusted. Multi-agent: frozen rules intersection at spawn, tree-level
budget aggregation, depth/fanout caps. Sessions: CheckpointBarrier
event records the {stream→seq} cut vector + snapshot refs; fork
materializes its own worktree via ForkedFrom genesis. MCP: fully
qualified tool names, unlabeled tools treated as execute-class.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Update stale L3 workspace reference to SnapshotStore/CheckpointBarrier
semantics; reconcile config layering (spec + user + project sources)
with the trust model so trusted hooks come from a layer that exists;
qualify hook persistence split (pre-hook in EffectResolved, post-hook
in ActivityCompleted); journal EffectResolved on deny/block too, not
just the pass path; split budget-gate outcomes — resource limits get
graceful wrap-up, structural spawn limits render as error results.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
…odes)

Unify goal mode and loop mode as one IterationDriver actor with two
schedules (immediate+verifiers vs interval/cron/self-paced): shared
iteration event family, journal-before-send launches with deterministic
envelope ids, driver-rooted tree budgets, shared stall detection and
child-failure policy. Background runs: resident runtime hosts runs,
frontends attach/detach as subscribers (detach journals nothing), plus
a notifier actor with deduplicated NotificationSent stream (documented
carve-out like hooks). Background effects: background:true activities
whose paired tool result is the fold-rendered ActivityStarted handle;
completions re-enter the loop as user-role inputs at turn boundaries
(Gemini pairing untouched); WAITING_TASKS joins a waiting-state
registry with an interruptibility table. Artifacts: ArtifactStore as
the second SnapshotStore-pattern instance (CAS, opaque refs, blob
durable before referencing event), publish_artifact as a full-pipeline
tool with publish-time durability independent of run completion,
per-stream versioning, outputs: as end-of-run deliverable contracts,
ApprovalRequested payload_ref for plan-style artifact approvals, and
artifacts as run inputs. Define the fixed run epilogue (quiesce →
auto-publish → terminal barrier → terminal event), declared-idempotent
activities as the only auto-rerun channel for in-doubt resolution, and
amend the durable-state doctrine to include ref-addressed blob stores.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Split the design into seven teachable, independently digestible stages:
walking skeleton, event-sourced kernel, effect pipeline, interaction &
context, ecosystem & multi-agent, service & run modes, and a deliberately
deferred world-state lifecycle batch (snapshots, barriers, fork/rewind,
cloud workspace lifecycle, sandbox backend, derived indexes). Records
the four standing constraints that keep stage 7 an addition rather than
a rework (mandatory workspace abstraction, no-op barrier slot in the run
epilogue, activity quiescence bookkeeping from stage 2, event-log
discipline), per-stage exit criteria, and an adversarial review gate at
每 stage boundary. DESIGN.md remains the architectural source of truth;
its M1-M5 roadmap is superseded by this file and will be reconciled
later.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Fine-grained numbered steps with deliverables and verification for
S1-S3 (scaffolding through effect pipeline), module-level sequences for
S4-S6, milestone-level for the deferred S7 (refined at kickoff with
dogfood data). Fixes tech stack (Python 3.12/uv/pydantic v2/pytest/
ruff/mypy), final repo layout, and the cross-stage test base
(ScriptedProvider replay fixtures, sample-repo fixture, crash-injection
harness). Declares expected rework explicitly (S2 rewrites the S1 loop
onto activities, interfaces stable), per-step definition of done,
stage-gate adversarial reviews, kickoff refinement before each stage,
size expectations as plan signals, and the invariant-change protocol
(stop, surface, review — never work around in code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
PLAN.md rewritten incorporating all 32 review findings. Sequencing:
provider interface is streaming-shaped with opaque Part extras and a
capabilities() stub from step 1.2 so it genuinely survives to S4; crash
harness skeleton moves right after the kernel with named predicates and
a code-level injection-point registry instead of brittle global event
counts; the loop rewrite is explicitly homed at 2.10 with tool results
stored per-call-id from day one; durable timers land immediately after
the activity executor; the run-epilogue skeleton arrives at 2.16 so S3's
graceful wind-down hangs into it; fold state becomes namespaced
sub-states with per-substate schema versions, and the in-flight
activity set lands in S2 (completing hook 3); the waiting-state
registry enumerates all four variants up front. Coverage: adds inspect
v0, denied-by-interrupt, catalog injection, cache-token settlement,
thinking capability, per-provider error wire forms, TurnDiscarded
wiring, 0600 permissions, causation-chain tests, MCP allowed_tools, and
notes the config-layering pull-forward. Buildability: Clock abstraction
with FakeClock and a lint ban on wall-clock calls in core, ScriptedProvider
matching contract plus a fixture recording tool, debug tooling (events
pretty-printer, fold diff helper) early in S2, oversized steps split
(3.6/3.7/S4.4), JSONL store gains per-session flock, data-dir/session-id
/config locations decided, error taxonomy module, POSIX-only declared,
fixture-repo copy-per-test policy, honest size re-estimates with an S6
cut line.

Language switch Python → Go 1.23+ (decision #1): goroutines/channels map
directly onto the actor model, single static binary distribution, and
official Go SDKs now exist for Gemini, Anthropic, and MCP — the SDK
argument that favored Python no longer differentiates. DESIGN.md and
STAGES.md updated accordingly, including the S2 exit-criteria erratum
(waiting-state crash survival via synthetic events; full approval flow
verified in S3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
…s pack, acceptance-test framework

Consistency (12 findings): STAGES catches up with PLAN's reordering —
epilogue skeleton and hook 2 land in S2, config layering pulled to S3,
waiting-state registry drawn in full in S2, session CLI in S2 with S4
polish, inspect v0/S5 tree extension scheduled, S3 TOCTOU criterion
scoped to synthetic concurrency, S4 gains the dual-provider gate, S6
cut-line items annotated. DESIGN gains best-of-N as the fourth
IterationDriver schedule (decision #21), a deferral note on the
barrier quiescence invariant pointing at S7, the S7 snapshot-benchmark
reference fix, and the last asyncio-era phrasing removed.

PLAN gains: §0.5 loop-mode execution protocol (bootstrap order,
PROGRESS.md decision ledger, step=commit contract, DEFERRED rule for
unverifiable checks like missing GEMINI_API_KEY, underspecified-vs-
invariant-conflict triage, forward-reference stub rule); §0.6
acceptance-test framework (scenarios as human-readable YAML data
mapped one-to-one from stage completion criteria, agentrunner accept
--stage N runner with bubbletea TUI, plain-text + JSON report fallback,
SKIPPED semantics for live-gated scenarios); step 1.11 acceptance
harness v0; and the S1 defaults pack fixing all 15 decisions the
executability audit found an unattended agent would otherwise guess
(module path, check.sh, StreamEvent/Part shapes, call_id scheme, spec
rules, fixture format, tool limits, journal schema, paths, exit codes),
plus the 1.1 knownTools stub, the 1.7/1.7a ordering note, and
hand-authored E2E fixtures to break the recording chicken-and-egg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Gitignore .env (local credentials, 0600, loaded at CLI/test startup
without overriding existing env vars, never committed or persisted into
fixtures/journals). Add a reproducible mid-size testbed: scripts/
testbed.sh clones a pinned external repo (default gin-gonic/gin@v1.10.1,
~20k LOC; caddy as the larger tier), applies a known bug patch from
testdata/testbed/, and the agent's fix is verified by the repo's own
tests. Testbed scenarios are acceptance-only (requires: [testbed],
SKIPPED when offline), used from the S1 exit checkpoint and for
dogfooding from S4/S6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
…e set

166-feature gap analysis plus stress tests of load-bearing design
decisions. Verdict: no blockers; 18 friction points consolidated into
7 design amendments recommended before implementation (shadow git
checkpoints, detached activities, in-doubt policy table, message-stream
injection channel, hook sites, turn sweep semantics, credential
provider) plus 8 one-line contract additions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015tnXetVuMWdtgdDUDzQ9vF
FEATURES.md: 166 Claude Code / Codex feature points in scannable tables
(one line each, with verdict markers). DESIGN-SUGGESTIONS.md: the review
findings restructured as a self-contained checklist (7 structural
amendments, 8 contract patches, 9 roadmap notes) with where-to-change /
why / change-to-what for each, so a future session can apply them to
DESIGN.md directly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015tnXetVuMWdtgdDUDzQ9vF
The review on main was generated against pre-2bae06e DESIGN.md — its
headline finding (per-turn git commit) was already resolved by the
SnapshotStore/shadow-repo decision; triage notes added to the review
files marking resolved-vs-merged items. Genuinely new findings folded
into DESIGN.md: in-doubt handling becomes a per-tool-class data policy
(LLM re-issue via TurnDiscarded, read/idempotent rerun, execute/edit
render interrupted-by-crash and continue, human triage only for
configured high-risk tools — headless runs no longer stall); turn is
now defined (one LLM call + its tool batch) with steering consumed at
the earliest pairing point; interrupt performs a turn sweep — every
non-terminal call gets a terminal event, abandoned approvals journal
EffectAbandoned and late answers no-op by request id (closes the
Esc-then-late-approval executes-dangerous-call hole); ApprovalRequested
carries already-completed gate verdicts so pre-hook side effects are
durable across multi-day parks; tool faces split into advertised
(prefix-stable) vs permitted (gate data) so plan-mode switching cannot
bust tools-level cache; credentials resolve through a
CredentialProvider interface with a managed token store for OAuth
refresh flows; plus one-line contracts for the identity upcast seam,
PolicyChanged journaling with config paths excluded from rewind,
graceful shutdown and session-per-process topology, resident runtime
as the durable-timer firer, dual-channel bus semantics for
cross-process deployment, an event-write scrub stage reservation, and
a wait-class tool category parking in WAITING_INPUT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Hard git rules for this single-developer prototype: work only on main,
push immediately after every commit, fetch+fast-forward at session
start (a stale-base review incident motivated this), never commit .env.
Also records the three-document system and their roles, the
invariant-change protocol pointer, language and implementation
conventions, and marks the external review files as read-only archive.
PLAN §0.5 step-commit contract updated to include the push rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
go.mod (github.com/ralphite/agentrunner, go 1.24), cmd/agentrunner +
internal/cli with testable Run() and --version (exit codes per S1
defaults pack), slog-to-stderr convention with AGENTRUNNER_DEBUG,
.golangci.yml in v2 format (preinstalled golangci-lint is 2.5.0) with
forbidigo wall-clock ban scoped to internal/(kernel|state|pipeline) via
path-except, errcheck excludes fmt.Fprint* CLI writes, scripts/check.sh
as the single done-gate, PROGRESS.md decision ledger started, gitignore
cleaned of Python-era entries.

Decisions logged in PROGRESS.md: v2 lint config format; CLI skeleton in
internal/cli; run subcommand deferred to 1.9.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
AgentSpec{name, model{provider,id,max_tokens}, system_prompt|_file,
tools[], max_turns} loaded from YAML with strict unknown-field
rejection, validated in defined field order with the S1 error format
(spec <path>: field <name>: <problem>). system_prompt_file resolves
relative to the spec directory and folds into SystemPrompt at load
time; defaults applied (max_turns 40, max_tokens 8192); unknown tools
checked against the hardcoded S1 list (TODO(1.5) registry swap). Eight
golden error cases with -update regeneration, positive tests for
defaults and prompt-file resolution, specs/hello.yaml example.

Decisions logged in PROGRESS.md (first-error-only validation,
prompt-file resolution semantics, empty tools legal).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
internal/provider defines the final interface shape (per PLAN 1.2's
stability promise): roles, Part with harness call_id and opaque Extras
(thought signatures round-trip byte-identically via json.RawMessage),
wire-level ToolDef, CompleteRequest, the four-kind StreamEvent set,
normalized Usage with cache fields reserved, FinishReason enum with
abnormal variants deferred to S4, Capabilities stub, and the Provider
interface streaming via iter.Seq2[StreamEvent, error]. CollectTurn
assembles turn-granularity results for the S1 loop; CallID implements
the deterministic call_<turn>_<index> scheme. Tests cover assembly,
extras preservation, mid-stream errors, and Part JSON round-trip.

Decision logged: iter.Seq2 (inline error channel) instead of the
defaults pack's iter.Seq — recorded as a deviation in PROGRESS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Adapter maps normalized requests to GenerateContentStream: system
instruction, ParametersJsonSchema passthrough for tool schemas (SDK
supports raw JSON schema — supersedes the planned hand-written
converter), role mapping (tool results ride user-role contents with
FunctionResponse parts), harness call ids minted per stream order,
thoughtSignature round-trips through Part.Extras both directions,
usage (incl. cached tokens) and finish reasons normalized. Error
results render as {"error": ...} response payloads (decision #9 Gemini
convention); object results pass through, scalars wrap as output.
Five unit-test groups over the pure conversion functions; live smoke
test (build-tagged, .env-aware) executed against the real API and
passing. Default model switched to gemini-flash-latest — this key 404s
on bare gemini-2.5-flash (deviation logged). CompleteRequest gains an
additive Turn field for call-id minting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
internal/provider/scripted serves YAML fixtures by sequence with
per-step drift assertions (tools_include, last_message_contains — the
latter also matching tool_result payloads), optional call_id minting
from (turn, index), loud exhaustion errors, and a Done() helper that
catches unconsumed steps. internal/provider/record wraps any Provider
as pass-through middleware capturing fixture steps: expectations
auto-derived (offered tool names + a 60-char snippet of the last text
part), *_API_KEY/_TOKEN/_SECRET env values redacted before anything
reaches disk, fixtures written 0600. Round-trip test records a session,
replays it against the same request, and verifies both the redaction
marker and drift detection on a changed prompt.

Decision logged: recorder is provider middleware now, record-fixture
CLI wiring deferred to 1.9 where the loop exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Workspace.Resolve maps tool paths through Clean + symlink resolution
(deepest-existing-ancestor for not-yet-existing targets) and rejects
anything outside the resolved root with the canonical escape error.
Covers ../ traversal, absolute outside paths, symlinked directories for
both existing and new-file targets. Hook 1 (mandatory workspace
abstraction) is live from this step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Three built-in tool definitions ship as go:embed JSON (name,
description, class, input_schema): read_file (read-class), edit_file
(edit-class, exactly-once replacement semantics with empty-old-creates
convention documented in the schema), bash (execute-class). Registry
validates completeness and name uniqueness at init, exposes sorted
Names(), Get(), and ProviderDefs() wire conversion. Spec validation now
consults the registry — the 1.1 knownTools stub and its TODO(1.5) are
gone, unknown_tool golden regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Executor binds the tool suite to a workspace with a uniform
Result{Payload, IsError} outcome: every tool-level failure (missing
file, boundary escape, match-count violations, nonzero exit, timeout)
renders as a model-visible error result per decision #9. read_file caps
at 2000 lines / 50KB with a truncation marker; edit_file enforces
exactly-once replacement (errors name the 0/N count) and creates files
via the empty-old convention; bash runs in the workspace root under
Setpgid with a 120s default wall-clock timeout (declared provisional
until the S2 durable-timer substrate), SIGTERM-grace-SIGKILL process
group kill, head+tail 30KB output truncation, and WaitDelay so
background children holding pipes cannot hang Wait. Tests assert the
process group is actually dead after a timeout kill.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
internal/runtime/paths.go is the single home for filesystem naming:
XDG data dir with ~/.local/share fallback (same rule on macOS),
session dirs created 0700, sortable session ids
(YYYYMMDD-HHMMSS-<slug> with a 30-byte lowercased slug), user and
project config paths. Ordered before 1.7 per the recorded
adjacent-step swap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Five record types (run_meta, assistant_message, tool_call, tool_result,
run_end) written as {type, ts, data} lines to sessions/<id>/journal.jsonl,
0600, record-only — the harness never reads it back in S1. Nested-data
line shape chosen over flattening (decision logged). Test verifies every
line parses, type ordering, and permission bits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Loop.Run drives turns: build request from spec + conversation, collect
the turn, journal + render the assistant message, and if it carries
tool calls execute them in order (each journaled with its result),
feeding all results back as one tool-role message; a tool-call-free
turn ends the run, max_turns caps it. Usage accumulates into RunResult.
A Sink interface decouples turn-granularity rendering (CLI wires it in
1.9). Four ScriptedProvider integration tests: multi-turn file edit,
text-only stop, tool-error recovery, max_turns. Body is deliberately
naive — S2.10 rewrites it onto activities + fold state (expected
rework #1), collaborators unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
run/record-fixture share one execution path: .env loading (never
overriding existing env), spec + workspace + provider wiring with an
injectable factory, session creation under the XDG data dir, journal
recording, and turn-granularity rendering via a text sink. Human-facing
info (session id, run summary) goes to stderr, stdout carries agent
output only. record-fixture wraps the provider with the recording
middleware and writes the fixture on success, closing the 1.3a wiring
item. Exit codes per the defaults pack. Five tests cover the scripted
end-to-end path (file actually edited, journal created), usage errors,
and dotenv semantics; manually accepted against live Gemini (3-turn
read→edit→confirm run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Committed sample repo (independent go module under e2e/testdata,
ignored by the go tool) with a deliberately failing test, plus a
hand-authored four-step fixture (read → edit → go test → wrap-up) per
the defaults pack — no recording-tool chicken-and-egg. The E2E test
copies the repo to a temp workspace, asserts the pristine tests fail,
drives the full loop/tools/journal stack via the scripted provider,
then asserts the fix landed, the repo's own tests pass, and every
fixture step was consumed. Live-Gemini variant deferred to the stage
exit checkpoint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
internal/accept executes embedded per-stage scenario YAMLs (id,
human-readable title, files written into a fresh scratch dir, shell
steps with BIN/SCRATCH/isolated XDG_DATA_HOME env, four expect kinds
incl. built-in journal line validation, live/testbed skip gating).
agentrunner accept --stage N renders a bubbletea checklist on a TTY,
plain text otherwise, and always writes acceptance-report.json (exit 1
on any FAIL). The CLI provider factory gains a scripted seat behind
AGENTRUNNER_SCRIPTED_FIXTURE so scenarios drive the real binary
offline. Three S1 scenarios map the stage completion criteria; the
suite runs 3 PASS / 0 FAIL. TUI visual check deferred to the stage-exit
human checkpoint (no TTY here).

Stage 1: all 12 steps complete.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Acceptance integrity: aborted TUI runs can no longer report green
(StatusAborted + Report.Green gate), scenario YAML parses strictly with
exactly-one-assertion validation (typo'd keys can never become silently
passing zero expects), journal_valid now requires run_meta first and
run_end last. Process discipline: SIGINT/SIGTERM propagate via
NotifyContext to tool process groups; bash separates cancellation from
timeout (no fabricated timeout records), prefers done over the timer on
photo-finish races, killGroup only trusts ESRCH, and stdout/stderr
split one 30KB budget. Correctness: UTF-8-safe truncation everywhere,
edit_file create via O_EXCL, recorder redacts expect snippets (closes a
credential leak to fixtures) and carries tool-call extras, Gemini
thinking tokens count as billed output, failed runs journal a terminal
run_end{error}, fixtures are written even when a recorded run errors,
run_meta.Version threads from ldflags, session ids gain 4-hex entropy
against same-second collisions, dotenv handles quotes/export, provider
construction failure exits 1 vs unknown-name 2, and max_turns force
stops now exit 1 (S1.9 decision revised). Known S4 gaps and remaining
pinning-test queue recorded in PROGRESS.md.

Gate green; accept --stage 1: 3 PASS / 0 FAIL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Request-assembly golden pins the exact provider-visible message shapes
(roles, part kinds, call ids, tool-result placement) the S2.10 rewrite
must preserve. The stage-1 acceptance suite now runs under go test by
building the real binary (e2e), making the completion criterion CI-
reproducible. Report.Green unit tests cover aborted/zero-value gating;
scenario parsing rejects typo'd keys, empty and double assertions;
journal validation tests cover the truncated-journal case. Loop error
paths: provider failure surfaces wrapped with the turn number and
journals a terminal run_end{error}; journal write failure aborts.
record-fixture round-trips through the real CLI path with a write-
failure exit test; provider construction failure vs unknown-name exit
codes pinned. Gemini: zero-part messages now rejected at conversion
(API would 400), conversion-error table, stream-surfaced errors, and
the empty-result output convention pinned. Scripted consumption is
pinned as per-iteration. Workspace gains root-symlink and sibling-
prefix boundary tests; bash gains the context-cancel test (canceled,
not fabricated timeout; process group confirmed dead). New acceptance
scenario s1-04-e2e-fix-test drives the full read→edit→go-test flow
through the CLI — the S1 suite is now four scenarios.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Decisions: 包布局(event/kernel/state/clock/crash)、envelope 线上形态与
id 方案、events.jsonl+lock+snapshots 文件布局、event 类型全集(14)、
崩溃注入两轨、错误分类学 8 类、retry 政策、CLI 形态、顺序微调预授权
(2.5 前移、2.6+2.7 可合并)。详见 PROGRESS.md。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
claude added 28 commits July 4, 2026 06:41
新包 internal/driver:独立 actor,自有 EventStore(child runs 在 sub/iter-N)
与纯 fold(iterations/verdicts/BestIter/status)。统一事件族
IterationScheduled/Launched/Completed/Skipped + DriverCompleted 进
event.Registry,但属 driver 自有 stream——新增 event.DriverStream 集,run
fold 的 TestApplyCoversRegistry 跳过之,driver 侧 TestFoldCoversDriverStream
对称兜底。

goal mode(schedule=immediate + verifier 必填):Driver.Run 逐迭代
journal-before-send 起 fresh child run(ChildFactory 注入装配)、verify、
journal IterationCompleted{verdict}。satisfied/max_iterations/stalled(纯
fold patience)/child_failed/stopped 五终态。command verifier:bash exit
或 metric_regex 捕获组打分(≥threshold)。聚合 min(首个 seed 避免 clamp)。

budget 树根、失败重试策略、llm_judge/human verifier、resume、loop mode
留待后续步骤。四 driver 测试 + round-trip + 覆盖对称全绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
DriverSpec.Budget{MaxTotalTokens};fold 新增 State.SpentTokens——每
IterationCompleted 累加 Usage.Billed()(纯 fold,resume 精确恢复)。每迭代
启动前 reserve(st):allowance = min(树剩余, child spec cap),剩余 ≤ 0 →
DriverCompleted{budget}。ChildFactory 签名加 budgetTokens 供工厂钳制 child。

TestDriverBudgetStop(budget 250 / child 150 一迭代 → 2 迭代后 budget 停)
+ reserve() 表驱动单测(7 例)。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
DriverSpec.OnChildFailure{Mode,Max} 区分 child RUN 失败(非验证未过):
stop(默认)→ DriverCompleted{child_failed};surface → 记 error 迭代(带
child 真实 spend,预算不漏账)后继续下一迭代;retry{max} → runIteration
内就地重试,每 attempt 独立 store(sub/iter-N / sub/iter-N-aM),ctx 取消
不重试,耗尽落回 child_failed。backoff 延后(需 scheduler 的 durable timer)。

新增 childSpent() 折 child journal 取真实 spend。三测试(stop/surface/
retry-recovers)全绿,全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
verifier 三态齐:llm_judge = Driver.Judge 单次打分调用(system=rubric+严格
JSON 指令,firstJSONObject 容忍散文包裹,显式 pass 优先否则 score≥threshold,
nil/失败/不可解析一律 gate 失败不静默放行);human = 复用 agent
ApprovalResolver ask 路径(nil→EnvApprovals fail-closed,approve→pass)。
VerifierSpec.Rubric 新字段。

三测试(llm_judge 0.5拒→0.9过 satisfied@2、human approve@1、human deny→
max_iterations)全绿。driver goal mode 功能完整(五终态 + 三 verifier +
预算根 + 失败策略 + 停滞)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Driver.Artifacts(S5.5 CAS,nil→仅内联):每完成迭代把 child 全量 report
publish 到 carry stream(逐版本链),IterationCompleted.CarryRef 留 ref、
Carry 留 ≤512B 摘录(DESIGN:carry 文档存 CAS,只带 ref+短摘录),
redact-before-Put。TestDriverCarryToArtifactStore 断言末迭代 ref 解析回
report 文本。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Run/Resume 共享 drive(ctx,st,appendE,startN) 循环,prepare() 提取校验+单写
路径。Resume:折 driver journal,ended 返回记录结果,否则再推导已决终态
(崩溃落在定终态 IterationCompleted 与 DriverCompleted 之间):末完成迭代
verdict 过→satisfied、stalled→stalled(max_iterations/budget 在 drive 顶
重查)。startN=已完成前缀+1。

drive 幂等:st.at(n) 已在 fold 则不重发 Scheduled/Launched。runIteration
恢复 in-flight child:attempt 1 store 有旧 events 时,child 已 ended 则
settledChild 从 fold 结算,否则 child.Resume(自身 in-doubt 纪律),不重复
fresh run。

三测试(resume-ended 不追加、re-derive-satisfied 不发冗余迭代、
resume-continues 续跑达标)全绿。driver 模块② 完成(goal mode 全功能+崩溃
恢复)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
driver 支持 loop mode(schedule: interval,interval Go duration 串):verifier
选填,按节奏迭代至 max_iterations/budget/cancel。drive 加 loopMode 分支:
iteration 1 即刻,之后每迭代 waitForTick(Clock.WaitUntil(now+interval)),
cancel 于等待中→stopped;loop mode 不因 verdict.Pass/stall 停;有 verifier
才 verify(质量闸非终止)。prepare 放行 interval 并校 duration。

两测试:back-to-back(无 verifier→max_iterations)、interval-cadence
(FakeClock+goroutine,waitParked 靠 Waiters() 同步 Advance;纯文本 child
避免 bash 超时 timer 污染 Waiters())。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
新包 internal/cron:五字段最小自解析(决策:自实现无依赖)。支持 * , - /、
n/step(vixie)、dow 7≡0、dom+dow 双限 OR;名字/秒/宏不支持,parse 响亮
报错;Next 逐分钟扫 + 4 年 lookahead 界定不可满足。

driver:schedule=cron + cron 字段;awaitTick 取代 waitForTick——interval
首迭代即刻(固定延迟无 overlap),cron 每迭代等绝对 tick(nightly 首跑等
真 tick)。overlap:skip(默认,每错过 tick 消耗迭代号 + IterationSkipped
事实,fold 记 Skipped)/ coalesce(到期 tick 折一次立即跑);interrupt 需
并发 launch 延后 daemon。

cron 13 例 Next 表测 + 12 例 parse 错误;driver skip/coalesce 两测试
(FakeClock 编排,工厂 Advance 模拟长迭代)。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
两个内置数据定义 tool(registry 11→13):schedule_next{after} /
finish_series{reason},executor 只验参+ack,意义由 driver 在迭代结束后从
child journal 读出(childIntent 取最后一个成功配对的声明)。

driver schedule=self_paced:prepare 注入两 tool 到 child 工具面;
applyPaceIntent——finish_series 走 human 把关(同一 ask 路径,fail-closed;
approve→satisfied,deny→floor 续跑);schedule_next 经 pace_min/max 钳位
存 nextPace,awaitTick park;无声明按 on_no_intent(finish 默认/continue
强制配 pace_min 防空转)。

四测试(基本流、no-intent、clamp、denied finish)全绿。loop mode 语义齐
(interval/cron/self_paced + overlap)。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
DriverSpec.SeriesMemory(workspace 相对路径):buildTask() 每迭代把该文档
作为 <series-memory> 块并入 task,8KB 截断在注入点执行(权威边界——agent
放任文档膨胀也污染不了下迭代 context)。文件缺失/路径逃逸 → 无块。

注入 e2e(iter 1 写 SERIES.md → iter 2 scripted Expect 断言 task 含记忆)
+ truncation 单测(截断标记/长度上界/缺失/逃逸)。模块③ loop mode 收口。
全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
driver.LoadSpec:driver YAML,agent_spec 相对路径解析进 Agent,错误格式与
agent.LoadSpec 一致。agentrunner drive <driver.yaml>:driverID 走
NewSessionID,child 复刻 run 装配(frozen spec+allowance、buildPipeline、
共享 approvals/provider、Judge、Artifacts)。exit code 契约:satisfied→0,
loop 的 max_iterations→0(有界系列正常收束),goal 的 max_iterations→1,
其余终态→1,spec 错→2。

四 CLI e2e(goal satisfied / goal 不达 exit1 / loop 有界 exit0 / spec 错
exit2)。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
三场景:s6-01 goal-verify(drive 两迭代达 verifier,child journal 逐迭代
events_valid)、s6-02 series-memory(迭代 2 scripted expect 断言注入)、
s6-03 background-task(handle 配对 + await 善终 + journal 事实)。

checkEvents 扩展:journal 两形态——run(run_started/run_ended)与 driver
stream(iteration_scheduled/driver_completed)按首事件分流,其余同规。
stage 1-5 acceptance 回归全绿。记档:driver stream 无 header 事实,
version discipline 留 S6 出口 review。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
first-match 规则表扁平合并不保 AND 语义,物化按层:RunStarted.
PermissionLayers = [][]PermissionRule(外层 root → 内层本 run,raw JSON
避 event→pipeline 反向依赖)。agent.Run() 从 live pipeline 派生层——child
pipeline 持有 parent gate 实例,root 与 child 同一代码路径自然正确。

resume:journaled layers 存在则 buildPipelineFromLayers 每层一 gate 链装
(hooks 仍取 live config),缺失回退 config-merge;assemblePipeline 提取
共用装配。语义改进:resume 权限以 journal 冻结为准,config 漂移不再静默
改写在飞 run。

spawn e2e(两层有序入 child journal)+ 层重建语义单测(含扁平合并反例)。
全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
新包 internal/daemon:线协议 = protocol JSON lines(与 --json 同一编码),
client→server 一行 Command(ping/run/attach),server→client 为
protocol.Event 流;protocol.Event 加 Session 字段(多路复用,additive)。

职责切割:daemon 只管 socket/wire/广播,run 装配经注入 RunFunc、attach
补读经注入 Replay(不 import cli,可独测)。hostedRun 广播 hub(buffered
256 溢出 drop——可丢 delta doctrine);run 属 daemon 生命周期非连接;
attach 先订阅后补读(缝隙宁重复不缺口),detach 零事件;socket 独占
(live 拒绝、stale 回收),停机 drain 连接。

六测试(ping/run 流/客户端跑路/补读/活 run 无缺口/独占)全绿。
全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
daemon.ReplayJournal:journal→protocol.Event 纯投影(attach 补读),
ephemeral 类天然缺席;tool 结果按 ActivityStarted 配对,Failed/Cancelled
渲染 error 结果。三命令:daemon(常驻,run 同款装配减 tty,审批经 socket
路由前 headless 只认 AGENTRUNNER_APPROVE)、submit(托管+跟流,流终无
run_end = 失败)、attach(前缀解析,补读+跟流)。socketPath 建目录;
108 字节 socket 路径上限记档。

s6-04-reattach acceptance:后台 daemon 单 step 编排;fixture env 必须给
daemon 进程(provider 在 daemon 侧解析)。stage 6 四场景全绿,全量
check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
ctx 取消 → 协作取消传入每个 hosted run(abort 路径 journal 终态)→ daemon
等全部 run 落终态再退出(runsWG),连接随后 drain;停机中拒绝新 run。

race 修复:WaitGroup Add-after-Wait(晚到连接可在停机 Wait 后 Add)——
Add 与 stopping 标志同在 server mutex 临界区,停机先置 stopping 再 Wait。
测试 park run + cancel 断言退出晚于终态落定,-race ×3 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
sweepTimers:ScanTimers 注入(cli = 逐 session 折 journal 取最早 pending
FireAt,派生索引每 sweep 重算)→ 到期且未托管 → hostResume(与 submit 同
hub/attach 语义)→ resume 自身 FirePendingTimers 落 TimerFired(复用 2.13
sweep)。睡到 min(最早 deadline, 1min 重扫);Clock 注入可测。resume 失败
记 failed 集(mu 保护)不再重试——in-doubt 需要人。

cli hostResumeFunc = resume 装配减 tty(spec/权限取 journaled RunStarted/
layers,S6.14 物化兑现);flock 被占 → 记 failed(活 run 不抢锁)。
两 sweeper 单测(FakeClock)全绿,全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
daemon.ApprovalBroker:hosted run 的 ask 以 (session, approval_id) park,
approve 线命令从任意第二连接应答(错 id 拒、双答 no-op)。cli
socketApprovals 适配器 Resolve 先 emit ask 到 hub 再 park——child 共享
parent resolver,ask 自然上卷 attach 流,req.Agent 标明谁在问。
protocol.Event 加 ApprovalID;新 CLI 命令 approve;渲染给出应答提示。

round-trip 测试(双连接:见 ask→错 id 拒→approve→理由回传→run 完成)。
模块④ daemon 收口。全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
新包 internal/notify:通道 = user 配置 shell command(JSON 上 stdin,
carve-out 只认 user 层)+ stderr 兜底,通知绝不静默丢。自有 EventStore
去重 stream(journal-before-send,崩溃至多丢一条不重复),
event.NotifierStream 排除于 run fold。

daemon Server.Notify 钩子:hub.Emit 锁外 tee run_end/approval_request;
cli buffered 队列单 goroutine 消费(emit 不阻塞)。启动对账:
WAITING_APPROVAL park 补通知一次;ended-run 对账明确不做(避免历史重放,
记档)。命令 30s 超时。

notify 三测 + daemon tee + 对账两测全绿,全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Board.Mirror(锁外调用,回调可安全 Read;store 仍是 read-back 真相)+
agent.Loop.BoardMirror(ensureBoard 接入,工具面不受影响——face 仍只依赖
spec.Agents,避免 daemon 托管与本地 run 的 face 漂移)。daemon hostRunFunc
设镜像 → 新 protocol KindNote,attach watcher 实时看到全树协作笔记。

blackboard 镜像单测(有序、锁外不死锁)。模块⑤ notifier 收口。
全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
P0:loop-mode resume 误判终态(再推导限 goal mode);WAITING_TASKS park
以 WaitingEntered/Resolved 落 journal(挂起是显式状态)。

P1:await outcome 回流成真(decide 对末 assistant 后的 user 输入给
turn,受 max_turns 界;原行为被自测掩盖);daemon 停机关闭残留连接防
wedge;ApprovalBroker Register/Wait 两阶段解并发兄弟 ask 键冲突;重试
花费全 attempts 记账;self_paced resume 重推 pace;skip 槽位崩溃后不
重跑。

P2:quiesce 忙转、runs 清理、notifier 停机 drain、settledChild 失败
reason、cron lookahead 9 年、wire mode 白名单、空权限层显式 [] 哨兵、
socket chmod 0600、verifier 审批 id 带迭代号、注释更正。

九个新回归测试;未修项(RunAgent 幂等、完成标志①、verifier 管线化、
悬空 deferral)记入 PROGRESS 收口议题。全量 check + race + stage 1-6
acceptance 回归全绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Driver.Out sink 在单写路径统一 tee(所有 journal 点必经):
IterationCompleted → 新 KindIteration,DriverCompleted → KindRunEnd;
ReplayJournal 补 driver 投影。daemon 加 drive 线命令(与 run 同 hub/
notify 语义)+ submit --drive;hub tee 过滤加 KindIteration,
toNotification 加 iteration/<session>/<n> 键。

场景抓出真 bug:child run 的 KindRunEnd 抢先消费 run_end/<session> 去重
键,driver 真结局被当重复丢弃——childLifecycleFilter 滤掉 child 的
run_start/run_end 框架事件(系列生命周期属 driver)。

s6-05-series-overnight:interval ×3 无人读流,notify command 落盘断言
3 iteration + max_iterations + 无重复 launch。stage 1-6 acceptance 全绿,
全量 check + race 通过。cron 跨 daemon 重启的 durable 唤醒仍在 backlog
(记档)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
① command 幂等:DESIGN 修订为实际机制(driver 侧 fold 检查+确定性目录,
等价原 hash 方案;scheduler v0 无独立 actor 成文);补实现 daemon 线协议
idem_key(run/drive,重试转 attach 语义)+ submit --idem。
TestDaemonSubmitIdempotency。

② verifier:DESIGN 成文 v0 例外(driver 可信配置直连执行,verdict 入
IterationCompleted);judge LLM 花费穿回 verify 并入迭代 usage(树预算
诚实);过四关卡管线化列 S7。

Stage 6 关闭:六模块交付(壳 cut line 延后)、三完成标志全兑现、出口
review 全落地、backlog 逐条记档。stage 1-6 共 24 acceptance 场景全绿,
全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
PLAN 新增 S7 执行包。四条硬线:快照是优化 journal 是真相(ref opaque/
pinned/none 降级)、barrier 弱化 consistent-enough cut(向量记 in-flight
tasks+处置,fork 目标仍限 barrier)、fork 两轴正交(事件切面×快照物化)、
shadow repo 隐形(独立 GIT_DIR+排除策略,rewind 不复活凭据)。

实施序:S6 还债包 → SnapshotStore+shadow repo → CheckpointBarrier 弱化
(DESIGN 修订随该步走变更流程)→ fork/rewind → IndexStore → 沙箱/网络 →
云(cut)→ IDE(cut)。新 event CheckpointBarrier/ForkedFrom,版本集
+barriers(10→11)。S6 backlog 逐项归置。三文档一致,DESIGN 未动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Driver.Pipeline:每 verifier 执行前 adjudicateVerifier——journal
EffectRequested → Evaluate(command=tool_call/execute 携 args,judge=
llm_call 携 EstTokens)→ EffectResolved{verdict,gates};deny → fail 带
gate 理由绝不静默过,ask 收紧为 deny(配置声明效果无人应答)。执行由
ActivityStarted/Completed 括住(verdict 为 result,judge 带 usage)——
event log 即 trace 在 verifier 腿闭合。

信任层:CLI 构造 = user/project 规则在前 + trailing allow 走 spec 槽
(driver-trust,显式 deny 约束、未命中放行、mode 默认永不触达;spec 槽
不受 untrusted 降级,与 agent spec 同信任级)。DESIGN v0 例外注记改写为
兑现口径。三测试(deny 生效/trace 完整/ask 收紧)。全量 check + race +
stage 5/6 acceptance 回归绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
DriverStarted{spec(redacted), workspace_root, fold_version} 为 driver
stream 首事件(镜像 RunStarted 2.17)。driver.FoldVersion=1;Resume 校验
header 版本不符响亮拒绝,S6 无 header 旧流按 v1 接受(既有 resume 测试
即向后兼容证明)。accept checkEvents 首事件规则加 driver_started。
两测试(mismatch 拒/header 溯源)。全量 check + race + stage 6 绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
Server.IdemPath(cli 接 data/idem.json):注册即整表原子重写(tmp+rename
0600),启动 loadIdem(缺失/损坏=空表,降级为 daemon 生命周期不报错)。
测试:daemon 停机重启后同 key 重试不重复启动、回持久化 session。
全量 check + race 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
spec 加 await_timeout(默认 30m,校验正 duration);epilogue quiesce 的
await 分支先 journal TimerSet{await_quiesce} 再等——durable 事实让崩溃中
的 await park 对 daemon sweep 可见;到点 TimerFired → cancelAll → 取消
settle 照常 drain;按时清完 TimerCancelled,fold.Timers 终局为空。mid-run
WAITING_TASKS park 仍无界记档(interrupt/attach 为逃生口)。

两测试(超时腿严格事件序 / 按时腿 timer_cancelled)。S7 还债包①~④全部
收口。全量 check + race + stage 6 acceptance 绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCa3ziBoygju6dnu9imSsd
@ralphite ralphite closed this Jul 4, 2026
ralphite pushed a commit that referenced this pull request Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants