Commit Graph
218 Commits
Author SHA1 Message Date
pj 419a2d564e feat(verifier): track extractor value transitions
Cache each extractor's prior and current JSON-encoded value during
PushSnapshot; expose ChangedExtractors to surface per-step diffs the
runner can emit into the trace. The first observation flushes every
non-null extractor as a change so the inspect UI shows initial state
breadcrumbs alongside later transitions.
2026-05-30 21:57:59 +05:30
pj 07c292913c chore(folio): name every extract() call
Give each extractor in the Folio spec a debuggable label so the
inspect UI can render extractor-value diffs at violation steps
keyed by intent (ledgerRows, route, ledgerBalance, ...) rather
than by registration index.
2026-05-30 21:54:35 +05:30
pj 1b35e5a6a6 feat(verifier): name extractors for diff surfacing
bindExtract accepts an optional name argument; falls back to
extractor_N when omitted. The name is stored on extractorState
alongside prev/curr value caches that the next change will use to
emit per-step diffs.
2026-05-30 21:54:30 +05:30
pj cbef329cdd test(spec): cover extract name overload
Verify the runtime receives an undefined name in the legacy shape,
the supplied name in the (name, getter) shape, and that
extract("name") with no getter throws.
2026-05-30 21:54:25 +05:30
pj 6fdbf9d2ab feat(spec): accept optional name on extract()
Add an (name, getter) overload so each extractor handle carries a
debuggable label that future trace fields (per-step diffs) can key
off. The web-runtime falls back to extractor_\${index} when none is
supplied so existing call sites keep working unchanged.
2026-05-30 21:54:20 +05:30
pj 7291d5965b test(sidecar): cover pollUntilStable and structuralHash
Verify the poll returns on two equal snapshots, after transient
churn, and at the cap when never stable; assert the hash ignores
bounds-only flicker and detects content changes.
2026-05-30 21:50:52 +05:30
pj cd4bd5a194 feat(sidecar): structural-hash settle poll
Add pollUntilStable and structuralHash helpers; wire them into the
Stub, Maestro, and iOS backends' waitForIdle. The structural hash
ignores bounds-only flicker (measure passes) but trips on any change
in resource-id/class/content-desc/text, so a Compose cross-fade where
both source and destination composables are momentarily alive no
longer slips through Maestro's waitForAppToSettle and contaminates
the next hierarchy fetch.
2026-05-30 21:50:46 +05:30
pj 50e03244d6 refactor(inspect-ui): use next step's screenshot for state after
Each step now has one screenshot (the moment of observation). The
"state after" view of step N is the same moment as step (N+1)'s
observation, so reuse that file rather than expecting a separate
-after.png.
2026-05-30 21:48:26 +05:30
pj fb69c1b774 refactor(runner): one concurrent screenshot per step
Move screenshot capture into the post-action errgroup so it observes
the same UI moment as the hierarchy fetch. Drop the pre-action and
deferred -after captures. Skip WaitForIdle when the action is Wait
since the wait itself provides settling time.
2026-05-30 21:48:21 +05:30
pj 095b58afcf refactor(trace): drop WriteScreenshotAfter
Only one screenshot per step is captured now (concurrently with
hierarchy after settle), so the -after.png variant is unused.
2026-05-30 21:48:17 +05:30
pj f9512354ed refactor(folio): replace txn invariants with balanceMatchesAddedTxn
Collapse noDuplicateTxnPerStep and newTxnChangesBalance into a single
per-row property: every newly-appearing ledger row's signed amount must
match the ledger balance delta. A double-submit lands two rows whose
individual amounts cannot both equal the aggregate delta, so each row
fires the property, catching both the row-count and balance-math
classes of bug under one semantic invariant.
2026-05-30 21:44:41 +05:30
pj 352118c199 fix(verifier): canonicalize selector strings
Object/chain JS selectors used to fall through to goja's default
stringification, producing "[object Object]" tags that surfaced as
garbage in trace.action.selector. Emit canonical "k:v" / " > "-joined
strings instead so the tag round-trips back through the hierarchy
selector grammar.
2026-05-30 21:43:27 +05:30
pj 09c1b8df26 fix(folio): make login spec content-driven (idempotent across re-entries) 2026-05-30 17:04:11 +05:30
pj c69052ae89 style(verifier): use maps.Copy for verdict snapshot 2026-05-30 16:33:23 +05:30
pj 60c4ef7458 refactor(runner): emit onset-only violations to trace and summary
Switch the per-step violation list from the sticky verdict map to the
verifier's onset set. Each property now appears exactly once across a
run: at the step it first violates, not on every subsequent step where
the residual stays false. Removes the dead violationNames helper.
2026-05-30 16:32:17 +05:30
pj b9fa41553f feat(verifier): track newly-violated property set per step
Sticky `always(P)` violations re-surfaced on every step after onset,
flooding traces and summaries with duplicate records. EvaluateProperties
now diffs against the prior verdict map and records the onset set; a new
NewlyViolatedProperties accessor exposes it so callers can emit each
violation exactly once at its onset step. The verdict-map return is
preserved for residual / current-verdict consumers.
2026-05-30 16:30:37 +05:30
pj 3d67e5e3b6 fix(folio): make ledgerRowsSeen monotonic to suppress transient-render false positives 2026-05-30 16:01:16 +05:30
pj aa42b8e504 refactor(folio): drop doubleSubmitTxn; fuzzer surfaces double-submit via defaultActions 2026-05-30 16:00:14 +05:30
pj 801f09d455 feat(verifier): add doubleTaps random-target generator 2026-05-30 16:00:09 +05:30
pj 177b571b0a feat(spec): add doubleTaps random-target builtin to defaultActions 2026-05-30 16:00:06 +05:30
pj f08d9119b2 fix(folio): track ledger row count across non-ledger steps; pin reproducer seed 2026-05-30 11:44:43 +05:30
pj 9f17afecc2 feat(folio): add noDuplicateTxnPerStep invariant and doubleSubmitTxn action 2026-05-30 11:07:31 +05:30
pj 87834caf96 test(doubleTap): cover constructor, verifier round-trip, and runner dispatch 2026-05-30 11:05:58 +05:30
pj fb085eeaa0 feat(runner): dispatch DoubleTap as two taps inside one step 2026-05-30 11:05:53 +05:30
pj 6766f1ad58 feat(verifier): bind doubleTap and decode DoubleTap actions 2026-05-30 11:05:50 +05:30
pj 237ead2d33 feat(spec): wire DoubleTap through web-runtime serializer 2026-05-30 11:05:47 +05:30
pj 7006e82ca4 feat(spec): add DoubleTap action type and constructor 2026-05-30 11:05:44 +05:30
pj a9b2b4b4e1 fix(spec): drop hardware back from defaultActions to stay in-app 2026-05-28 11:24:31 +05:30
pj dff91095b8 feat(runner): relaunch app when foreground escapes during exploration 2026-05-28 11:23:50 +05:30
pj dea39d3bac feat(sidecar): implement ForegroundApp via adb for android 2026-05-28 11:21:52 +05:30
pj 09528d84e6 feat(android): detect foreground package via adb dumpsys 2026-05-28 11:21:14 +05:30
pj 4d26bdf00d feat(driver): add ForegroundChecker optional capability 2026-05-28 11:19:49 +05:30
pj 032129cc5f chore(folio): auto-boot a bootable AVD in just test/install when none connected 2026-05-25 19:11:11 +05:30
pj 64d0633bd6 feat(spec): typing builtin for the web (V8) action path 2026-05-25 18:42:30 +05:30
pj 9df104e5b2 test(chrome): editable flag for inputs, textarea, contenteditable 2026-05-25 18:28:32 +05:30
pj b8b183e970 fix(testrun): alias @sanderling/spec/defaults for the bundler 2026-05-25 18:21:12 +05:30
pj 761627dde3 test(spec): defaultActions, typing, and defaults barrel resolve 2026-05-25 18:16:52 +05:30
pj be0d071826 test(hierarchy): editable derivation and selector matching 2026-05-25 18:16:20 +05:30
pj b59a62643d test(verifier): typing builtin targets editable fields, declines otherwise 2026-05-25 18:15:52 +05:30
pj bf235e54c2 feat(folio): layer defaultActions breadth over targeted flows 2026-05-25 18:14:40 +05:30
pj 7fd8b6d347 feat(spec): export @sanderling/spec/defaults subpath 2026-05-25 18:13:36 +05:30
pj c8528af12b feat(spec): add defaultActions bundle 2026-05-25 18:13:36 +05:30
pj 9ca16e7627 feat(spec): export typing builtin generator 2026-05-25 18:13:13 +05:30
pj 923d06813e feat(verifier): typing builtin types edge-case corpus into editable fields 2026-05-25 18:12:31 +05:30
pj e079574571 feat(verifier): register typing builtin generator 2026-05-25 18:12:08 +05:30
pj bf922fcbd5 feat(spec): add editable to selector and element types 2026-05-25 18:11:56 +05:30
pj f2ebedd82a feat(verifier): expose editable on ax element objects 2026-05-25 18:11:56 +05:30
pj 5d21b8c2cf feat(chrome): emit editable flag in hierarchy dump 2026-05-25 18:11:41 +05:30
pj 1d01ca77dc feat(hierarchy): add editable signal with native derivation 2026-05-25 18:11:01 +05:30
pj f572c8ba66 WIP: docs: refresh after iOS + web support (#50)
* docs: README covers iOS + web, surface both example apps

* docs(cli): document --ios-device and per-platform doctor

* docs: tighten README, fold examples into Docs list

* docs(runs): correct --clear-data lifecycle wording

Default behavior no longer wipes app data between runs; --clear-data is now opt-in.

* docs(getting-started): add iOS path, separate folio and folio-web

Document just test-ios under examples/folio, and distinguish the KMP
sample from the React + Vite folio-web sample.

* docs(inspect): document the eight panels

Lists Screenshot, ActionList, Timeline, ViolationsPanel, HierarchyPanel,
SnapshotTable, MetricsChart, ExceptionsPanel. Cross-links HierarchyPanel
to the spec language reference.

* docs(writing-specs): document setup export, flag noLogcatErrors as android-only

Mirrors pkg/spec/README.md so the manual covers the runner's setup-first
fall-through. Marks noLogcatErrors as Android-only so iOS/web spec
authors know it silently no-ops.

* docs(folio): document web target and iOS sanderling test recipe

After the KMP refactor folio also runs on wasmJs and the justfile exposes
just web, just web-build, and just test-ios. Surface all three.

* docs(folio-web): add README

Covers prerequisites, demo credentials, just test recipe, and how the
React + Vite host exposes state to the sanderling spec via stable ids
and data-* attributes.

* docs: scrub driver-implementation name from user docs

Drop the implementation tool name from README, cli.md doctor table, and
spec-language.md. These docs should describe behaviour, not the specific
underlying tool the native sidecar wraps.

* docs(development): scrub driver-implementation name from dev docs

architecture, design-principles, decisions now describe the native
sidecar by role (gRPC surface over OS UI-test pipeline) rather than by
the specific tool it wraps.
2026-05-25 16:17:21 +05:30