# v0.6 Product Design — Controlled Runtime Experiments Status: **implemented at repository level in `0.6.0`**. ## Summary v0.6 adds one deliberately narrow controlled runtime experiment on top of the existing read-only diagnostics and Runtime Verification stack: a coding Agent may temporarily enable the already-shipped Cordis waterfall instrumentation seam under a finite, owned lease, collect metadata-only traces attributable to that lease, and rely on owner-safe stop/timeout cleanup. The milestone does **not** generalize this into arbitrary Cordis mutation. ```text v0.4 Agent can inspect runtime facts v0.5 Agent can verify before/after runtime facts v0.6 Agent can perform one bounded waterfall experiment ``` ## Final architecture ```text Human Profiler ───────┐ DSH Agent tools ──────┼─→ WaterfallExperimentCoordinator External MCP tools ───┘ │ ▼ WaterfallInstrumentationController │ ▼ Cordis runtime ``` `WaterfallExperimentCoordinator` is the single production owner of low-level instrumentation mutation. Human UI, DSH tools, and MCP do not maintain independent ownership flags or call the controller directly. ## Ownership and lease contract The canonical status reports factual instrumentation state and one owner: ```text disabled + none enabled + human enabled + agent { leaseId, source: dsh|mcp, startedAt, expiresAt } conflict unsupported ``` Rules implemented in v0.6: - only one owner exists at a time; - Human enable acquires Human ownership; - Agent start succeeds only from an idle supported state; - a second start returns busy/current-owner facts without mutation; - Agent stop requires the exact active `leaseId`; - a stale lease id cannot disable a Human session or a later Agent lease; - Agent leases are finite, with default TTL `15000 ms` and maximum `60000 ms`; - there is no infinite lease or renewal API; - expiry rechecks exact ownership before cleanup; - Human emergency stop may terminate an Agent lease at any time; - `conflict` / `unsupported` remain fail-closed and cleanup never overwrites another runtime patch. ## Trace attribution A waterfall trace created while an Agent lease owns instrumentation carries: ```text experimentId = leaseId ``` Human traces remain untagged. `profilerTraces` accepts an optional exact `experimentId` filter, including the MCP tool `cordis_profiler_traces`. This is attribution, not completeness. Profiler retention remains bounded and the existing `bounded / retained / matched / returned / truncated` semantics still apply. Late settlement and late `next()` facts stay attached to their original tagged trace even if the lease has already ended. ## DSH Agent authority `CordisRuntime` stays read-only. Mutation is exposed through a dedicated tool pair: ```text cordis_start_waterfall_experiment cordis_stop_waterfall_experiment ``` Start obtains a one-shot decision from the real DSH `ctx.approval` service before coordinator mutation. Only `allowed-once` proceeds. Missing Agent identity, missing/unavailable approval, rejection, or cancellation fail closed. The mandatory approval is issued from the start tool body rather than delegated solely to a reorderable `tools/pre-execute` listener. Stop needs no second approval because it can only reduce instrumentation by ending the exact active lease. A normal DSH Agent workflow is: ```text start({ ttlMs? }) ↓ leaseId ↓ reproduce one waterfall behavior ↓ profilerTraces({ experimentId: leaseId }) ↓ stop({ leaseId }) or TTL cleanup ``` ## External MCP authority External MCP has no authentic DSH Agent/session identity, so it does not impersonate one or route through `ctx.approval`. The original v0.5 MCP behavior remains backward-compatible: ```yaml mcp: enabled: true port: 43127 ``` This still exposes the original seven read-only tools only. External experiment mutation requires explicit operator capability plus authentication: ```yaml mcp: enabled: true port: 43127 token: ${CORDIS_DEVTOOLS_MCP_TOKEN} experiments: enabled: true ``` Final rules: - experiment mutation is absent by default; - `experiments.enabled: true` requires a non-empty bearer token; - when a token is configured, every MCP request must send `Authorization: Bearer ...`; - the endpoint remains fixed to `127.0.0.1`; - the token never enters tool arguments, status, diagnostics, traces, checkpoints, or logs; - experiment-enabled MCP adds read-only status plus finite start/exact-stop tools. ```text cordis_waterfall_experiment_status cordis_start_waterfall_experiment cordis_stop_waterfall_experiment ``` ## Human Profiler behavior Human profiling also uses the same coordinator. When idle, the existing Human enable/disable flow remains behavior-compatible. When an Agent lease owns instrumentation, the UI identifies the Agent source/expiry and presents an explicit **Stop Agent experiment** emergency action rather than pretending the session is Human-owned. Human emergency stop always reduces instrumentation; an Agent cannot silently steal active Human ownership. ## Privacy and evidence boundary v0.6 keeps the metadata-first contract. Controlled experiments do not collect raw event arguments, return values, error objects/messages, prompts, tool outputs, file contents, plugin config, credentials, bearer tokens, or raw Effect functions/disposers. The runtime still does not invent `selfTime`, definitive `shortCircuit`/`veto`, root cause, confidence, or “bug fixed” verdicts. ## Real DSH proof The final keyless Chromium/real-DSH gate runs alongside the v0.5 Runtime Verification regression and proves: ```text real DSH SessionStore live session + open turn ↓ real ToolRuntime ↓ real ApprovalService ├─ unavailable/rejected → no mutation └─ allowed-once → finite DSH Agent lease ↓ real waterfall ↓ exact tagged trace ↓ stale stop no-op / exact stop then official external MCP Client + bearer auth ↓ finite MCP lease ↓ exact experimentId trace filter ↓ Human emergency stop and TTL cleanup then ordinary Human Profiler still works ``` The fixture intentionally uses the shipped `SessionStore` to create an authoritative live session and opens a real turn before invoking the ToolRuntime. It does not bypass the DSH session/approval pipeline and requires no model or API key. ## Non-goals / deferred work Still outside v0.6: - automatic source/plugin reload or verification orchestration; - arbitrary Cordis event execution; - generic listener/service/config mutation; - persistent approval grants; - lease renewal or multiple simultaneous leases; - remote/LAN MCP; - raw payload capture; - automatic root-cause `diagnose()`; - profiling emit/parallel/serial/bail modes. ## Repository completion v0.6 is repository-ready when the source tree identifies itself as `0.6.0`, the architecture Note is implemented, the roadmap/parallel record match the landed PRs, and the full policy/typecheck/test/build/client-bundle/two-real-DSH-smoke gate is green. Repository readiness does **not** imply npm publication, a Git tag, or a GitHub Release.