Architecture
August 31, 2026 · View on GitHub
Context Guard separates DSH-owned execution from Guard-owned certification.
Responsibility boundary
| Module | Owns |
|---|---|
| DSH Goal | Persisted objective, automatic goal rounds, pause/resume/block/complete |
| DSH Todo | Lightweight current plan display |
| DSH Compaction | Model-visible history reduction without corrupting tool-call structure |
| Context Guard | Per-item task contract, revisions, evidence binding, and completion certificate |
Context Guard does not own Goal, Todo, Compaction, or continuation. It intervenes when completion is claimed without a valid certificate.
Durable state model
The effective plugin configuration and the DSH Session append-only log are the inputs to the rebuildable Guard projection. Context Guard appends no custom session event types: the persisted event vocabulary is harness-owned and the current persistence layer refuses unknown event types. The activation configuration supplies the initial enablement state, while all later session state is derived from the natively persisted events DSH already writes:
- effective plugin configuration — initial enablement (
opt-instarts disabled;alwaysstarts enabled before log replay); command/run— later enablement (/context-guard on|off|clear) and epoch transitions;user/message— captured contract clauses;tool/call+tool/result— bounded evidence and completion-certificate attempts.
The in-memory GuardProjection is a rebuildable cache: deriveProjection applies the effective activation configuration, replays the native log deterministically, recomputes every contract, evidence, and certificate, and flags corrupt when a recorded certificate no longer re-derives from the evidence in the log. The projection and its evidence are session-scoped: a new DSH session starts a new projection and cannot import, look up, or certify evidence IDs from another session. A completed workflow that needs a certificate must therefore produce its evidence and call context_guard_checkpoint in the same session. Under always, replay begins enabled; changing an existing profile from opt-in to always can therefore bring earlier persisted user messages into the derived contract. A recorded /context-guard off disables capture from that point until a later on. A recorded /context-guard clear supersedes every pending requirement and acceptance under a CLEAR:<revision> sentinel (prohibitions are retained) and bumps the contract revision, so a fresh empty-binding checkpoint can certify while the guard stays enabled. Captured contracts always carry a concrete subject/surface, so no unrelated evidence can close a requirement.
Synchronization
The runtime rebuilds the projection from the log before each step. Before evidence is produced, the runtime awaits ctx.sessions.flush(session); if no durability listener participated, evidence is marked durability-unknown, which fails closed.
The v0.3 runtime accepts host identity only from hostLockPackages generated from the active runtime/profile graphs and bound to the active platform/profile kind. It does not infer identity from the nearest pnpm-lock.yaml: DSH core and profile plugins have separate locks, and the runtime lock can contain several historical versions. Missing, unreadable, duplicate, multi-version, or drifted identity disables the dependent capability. The audited values live in manifests/supported-host.v1.json as an exact host cohort registry: the whole graph must atomically match one audited cohort, mixed or unknown rows fail closed, and the selected cohort identity is part of every host lock digest, so switching cohorts invalidates certificate authority. deriveProjection receives this exact evaluation before it replays any checkpoint, so a certificate is never validated under a default lock and overwritten later; a changed digest retains historical evidence but makes current authority stale. Ordinary persisted bash/pwsh results are replayed only when the active platform's agent-loop and terminal group is exact; wrong-platform tool names fail closed. Ordinary read/write/edit results require the independent filesystem group, which pins the tool schemas and result/presentation contract together with the local/sandbox provider, observation policy, sandbox policy, and approval services. A filesystem-group failure disables only create/modify and filesystem-derived facts, not an independently valid terminal action.
Evidence is produced only from persisted tool/call + tool/result pairs. Guard never inserts context between a Code Mode sub-call and its durable result.
Domain pipeline
classifyUserInteractiondrops session-layer utterances before capture: bare progression/acknowledgement phrases (继续,continue), meta questions (这个收尾具体要做什么,是不是bug), and meta comments/objections. The classifier fails closed — an artifact path, an explicit method, or a non-negated operation verb always keeps the message (or the individual clause inside a mixed message) a captured instruction.classifyClause/captureClauseclassify the remaining direct human message into requirement, acceptance, or prohibition.segmentAuthorityBlockskeeps quoted/code/reference material outside the contract, supports explicit section adoption, and captures uncertain material fail-closed.context_guard_evidenceproduces read-only resolution/state facts and validates already persisted effects;context_guard_actionowns the explicitly mutating install/apply/restart/publish and Git paths. Before any executable, command, HTTP request, or durable intent, the action tool flushes and replays the resolution/contract chain, then runtime authorization binds the action to one exact pending root-owned requirement/revision (never a prohibition or acceptance), rejects any matching pending root prohibition, and rechecks Guard integrity, host identity, semantic action, target-capture status, and every action-specific requested/resolved identity field. Exact package version/profile/registry and explicit Git remote/full refspec are required; resolution-only integrity, boot generation, and Git OIDs remain bound by the target digest and live prestate.evidenceFromPersistedToolResultmaps persisted results to versioned semantic actions, evidence roles, exact resolved targets, observed state, executable identity, immutable resolution-time expected transition, and bounded diagnostics. Only exact adapter and command-manifest IDs/versions in the shipped manifests may supply structured state facts. On Windows, audited.cmd/.batshims are version-probed through a closed invocation whose interpreter is pinned to the canonicalSystemRoot\\System32\\cmd.exerealpath and version. Resolution and effect bind both identities; execution reuses the revalidated paths and rejects shell-control or expansion characters rather than re-resolving the logical name throughPATHor trusting a changedComSpec. Modify transition construction first re-hashes the current source bytes against the resolved pre-digest, then applies the pinned unique UTF-8 replacement. Commit readback parses the raw post-commit parent tuple and accepts exactly one parent equal to the resolved pre-effect HEAD; fetch freezes that HEAD and requires the post-effect HEAD to remain identical. Pre-execute revalidation is a correctness gate, not isolation from a concurrently malicious process running as the same user; a mismatching post-action readback remains non-certifiable.certifyCheckpointflushes and resynchronizes first. Non-stateful actions require an action-compatible minimal facet; every action in the ten-memberSTATEFUL_ACTIONSset requires distinct resolution, effect, and independent state evidence, one shared resolved target, non-overlapping state observations, and an expected-transition predicate frozen and digested by the resolution fact before effect. The binding must reproduce that payload exactly before observed state is compared.- A certificate freezes protocol/certificate versions, epoch,
sessionRefDigest,hostLockDigest, contract revision/hash, explicit null-or-current Goal ref, open/evidence/binding digests, and the final certification digest. The tool computes a candidate without mutating runtime authority; only a persisted tool result that re-derives byte-for-byte becomes current authority. goalCompletionDenialrejects the Guard-ownedupdate_goal(action=complete)model-tool path before the Goal mutation unless that certificate is current. A trusted in-process producer can bypass the tool guard; replay detects the durablegoal/change completewithout a certificate and records an integrity violation, but the plugin does not claim to prevent or roll it back.context_guard_boundarypersists only qualifieduser_wait,external_wait, ordeferredcandidates. After the accepted tool result is flushed and replayed, the post-commit path reads the same active/armed Goal ref, callsgoals.disarm(agent), and independently reads the same ref as disarmed. Pre-effect, still-armed, and post-effect-unknown failures have separate fail-closed/fail-loud outcomes.decideTurnBoundaryreads only structured Guard/Goal state. Assistant completion prose is diagnostic and never a stop or continuation control source; active/armed continuation belongs to the Goal Round Driver.renderRecoveryPacketre-injects open requirements after compaction, resume, enable, rejection, or integrity loss. Injection is content-deduplicated: a re-armed packet with unchanged content is injected once, while resume, compaction, an enablement transition, new evidence, or a new contract revision change or forget the digest and always re-remind.