Commit Graph
5 Commits
Author SHA1 Message Date
imccyu ecdaf0dc24 test(web): connect a Workspace in the e2e boot path and refresh goldens
The startup-selection flow leaves a fresh world (no Workspace) in the
locked view state, so every e2e scenario that types into the composer
now connects one first via the shared connectFreshWorkspace helper
(hero picker create-by-name dialog; the default 'workspace' name keeps
the session-header cwd assertions intact).

Golden refreshes carry the current composer chrome: the plan/model
control seats are empty until their owning plugins register (the seats
shipped without occupants on this branch), the sidebar shows the
connected workspace group pre-send, and the bash details material
renders Input/code/Output as separate nodes. The cancel scenario polls
the frozen-partial swap instead of counting synchronously — the abort
frame reaches the browser over SSE after the host settles.
2026-07-27 08:25:00 +08:00
Tianyi Cui e2882f486b fix(review): harden web replay verification
Validate replay sidecars and cross-copy failure facts, make browser console tripwires and macOS temp paths deterministic, and wait for asynchronous TUI resume details. Keep the owning docs, translations, and generated catalog aligned.
2026-07-26 22:38:33 +08:00
Tianyi Cui f1b7d52a77 fix review findings: hostile code accessor + swallowed teardown
Both ds-review-bot findings were real:

- markLlmAdapterFailure's carried-facts cross-check read error.code
  directly; a foreign Error with a valid own failure payload but a
  throwing code accessor would replace the original adapter error with
  the accessor exception, breaking the error-identity guarantee. The
  read now goes through foreignErrorCode(), which contains the trap and
  falls back to the normalized snapshot (test: hostile code accessor
  beside a valid failure payload -> original identity kept, UNKNOWN
  facts).
- live-interactions' afterEach caught scaffold.close() into undefined,
  silently disabling ReplayHandle.assertConsumed() — the fixture-drift
  tripwire — and hiding cleanup defects. Teardown now runs every step,
  collects failures, and rethrows (AggregateError when several).
2026-07-26 14:12:52 +08:00
Tianyi Cui ea1d8d06b3 test(web): pin every scenario end-state with an aria golden
Every spec now commits at least one golden and the interactive ones one
per distinct end-state (nine new .expected.md):

- live-interactions: cancel.expected.md (frozen partial + 已停止 marker),
  error-auth.expected.md (the prompt bubble alone — the committed artifact
  of the web-error-surface gap, the diff that flips when error rendering
  lands), retry.expected.md (indistinguishable from a clean completion —
  retries are deliberately invisible in the transcript).
- question-composer: answered.expected.md (the question resolved into its
  tool round trip plus the final reply, takeover gone) beside the existing
  waiting-state golden.
- steering: mid-steer.expected.md pins the accepted-but-INVISIBLE state
  (the loop drains steering only at the step boundary, so no interjection
  bubble exists while the question still blocks — if the client ever
  renders pending steers eagerly, this golden flips first) and
  settled.expected.md the badged bubble plus obeying reply.
- navigation-panes: waterfall.expected.md and details-open.expected.md
  (tool-name header, Input args, Output result) beside the trajectory one.
- lifecycle-chrome: reloaded.expected.md — rendering the same settled
  transcript from persistence alone IS the recovery claim.

Fixture inventories extended to the new closed sets; the Agent Note's
expected-outputs policy updated in both languages (per-end-state goldens
for interactive scenarios), pairing re-recorded.
2026-07-26 12:45:44 +08:00
Tianyi Cui 04b7f517ae test(web): live-turn interaction scenarios — cancel, error, retry, question composer, steering
Five browser e2e scenarios over the existing keyless lane, one recorded
base fixture per spec family:

- live-interactions: one tool-free recorded turn + per-run override
  sidecars authored in the spec (content single-sourced from the fixture
  via deriveReplayScript, minted into a spec-owned temp dir). Cancel uses
  a hang patch with a readyFile marker — the marker proves the stream is
  parked mid-turn before the Stop click, so mid-stream cancellation is
  deterministic by construction (turn/end 'aborted', composer re-enabled).
  AUTH pins the non-retryable path: turn/end 'error', zero llm/retry
  events, composer recovers; FIXME(web-error-surface) marks the found
  product gap (no error copy renders — the client consumes no agent/error
  frames and a pre-chunk failure freezes no partial). SERVER retry appends
  the fixture's own success after an injected throw and proves llm-retry
  end-to-end in the browser via the durable llm/retry record.
- question-composer: the shipped ask_user_question takeover blocks the
  turn mid-step on the real userInteraction seam; the test answers through
  the composer (the one sanctioned model-content-reactive drive step: the
  turn cannot complete without it) and the tool result carries the answer.
  Adds the composer waiting-state aria golden.
- steering: steers mid-turn while the composer blocks the step (the
  deterministic mid-turn window). The steer rides the real wire
  (session.prompt mode:'steer' POSTed from the page; the locked composer
  has no steering gesture yet — TODO(web-steer-composer)); downstream is
  all product: gateway -> Agent.steer -> step-boundary drain -> durable
  steering/message -> SSE -> badged interjection bubble. Record mode
  rejects a fixture whose live reply ignored the steer.

Scaffold gains the replayOverride passthrough; specs register in both
tsconfig planes (client exclude, host include).
2026-07-26 03:36:55 +08:00