| # Deterministic AutoCAD sandbox contract |
|
|
| This document defines the only supported path from an AutoCAD benchmark AMI to |
| a model-controlled desktop. “Deterministic” means that every accepted VM proves |
| the same immutable environment and handoff invariants, every ambiguous mutation |
| is replay-safe, and every wait/retry is bounded. It does not mean Windows, AWS, |
| or AutoCAD can never fail; it means those failures either occur before model |
| usage or are retained as explicit rollout failures. |
|
|
| ## Release status |
|
|
| - Active source/runtime contract: `windows-autocad-2019-v10`. |
| - Candidate source/runtime contract: `windows-autocad-2019-v11`. |
| - Worker images and rollback images are built and owned by the operator. |
|
|
| The harness accepts v10 for historical result reproduction and v11 for new |
| runs, while requiring each configuration and live image to agree exactly. |
| Broker v9 images are intentionally rejected before agent handoff. |
|
|
| ## State machine |
|
|
| ```text |
| launch |
| -> EC2 running + both status checks OK |
| -> SSM online |
| -> current-boot interactive readiness |
| -> authenticated exact-process tunnel (up to 3 fresh tunnel processes) |
| -> exact task lease/reset (up to 2 wrapper attempts; broker recovery inside each) |
| -> verified sequence-0 screenshot |
| -> agent handoff |
| -> actions/controller-owned checkpoint save/evidence retrieval |
| -> session release |
| -> instance termination request |
| ``` |
|
|
| Runtime admission deliberately does not run a disposable AutoCAD reset. The |
| immutable broker/session checks are followed directly by the exact task reset, |
| which removes the former gap where a smoke passed but the real reset failed. |
| Release-image validation may still use a disposable smoke as an offline AMI gate. |
|
|
| Before the model child starts, a reset may use the broker's two clean AutoCAD |
| launch attempts, then one wrapper-level replay of the same idempotent task reset. |
| A newly launched clone may then be discarded and replaced once. These layers are |
| bounded and occur before model/API usage. After `sandbox_agent_started`, the |
| sample is never restarted or silently replaced. |
|
|
| ## Required handoff evidence |
|
|
| The model receives the VM only when all of the following are true: |
|
|
| 1. EC2 is `running`; instance and system checks are both `ok`. |
| 2. SSM reports the exact instance online. |
| 3. the readiness timestamp and startup ID belong to the current Windows boot; |
| 4. the installed deployment ID, manifest checksum, broker binary checksum, |
| broker version, and input-driver version all match; |
| 5. Administrator is logged into the DCV console, the broker is in that same |
| nonzero interactive Windows session, and the desktop is exactly 1920x1080; |
| 6. the PyAutoGUI worker has successfully injected its real pointer prewarm on |
| `WinSta0\\Default`; |
| 7. authenticated `/health` through the SSM tunnel identifies the exact broker |
| PID and Windows session that passed readiness; and |
| 8. the rollout's own replay-safe lease/reset has passed the full AutoCAD handoff |
| path: clean process boundary, restored template, rendered ribbon, maximized |
| window, AutoCAD foreground ownership, no unknown modal popup, stable initial |
| pixels, and a sequence-zero PNG with a valid checksum. |
|
|
| The benchmark wall clock begins only after item 8. After that point, AutoCAD is |
| not required to stay maximized or foreground during model work. The model does |
| not save or choose a filename. At checkpoint, the trusted broker focuses the |
| leased AutoCAD process, cancels transient commands, verifies that ActiveX is |
| bound to that exact process, and invokes `Save` or `SaveAs` to a |
| controller-owned attempt path. It retries the COM save five times and accepts |
| the checkpoint only after a stable, signature-valid DWG exists. |
|
|
| ## Bounded recovery and retry matrix |
|
|
| | Boundary | Bound | Safe retry identity / behavior | |
| |---|---:|---| |
| | EC2 `RunInstances` | 6 requests | retries quota-release, capacity, throttling, and transient signing failures | |
| | Other EC2/SSM calls | 3 requests | read calls or idempotent start/stop/terminate calls only | |
| | AutoCAD reset handoff | 2 complete launches | kill process tree, restore template, retry the entire handoff | |
| | Current-clone admission | 2 checks | first check plus one diagnostic broker/process-tree recovery | |
| | Fresh clone admission | 2 clones by default, max 3 | failed clone is terminated before a replacement is launched; no model call occurred | |
| | SSM port-forward startup | 3 fresh processes | each process must make authenticated `/health` pass within 45 seconds | |
| | SSM port-forward during rollout | 8 restarts | one stable local port; watchdog kills the complete process group and reconnects | |
| | Exact task reset | 2 wrapper attempts | same lease and idempotent reset identity; each broker reset retains its own two clean AutoCAD handoffs | |
| | Broker HTTP operation | 8 transport attempts | one operation deadline, fresh HTTP connection, unchanged idempotency identity | |
| | Direct-provider pre-action response | 10 consecutive failures | OpenAI and Anthropic retries are safe because no desktop action has occurred; any valid provider response resets the transport-error streak, while malformed/missing tool output has its own consecutive limit and gets a larger output cap | |
| | Evidence retrieval | 300 seconds total | checkpoint, DWG, events, frame events, and status each have a sub-cap | |
| | Release | 60 seconds | idempotent release; EC2 termination still follows if it times out | |
| | Batch straggler cleanup | 1 reconciliation pass | one tag-scoped `TerminateInstances`, with bounded transient AWS retries and no polling | |
|
|
| No loop polls forever. No retry expands the number of evaluated model samples. |
|
|
| ## Exactly-once mutation rules |
|
|
| - Lease identity is `(task_id, attempt_id)`. A lost lease response is replayed |
| from the existing active lease; a different identity conflicts. |
| - Reset uses stable `request_id=reset-{session_id}` and returns the cached initial |
| screenshot on replay. Reusing another reset key conflicts. |
| - Every action uses a stable SHA-256 request ID derived from attempt ID, model |
| tool-use ID, and batch offset, plus the next expected action index. An identical |
| retry returns the cached action result without input or logging side effects. |
| - Checkpoint and release are state-idempotent. Artifact, event, frame-event, and |
| status retrievals are read-only. |
| - A broker HTTP error is never retried as if it were a transport failure. |
|
|
| This removes the unsafe choice between duplicating an input and abandoning an |
| input whose response was lost. |
|
|
| ## Action outcome rules |
|
|
| The complete action batch is validated before its first input. Coordinates must |
| fit the live display, typed text must be printable ASCII, `done` must be last, |
| and the non-empty batch must fit the remaining 5,000-action rollout budget. There |
| is no separate per-tool-call action-count cap. |
| Local validation errors are returned to the model without touching the desktop. |
|
|
| After input is injected, whole-desktop animation is diagnostic rather than |
| fatal. If pixels do not settle within the post-action window, the broker caches |
| and returns the freshest screenshot with |
| `post_action_visual_stable=false`. This is essential: throwing after input commit |
| would create an ambiguous mutation. Initial handoff stability remains a hard |
| admission requirement. |
|
|
| An input receipt proves only that input reached the interactive Windows desktop. |
| It never proves that AutoCAD semantically accepted the command. The model must |
| inspect the resulting screenshot, restore focus when necessary, and recover from |
| the visible state. |
|
|
| ## Failure classification |
|
|
| - `admission_failed`: no model request was made; clone may receive its one fresh |
| replacement. |
| - `transport_exhausted`: supervised tunnel and bounded broker retries could not |
| restore communication; preserve partial trace/evidence and fail the sample. |
| - `model_contract_error`: provider repeatedly omitted or malformed the required |
| action call; preserve its billable usage and fail the sample. |
| - `action_rejected`: the full batch was rejected before injection and reported |
| back to the model, or an unexpected Windows-side rejection failed closed. |
| - `artifact_unavailable`: final DWG save/checkpoint evidence was absent; the task |
| fails even if screenshots looked correct. |
| - `cleanup_error`: bounded evidence/release/instance cleanup failed; retain it in |
| result/lifecycle state and run tag-scoped fleet reconciliation. |
|
|
| ## Observed scale failures and their v10 controls |
|
|
| | Observed failure | v10 control | |
| |---|---| |
| | SSM tunnel died and all later broker calls failed | watchdog restart on stable port, process-group kill, per-outage restart allowance, fresh HTTP connections, and up to 48 deadline-bounded transport attempts with the same idempotency key | |
| | reset smoke returned HTTP 500 with orphan broker/Python/AutoCAD processes | scheduled-task stop/start gates, bounded tree kill, verified empty runtime/attempt directories, one recovery only | |
| | post-action animation caused `desktop_unstable` after input | return and cache freshest frame with explicit unstable receipt | |
| | lost action response risked duplicate keyboard/mouse input | stable request ID, expected index, cached exact replay | |
| | lost lease/reset response left an unusable active desktop | replay-safe lease identity and cached reset response | |
| | non-ASCII typing failed after earlier batch items ran | whole-batch printable-ASCII validation before injection plus broker defense-in-depth | |
| | OpenAI/Anthropic response omitted/truncated `computer_action` | ten consecutive safe pre-action retries, usage aggregation, larger output allowance, explicit format repair; a valid tool response resets the streak | |
| | transient AWS signature failure aborted preflight/control plane | bounded retry of transient signed AWS calls | |
| | terminated vCPU had not returned to quota | bounded `RunInstances` retry for `VcpuLimitExceeded` | |
| | one bad cold clone required a manual retry pass | one automatic terminate-and-replace admission attempt before model handoff | |
| | finalization hung for many minutes | 300-second total evidence budget and 60-second release bound | |
| | cleanup API error leaked tagged instances | idempotent terminate retries plus one batch tag reconciliation pass | |
|
|
| ## Release gate |
|
|
| Source tests are necessary but not sufficient. A v10 AMI becomes benchmarkable |
| only after the Windows gates in |
| [`incremental-ami-v10-runbook.md`](./incremental-ami-v10-runbook.md) pass on an |
| untouched clone. Until then, v10 is a source candidate and v9 remains only a |
| rollback image, not a compatible runtime for the hardened harness. |
|
|