# Helixwright 1.0 AI Rules

Target SDK: `helixwright==1.0.0` (local release candidate).

These rules are normative for code generation and review. The SDK is a breaking,
single-protocol facade over Helix Browser Desktop Local API and Browser RPC V6.

## Exact runtime contract

| Contract item | Required value |
| --- | --- |
| Browser RPC protocol | `6` |
| Endpoint | `/rpc/v6` |
| Chromium core contract | `0075` |
| Semantic contract hash | `40DFB6DEDAA4CD9A1F56BCEBB019A08B1F57025A28069E79605945CA1FF60BE8` |
| Required wire methods | 41 namespaced methods, schema version `1` each |
| Required capabilities | 11 integer capabilities, version `>=1` each |
| Action receipt | exactly the 22 evidence fields defined by `helixwright.rpc_contract` |
| Trace manifest | `helixwright.trace.session`, schema version `4` |

Admission is fail-closed. Do not bypass a protocol, endpoint, method-version,
capability-version, core-contract, or semantic-hash mismatch.

## Architecture boundaries

- Helix Browser Desktop owns profiles, fingerprint selection, proxy configuration,
  Chromium processes, automation sessions, lifecycle leases, and Local API jobs.
- Helixwright owns the typed Python facade, immutable scopes, readiness contracts,
  action effects, statecharts, Trace/Authoring, and Flow IR.
- Browser core owns element resolution, frame/OOPIF and Shadow DOM traversal,
  target-owned scrolling, mechanical actionability, trusted input, final dispatch
  revalidation, default trajectories, action journals, and authoritative receipts.
- Do not use CDP, WebDriver, Playwright, Selenium, direct Chromium launch, local user
  data directories, synthetic DOM events, or JavaScript as an action substitute.

## Public namespace rule

- Use root `helixwright` for `launch`, `attach`, `Page`, `Frame`, `Locator`, `Input`,
  readiness, effects, motion, and statecharts.
- Use `helixwright.admin` for Local API/profile/proxy/session administration.
- Use `helixwright.expert` for Trace/probe, immutable context/snapshot types,
  balanced gestures, diagnostics, and Flow IR.
- Use `helixwright.signals` for typed outcome signals.
- Use `helixwright.errors` for the complete error hierarchy.
- If a name is absent from `api.md`, do not infer or recreate it.

## Launch and ownership

- `hw.launch(...)` creates a server-owned profile when `reuse_profile_id` is absent.
  `name` is optional. The server chooses a coherent fingerprint and geo-follow
  configuration; a proxy may be the only supplied environment input.
- Reuse an existing profile only with an explicit `reuse_profile_id`.
- `hw.attach(session_id)` is control-only by default. Set `take_ownership=True` only
  when this caller must own and close that browser session.
- Prefer `with hw.launch(...) as page:` so owned browser cleanup is deterministic.
- A lifecycle close is complete only after the Local API session is absent and the
  profile has no active browser process.

## Locator and action rules

- Use semantic locators when possible: role/name, label, placeholder, text, title,
  alt text, test id, or stable CSS.
- `Locator.click()` is the normal action. It already performs immutable frame routing,
  target-owned materialisation/scrolling, actionability, trusted trajectory dispatch,
  and final pointer-down revalidation in one `element.await_ready_and_act` request.
- Do not pre-scroll or fall back to guessed coordinates for an ordinary element
  action. Escalate a reproducible framework gap instead.
- `fill(text)` replaces the control value. `type(text)` focuses and appends keyboard
  input. They are intentionally different operations.
- Use `Locator.upload(...)` for file inputs and `Locator.drag_to(...)` for
  element-bound drag operations.
- Use `Input` only when coordinates are the intended interface. Use one
  `hw.expert.Gesture` when explicit down/move/up or key-down/key-up control is needed.
  A gesture must be balanced before commit.
- JavaScript is diagnostic-only through `page.probe.evaluate(...)`; it must not click,
  fill, submit, dispatch events, or mutate business state.

## Readiness and slow hydration

Mechanical readiness cannot be disabled. For a site-specific hydration, slider,
overlay, network, or widget condition, add a serializable `ReadinessContract` to the
same locator action:

