# Private Trace and Persistent Authoring

Target SDK: `helixwright==1.0.0`, Trace schema
`helixwright.trace.session` version `4`.

Trace is structured causal evidence for authoring and diagnosis. It is not a screenshot
recorder and not a production action engine. Use normal `Locator`/`Input` actions while
Trace records the state, readiness, event, receipt, and outcome evidence around them.

## Evidence policy

Trace and Authoring are owner-private and intentionally full-fidelity. When observed,
they preserve raw:

- passwords and other form values;
- proxy usernames/passwords and launch/runtime proxy data;
- cookies and storage;
- authorization data;
- action arguments;
- network request/response metadata, headers, duplicate ordered raw header lines, and
  request/response bodies.

There is no automatic masking, redaction, or value-capture downgrade. The compensating
controls are:

- owner-only ACL/access boundary established before evidence files are created;
- one isolated, locked run directory;
- atomic manifest/file replacement;
- explicit retention by the owner;
- `local_only=true` and `upload=false`;
- no automatic evidence upload during SDK, Skill, documentation, or release publication.

Treat the run directory as secret-bearing private evidence.

## Persistent Authoring is the default AI workflow

Start one controller and keep the same browser/profile/session/page while discovering
and testing the flow:

```powershell
$run = "evidence\authoring-run"

python -m helixwright author start `
  --url "https://target.example" `
  --run-dir $run `
  --visual-policy adaptive

python -m helixwright author status --run-dir $run

python -m helixwright author exec `
  --run-dir $run `
  --command-id inspect-form-001 `
  --code "page.probe.forms()"

python -m helixwright author checkpoint `
  --run-dir $run `
  --label "form-ready"

python -m helixwright author stop --run-dir $run
```

`author start` starts Trace before target navigation. Every `exec` command is serialized
through the durable command journal. Reuse the same `--command-id` after a timeout and
use `command-status`/`reconcile`; do not submit unknown work under a new identity.

A second launch is a declared new segment and requires a restart reason. A run declared
non-idempotent requires explicit restart authority.

## In-process Trace session

```python
from pathlib import Path

with hw.launch("https://target.example") as page:
    with page.trace.start_session(
        Path("evidence/trace"),
        mode="authoring",
        visual_policy="adaptive",
    ) as trace:
        page.probe.forms()
        page.probe.cookies()
        page.probe.storage()

        effect = trace.action(
            "submit",
            lambda: page.get_by_role("button", name="Submit").click(),
            action_kind="click",
            selector="role=button@@name:Submit",
        )
```

`page.record(path, full_html=True, ...)` is the full-capture convenience entry and
returns the same `TraceRecorder` context manager.

Only one recorder may be active on a page. Always close it before verification.

## Recorder modes and visuals

Available modes are `basic`, `authoring`, `failure_debug`, and `expert_js`.
`authoring` is the normal AI workflow. `failure_debug` increases structured capture and
visual coverage. The expert preset does not imply browser-core JavaScript opcode
channels; unsupported channels remain explicit.

`visual_policy` is one of:

- `off`: no automatic screenshots;
- `adaptive`: session boundaries and evidence-driven checkpoints;
- `all`: broad before/after capture;
- `failure`: failure-focused capture.

Screenshots are supplementary. They never replace selector identity, one-epoch
snapshots, readiness, correlated events, action effects, or receipts.

## Manifest contract

Every `manifest.json` records:

- schema `helixwright.trace.session`, version `4`;
- trace/run/segment/launch identities;
- protocol `6`, endpoint `/rpc/v6`, core contract `0075`;
- semantic hash
  `40DFB6DEDAA4CD9A1F56BCEBB019A08B1F57025A28069E79605945CA1FF60BE8`;
- all 41 method schema versions and 11 capability versions;
- atomic document fields and exact 22 receipt fields;
- full-fidelity/local-only/no-upload/access-boundary flags;
- structured event/action/probe/asset counts and incomplete reasons;
- whether Trace started before target navigation.

An open, incomplete, foreign-contract, or access-boundary-failed manifest is not valid
production evidence.

## Files

A recorder writes atomically managed evidence under the run directory:

- `manifest.json`;
- `events.jsonl`;
- `actions.jsonl`;
- `probes.jsonl`;
- `channels/*.jsonl` filtered structured views;
- `assets/` for snapshots, visuals, and network bodies;
- generated `AUTOMATION_REPORT.md` when `trace.report()` is called.

Network body assets retain raw bytes, size, SHA-256, text encoding, completeness, and
lossless raw response headers. Empty bodies are still represented as complete evidence;
missing/evicted evidence must not be misreported as an empty body.

## Probe surfaces

`page.probe` is a scope-aware `hw.expert.ProbeController`:

```python
page.probe.snapshot(full=False)
page.probe.forms()
page.probe.interactables(limit=200)
page.probe.cookies()
page.probe.storage()
page.probe.listener_hints("#submit")
page.probe.selector_candidates("role=button@@name:Submit")
page.probe.locator("#submit").explain()
page.probe.signature(name="checkout")
page.probe.evaluate("document.readyState", label="ready-state")
```

Form/cookie/storage values are complete private evidence. `evaluate()` is diagnostic
only; do not use it to mutate page state or synthesize actions.

For a frame:

```python
payment = page.frame("iframe#payment")
payment.probe.forms()
page.probe.scoped(payment.scope).snapshot()
```

## Action slices and marks

```python
with page.record("evidence/run") as trace:
    before = trace.mark("before-submit")
    effect = page.locator("#submit").click(ready=ready)
    after = trace.mark("after-submit")
    raw_slice = page.trace.segment(before, after, limit=200)
```

Keep the effect returned by the action. The action slice must carry that same
`action_id`; do not recover proof from a page-global latest value.

Use `Trace.load(...)`, `timeline(...)`, `digest(...)`, `effect_of(...)`, and
`segment(...)` for bounded offline inspection. `trace_diff(...)` and
`stability(...)` compare repeated runs.

## Recommended authoring loop

1. Start one persistent controller and Trace before navigation.
2. Observe one-epoch state, frames, interactables, forms, listeners, network, and
   storage without mutating the page.
3. Derive strong structured selectors, state signatures, readiness signals, and
   expected outcomes from evidence.
4. Execute one candidate action in the same browser and inspect its own effect,
   receipt, correlated events, and confirming state.
5. Repeat independent runs where needed, then emit the statechart and schema-1 Flow IR.
6. Close the run and verify all evidence/receipt/dispatch/terminal-state gates.

Do not restart from the beginning after every probe. Restart only when the site or test
requires a new session and record the reason/authority in the Authoring manifest.

## Framework-gap handling

If repeated structured evidence shows the SDK/core cannot represent or execute a
required selector, frame/shadow path, scroll, readiness condition, trusted action,
motion, network, dialog, download, or lifecycle operation, stop. Record a stable gap
id, exact API call, target/frame/document identity, expected/observed behavior, Trace
slice, receipt, and recommended fix layer. Do not hide the gap with JavaScript,
coordinates, silent retries, or a new browser.
