Typed activity boundary¶
The deterministic scheduler is validated for coding agents, but the same control plane runs research, browser/computer-use, data, and ops agents. The typed activity boundary is the one contract that lets any modality participate as a replayable step: every activity returns an artifact plus the hashes needed to replay it, so the scheduler stays deterministic and the agent stays an opaque stochastic activity behind a hash-in / hash-out contract.
Why¶
Bernstein already writes one canonical, Merkle-chained event journal per run and records every coding spawn against it. A non-coding agent -- one that fetches pages, drives a browser, or runs a data/ops step -- had no uniform way to participate as a replayable step, so its exogenous inputs sat outside the determinism guarantee. The activity boundary closes that gap without a new control plane: the same scheduler dispatches and journals a research or browser activity exactly as it journals a coding spawn.
The result contract¶
Every modality returns an ActivityResult:
| Field | Meaning |
|---|---|
kind | The agent modality: research / browser / data / ops / coding. |
artifact | The modality's opaque result payload (never inspected by the scheduler). |
artifact_hash | SHA-256 of the canonical artifact projection. |
evidence_set_hash | SHA-256 over the set of observation content hashes (order- and duplicate-independent). |
terminal_state | Typed terminal state: completed / refused / failed / timed_out. |
reason_code | A short, non-empty machine reason code for the terminal state. |
Each Observation is content-addressed at capture time: the bytes the agent saw behind a decision (a fetched page, a screenshot, a DOM snapshot) are hashed the moment they are captured, so the content hash is a forensic record of the exact bytes. The ref (URL, decision-step label) is provenance only and is not part of the content hash.
What the scheduler enforces at the boundary¶
- Schema validation. A result whose
artifact_hashorevidence_set_hashdoes not recompute, whoseterminal_stateis not a known state, or whosereason_codeis empty is rejected with a typedActivityRejectedrefusal before it reaches the journal. - Evidence pinning. The
evidence_set_hashis written into the run journal as oneactivity.resultentry, so a replay reattaches the same bytes. - Redundancy refusal. The scheduler refuses to add a stage whose
evidence_set_hashequals a prior stage's -- a stage that re-derives an already-seen exogenous signal introduces nothing new -- and logs the refusal. - Audit mirror. Each crossing is mirrored into the HMAC audit chain (
activity.result) carrying only hashes, the kind, the terminal state, and the reason code -- never the artifact body or the fetched evidence.
Declaring a role's modality¶
A team declares which modality a role runs as via agent_kind on its [[roles]] entry (default coding, so existing manifests are unchanged):
How verify reconstructs a run¶
bernstein activity verify <run> walks <workdir>/.sdd/runs/<run>/journal.jsonl:
- Confirm the journal's Merkle chain recomputes cleanly (a tampered anchored field breaks the chain at a precise step).
- For each
activity.resultentry, recompute theevidence_set_hashfrom the pinned observation hashes and compare it to the anchored value. - When the run's content store (
.sdd/cas) is present, reattach each observation's bytes and re-verify the content hash.
A tampered journal entry or a divergent stored blob makes the reconstruction diverge, and verify exits 2. Exit 0 is a clean verify; exit 1 means the run or its activity entries were not found.
Modalities¶
- Research and browser/computer-use: research content-addresses every fetched page at fetch time; browser records one observation hash per decision step. Both anchor identically to a coding spawn.
- Data and ops: a world-changing modality adds two guarantees on top of the same substrate.
- Deterministic-plan vs side-effecting split. The activity records signed inputs, then derives a plan whose
plan_hashis a byte-identical projection of those inputs and the declared steps, then records signed outputs. A side effect before a plan (or a new input after one) is refused, so the plan is provably the projection the effects were computed from. - Signed input/output artifacts. Every input and output is content-addressed and Ed25519-signed with the install key, bound into a
DataOpsReceiptthat is the activity'sartifact. The receipt's canonical bytes hash to the anchoredartifact_hashand are stored content-addressed, sobernstein activity verifyreattaches the receipt offline and re-verifies the plan projection and every signature -- not just the evidence bytes. Strip the store or the journal and the receipt stops verifying, not merely stops logging.
See also¶
deterministic-replay.md-- the canonical event journal.stall-escalation.md-- another journal-anchored receipt.