```python
ready = hw.ReadinessContract(
    all_of=(
        hw.ReadinessSignal.attribute(
            "#submit", "data-hydrated", equals="true"
        ),
    ),
    stable_frames=3,
    quiet_ms=100,
    description="submit is hydrated in the current document epoch",
)

effect = page.locator("#submit").click(ready=ready, timeout_ms=15_000)
```

- Readiness must be structured data, never a Python callback.
- Visibility alone is not business readiness.
- The core evaluates readiness and mechanical conditions in the target document epoch,
  grants a bounded lease, and performs a final identity/geometry/hit-test check before
  dispatch.
- For sliders, prove handle identity/bounds stability and widget initialization before
  pointer-down; prove the expected drag state after pointer-down.

## Authoritative action result

Keep the `RuntimeActionEffect` returned by the action that matters:

```python
effect = page.get_by_role("button", name="Save").click(ready=ready)
assert effect.ok
assert effect.dispatch_phase == "completed"
assert effect.receipt_confirmed
assert effect.receipt.action_id == effect.action_id
```

- The action's own effect and receipt are authoritative. A page-global last effect is
  diagnostic only and must not be used to prove a concurrent action.
- Do not replay an action whose dispatch is unknown. Reconcile through the V6 action
  journal first; retry only when evidence proves it was not dispatched and policy
  explicitly permits retry.
- Every completed mutation must carry its own receipt. Do not substitute the latest
  receipt from another request.

## Immutable frames and one-epoch reads

- `page.frame(selector)` returns an immutable child scope; nesting appends to its frozen
  frame chain and never changes a process-global frame cursor.
- A frame locator, probe, input operation, or state machine must retain that scope.
- Locator reads use one `state.snapshot` epoch. Mixed target/frame/document evidence is
  an error, not a false `hidden` or `detached` result.
- Waits use a private `events.subscribe` cursor followed by a confirming snapshot; do
  not add fixed sleeps or zero-timeout busy loops.

## Statechart rule

Use `StateMachine` for branchy, retryable, multi-page, frame-scoped, or concurrent
flows. Each state must have a serializable `Signature`; a non-terminal state must own
the readiness contract, return its exact action effect, and declare an
`OutcomeContract`.

The required cycle is:

1. classify from one atomic snapshot;
2. open a transition-owned event subscription;
3. dispatch one authoritative action;
4. evaluate typed outcome evidence bound to that action;
5. reclassify from a confirming atomic snapshot.

Unknown, ambiguous, mixed-epoch, malformed signal, foreign receipt, broken event
sequence, uncertain dispatch, deadline, cancellation, or oscillation must fail closed.
Model frame applications as frame-scoped child machines and overlays as explicit
regions; do not hide concurrency inside handler polling.

## Private Trace/Authoring evidence

Trace and Authoring evidence is owner-private and intentionally full-fidelity. When
observed, preserve raw passwords, proxy usernames/passwords, cookies, authorization
data, form values, storage, action arguments, request/response headers, duplicate raw
header lines, and request/response bodies.

- No automatic masking, redaction, or value-capture downgrade is applied.
- Evidence is written to an owner-only run directory with per-run locking and atomic
  manifest replacement.
- Evidence is `local_only=true` and `upload=false`; it is never automatically uploaded
  with SDK, Skill, documentation, or release publication.
- Screenshots are supplementary. Structured selectors, state identity, readiness,
  event correlation, action effects, and receipts are primary evidence.
- Close every recorder/controller before verification.

## Production delivery

A production AI-authored flow must include:

- `flow.py` using only the current public surface;
- a closed, persistent Authoring run directory;
- atomically written schema-1 `AUTOMATION_FLOW.json` from `hw.expert.FlowIR`;
- `AUTOMATION_REPORT.md` with state, readiness, receipt/dispatch, outcome, evidence,
  framework-gap, tests, and residual-risk sections.

Flow IR must bind states, signatures, immutable contexts, readiness, core action ids,
final dispatch phases, matching receipts, causal outcomes, transitions, Trace windows,
and matching run/trace ids. Its evidence ledger must declare `complete=true`,
`full_fidelity=true`, `local_only=true`, and `upload=false`.

Stop and report a framework gap when repeated evidence shows a locator, OOPIF/shadow,
scroll, actionability, trusted-input, motion, Trace, readiness, navigation, download,
upload, dialog, or lifecycle defect. Do not hide it with coordinates, JavaScript,
unbounded retries, or a second browser session.
