diff --git a/.gitignore b/.gitignore index 128829e..5bcbfd2 100644 --- a/.gitignore +++ b/.gitignore @@ -38,15 +38,15 @@ pkg/spec/dist/ # goreleaser local output /dist/ -# inspect web bundle output; built by `make web-build` before go build. +# replay web bundle output; built by `make web-build` before go build. # Only .gitkeep is tracked so //go:embed all:dist compiles on a fresh checkout. -/internal/inspect/dist/* -!/internal/inspect/dist/.gitkeep +/internal/replay/dist/* +!/internal/replay/dist/.gitkeep -# inspect web frontend -inspect-ui/node_modules/ -inspect-ui/dist/ -inspect-ui/.vite/ +# replay web frontend +replay-ui/node_modules/ +replay-ui/dist/ +replay-ui/.vite/ # folio-web frontend examples/folio-web/node_modules/ @@ -59,3 +59,5 @@ examples/folio-web/.vite/ # Personal research notes /research/ + +/talk/ \ No newline at end of file diff --git a/Makefile b/Makefile index e7733a1..57a4d7d 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,10 @@ PAGE_OUT := $(patsubst docs/%.md,build/site/%/index.html,$(PAGE_SRC)) DOCS_OUT := $(INDEX_OUT) $(PAGE_OUT) DOCS_TEMPLATE := docs/_template/page.html -INSPECT_DIST := internal/inspect/dist -WEB_DIST := inspect-ui/dist +REPLAY_DIST := internal/replay/dist +WEB_DIST := replay-ui/dist -.PHONY: bootstrap proto sidecar sanderling install test test-go test-browser test-kotlin test-spec-api web-typecheck web-build web-dev inspect-dev docs clean release-cli release-npm-dry +.PHONY: bootstrap proto sidecar sanderling install test test-go test-browser test-kotlin test-spec-api web-typecheck web-build web-dev replay-dev docs clean release-cli release-npm-dry bootstrap: $(GO) mod download @@ -48,19 +48,19 @@ install: $(SIDECAR_EMBED) web-build @dest="$$($(GO) env GOBIN)"; [ -n "$$dest" ] || dest="$$($(GO) env GOPATH)/bin"; echo "installed sanderling to $$dest" web-build: - cd inspect-ui && bun install --frozen-lockfile && bun run build - mkdir -p $(INSPECT_DIST) - rm -rf $(INSPECT_DIST)/assets $(INSPECT_DIST)/fonts - cp -R $(WEB_DIST)/. $(INSPECT_DIST)/ + cd replay-ui && bun install --frozen-lockfile && bun run build + mkdir -p $(REPLAY_DIST) + rm -rf $(REPLAY_DIST)/assets $(REPLAY_DIST)/fonts + cp -R $(WEB_DIST)/. $(REPLAY_DIST)/ web-dev: - cd inspect-ui && bun run dev + cd replay-ui && bun run dev -inspect-dev: $(SIDECAR_EMBED) - $(GO) run -tags withsidecar ./cmd/sanderling inspect --dev +replay-dev: $(SIDECAR_EMBED) + $(GO) run -tags withsidecar ./cmd/sanderling replay --dev web-typecheck: - cd inspect-ui && bun install --frozen-lockfile && bun run typecheck + cd replay-ui && bun install --frozen-lockfile && bun run typecheck $(SIDECAR_JAR): $(SIDECAR_SRC) ANDROID_HOME=$(ANDROID_HOME) $(GRADLE) :sidecar:shadowJar diff --git a/README.md b/README.md index 40488ef..c3bd0c6 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ Autonomous property-based testing for mobile and web apps. - [Getting started](https://priyanshujain.github.io/sanderling/manual/getting-started.html) - [Writing specs](https://priyanshujain.github.io/sanderling/manual/writing-specs.html) -- [`sanderling inspect` UI](https://priyanshujain.github.io/sanderling/manual/inspect.html) +- [`sanderling replay` UI](https://priyanshujain.github.io/sanderling/manual/replay.html) - Examples: [folio](https://github.com/priyanshujain/sanderling/tree/master/examples/folio) (KMP, Android/iOS/web), [folio-web](https://github.com/priyanshujain/sanderling/tree/master/examples/folio-web) (React + Vite) - [Architecture](https://priyanshujain.github.io/sanderling/development/architecture.html) -After a `sanderling test` run, browse traces locally with `sanderling inspect`. It opens a web UI for stepping through actions, screenshots, snapshots, residual formulas, and exceptions. +After a `sanderling test` run, browse traces locally with `sanderling replay`. It opens a web UI for stepping through actions, screenshots, snapshots, residual formulas, and exceptions. --- diff --git a/cmd/sanderling/main.go b/cmd/sanderling/main.go index 302d283..8273656 100644 --- a/cmd/sanderling/main.go +++ b/cmd/sanderling/main.go @@ -34,7 +34,7 @@ Usage: Commands: test Run a spec against an app for a fixed duration. - inspect Serve a local web UI for browsing runs/. + replay Serve a local web UI for browsing runs/. doctor Check that the host environment is ready to run sanderling. version Print the sanderling version. @@ -98,12 +98,12 @@ func run(args []string, stdout, stderr io.Writer) error { return err } return runTest(options, stdout) - case "inspect": - options, err := parseInspectArgs(args[2:], stderr) + case "replay": + options, err := parseReplayArgs(args[2:], stderr) if err != nil { return err } - return runInspect(options, stdout) + return runReplay(options, stdout) case "doctor": return runDoctor(args[2:], stdout, stderr) case "version", "-v", "--version": diff --git a/cmd/sanderling/inspect.go b/cmd/sanderling/replay.go similarity index 74% rename from cmd/sanderling/inspect.go rename to cmd/sanderling/replay.go index 29190b7..9d24dec 100644 --- a/cmd/sanderling/inspect.go +++ b/cmd/sanderling/replay.go @@ -14,29 +14,29 @@ import ( "strconv" "time" - "github.com/priyanshujain/sanderling/internal/inspect" + "github.com/priyanshujain/sanderling/internal/replay" ) -type inspectOptions struct { +type replayOptions struct { port int noOpen bool dev bool directory string } -func parseInspectArgs(args []string, stderr io.Writer) (inspectOptions, error) { - flagSet := flag.NewFlagSet("inspect", flag.ContinueOnError) +func parseReplayArgs(args []string, stderr io.Writer) (replayOptions, error) { + flagSet := flag.NewFlagSet("replay", flag.ContinueOnError) flagSet.SetOutput(stderr) - var options inspectOptions + var options replayOptions flagSet.IntVar(&options.port, "port", 0, "TCP port to listen on (0 = ephemeral)") flagSet.BoolVar(&options.noOpen, "no-open", false, "do not open the default browser on startup") - flagSet.BoolVar(&options.dev, "dev", false, "reverse-proxy non-API requests to "+inspect.DevTarget) + flagSet.BoolVar(&options.dev, "dev", false, "reverse-proxy non-API requests to "+replay.DevTarget) if err := flagSet.Parse(args); err != nil { - return inspectOptions{}, err + return replayOptions{}, err } rest := flagSet.Args() if len(rest) > 1 { - return inspectOptions{}, errors.New("inspect takes at most one positional argument (run or runs directory)") + return replayOptions{}, errors.New("replay takes at most one positional argument (run or runs directory)") } if len(rest) == 1 { options.directory = rest[0] @@ -44,16 +44,16 @@ func parseInspectArgs(args []string, stderr io.Writer) (inspectOptions, error) { return options, nil } -func runInspect(options inspectOptions, stdout io.Writer) error { - runsDirectory, deepLinkID, err := inspect.ResolveRunsDirectory(options.directory) +func runReplay(options replayOptions, stdout io.Writer) error { + runsDirectory, deepLinkID, err := replay.ResolveRunsDirectory(options.directory) if err != nil { return err } devTarget := "" if options.dev { - devTarget = inspect.DevTarget + devTarget = replay.DevTarget } - server, err := inspect.NewServer(inspect.ServerOptions{ + server, err := replay.NewServer(replay.ServerOptions{ RunsDirectory: runsDirectory, DevTarget: devTarget, }) @@ -67,7 +67,7 @@ func runInspect(options inspectOptions, stdout io.Writer) error { } address := listener.Addr().(*net.TCPAddr) browseURL := buildBrowseURL(address, deepLinkID) - fmt.Fprintf(stdout, "sanderling inspect listening on %s (runs=%s)\n", browseURL, runsDirectory) + fmt.Fprintf(stdout, "sanderling replay listening on %s (runs=%s)\n", browseURL, runsDirectory) context, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/cmd/sanderling/inspect_test.go b/cmd/sanderling/replay_test.go similarity index 54% rename from cmd/sanderling/inspect_test.go rename to cmd/sanderling/replay_test.go index dbf2c35..ab01d68 100644 --- a/cmd/sanderling/inspect_test.go +++ b/cmd/sanderling/replay_test.go @@ -7,8 +7,8 @@ import ( "testing" ) -func TestParseInspectArgs_Defaults(t *testing.T) { - options, err := parseInspectArgs(nil, io.Discard) +func TestParseReplayArgs_Defaults(t *testing.T) { + options, err := parseReplayArgs(nil, io.Discard) if err != nil { t.Fatal(err) } @@ -17,8 +17,8 @@ func TestParseInspectArgs_Defaults(t *testing.T) { } } -func TestParseInspectArgs_AllFlags(t *testing.T) { - options, err := parseInspectArgs([]string{"--port", "9090", "--no-open", "--dev", "/tmp/runs"}, io.Discard) +func TestParseReplayArgs_AllFlags(t *testing.T) { + options, err := parseReplayArgs([]string{"--port", "9090", "--no-open", "--dev", "/tmp/runs"}, io.Discard) if err != nil { t.Fatal(err) } @@ -27,19 +27,19 @@ func TestParseInspectArgs_AllFlags(t *testing.T) { } } -func TestParseInspectArgs_RejectsTooManyPositional(t *testing.T) { - _, err := parseInspectArgs([]string{"a", "b"}, io.Discard) +func TestParseReplayArgs_RejectsTooManyPositional(t *testing.T) { + _, err := parseReplayArgs([]string{"a", "b"}, io.Discard) if err == nil || !strings.Contains(err.Error(), "at most one") { t.Fatalf("expected too-many-args error, got %v", err) } } -func TestRun_HelpListsInspectCommand(t *testing.T) { +func TestRun_HelpListsReplayCommand(t *testing.T) { var stdout bytes.Buffer if err := run([]string{"sanderling"}, &stdout, io.Discard); err != nil { t.Fatal(err) } - if !strings.Contains(stdout.String(), "inspect") { - t.Errorf("usage missing inspect command: %q", stdout.String()) + if !strings.Contains(stdout.String(), "replay") { + t.Errorf("usage missing replay command: %q", stdout.String()) } } diff --git a/docs/_assets/inspect-ui.png b/docs/_assets/replay-ui.png similarity index 100% rename from docs/_assets/inspect-ui.png rename to docs/_assets/replay-ui.png diff --git a/docs/_template/page.html b/docs/_template/page.html index 37fcc02..ea9ef96 100644 --- a/docs/_template/page.html +++ b/docs/_template/page.html @@ -36,7 +36,7 @@
  • Writing specs
  • Spec language reference
  • Runs
  • -
  • Inspect
  • +
  • Replay
  • CLI reference
  • Development

    diff --git a/docs/development/architecture.md b/docs/development/architecture.md index ec2b5e3..8bce8de 100644 --- a/docs/development/architecture.md +++ b/docs/development/architecture.md @@ -18,7 +18,7 @@ flowchart TB DC["Device / Emulator"] CH["Chrome (CDP)"] RD[("runs/")] - IN["sanderling inspect\nHTTP + SSE"] + IN["sanderling replay\nHTTP + SSE"] UI["Web UI (React)"] D -->|gRPC| SC @@ -45,9 +45,9 @@ flowchart TB On native, the transport split exists because only real UI events need to cross process and OS-API boundaries. Introspection is cheap, frequent, and lives on a fast local socket directly to the app. On web, CDP handles both. -## Inspect UI +## Replay UI -`sanderling inspect` is a separate mode of the same Go binary. It serves an embedded React bundle and reads `runs/` from disk, streaming file-watcher events over SSE so the UI updates as new steps land. It has no connection to any driver; it only consumes the trace artifacts. +`sanderling replay` is a separate mode of the same Go binary. It serves an embedded React bundle and reads `runs/` from disk, streaming file-watcher events over SSE so the UI updates as new steps land. It has no connection to any driver; it only consumes the trace artifacts. ## Per-step cycle diff --git a/docs/development/decisions.md b/docs/development/decisions.md index 5f9c3bb..8964126 100644 --- a/docs/development/decisions.md +++ b/docs/development/decisions.md @@ -10,9 +10,9 @@ Architectural and organizational decisions worth recording. Each entry states th ## Directory and Package Organization -### `web/` renamed to `inspect-ui/` +### `web/` renamed to `replay-ui/` -The directory containing the React/TypeScript frontend is `inspect-ui/`, not `web/`. The name `web/` was ambiguous (the project also has a web/Chrome driver target). `inspect-ui/` makes the purpose explicit: this is the UI for the `sanderling inspect` command. +The directory containing the React/TypeScript frontend is `replay-ui/`, not `web/`. The name `web/` was ambiguous (the project also has a web/Chrome driver target). `replay-ui/` makes the purpose explicit: this is the UI for the `sanderling replay` command. ### Keep `internal/` @@ -22,9 +22,9 @@ Go's `internal/` directory restriction prevents any code outside this module fro The `driver.go` file defines the `DeviceDriver` interface. Concrete implementations live in subdirectories: `sidecar/` (gRPC to the native sidecar), `chrome/` (CDP), `mock/` (tests). This pattern keeps the runner and verifier decoupled from any specific platform. -### `internal/verifier/marshal.go` moves to `internal/inspect/` +### `internal/verifier/marshal.go` moves to `internal/replay/` -`marshal.go` serializes LTL formulas to JSON for the inspect UI. That is an inspect concern, not a verifier concern. Verifier should not know inspect exists. +`marshal.go` serializes LTL formulas to JSON for the replay UI. That is a replay concern, not a verifier concern. Verifier should not know replay exists. ### `internal/verifier/bindings.go` splits into `types.go` + `bindings.go` @@ -44,7 +44,7 @@ Android device enumeration, AVD selection, and emulator boot logic moves to `int Driver setup, agent connection, verifier init, trace setup, and runner orchestration extract to `internal/testrun/`. `cmd/sanderling/` wires CLI flags to `testrun` calls and nothing more. -### `internal/inspect/runs.go` splits into multiple files +### `internal/replay/runs.go` splits into multiple files 429 LOC with mixed concerns (cache, file I/O, JSON decoding, summary types) splits into at least `runs_cache.go` and `runs_decode.go` within the same package. diff --git a/docs/index.md b/docs/index.md index 555c749..f55ed14 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,7 +12,7 @@ Alpha: Scope of v0.1.0 is tracked in [issue #4](https://github.com/priyanshujain - [Getting started](./manual/getting-started/) - [Writing specs](./manual/writing-specs/) - [Runs](./manual/runs/) -- [Inspect](./manual/inspect/) +- [Replay](./manual/replay/) - [CLI reference](./manual/cli/) --- diff --git a/docs/manual/cli.md b/docs/manual/cli.md index e44c55b..0faf506 100644 --- a/docs/manual/cli.md +++ b/docs/manual/cli.md @@ -25,7 +25,7 @@ Run a spec against an app for a fixed duration. | `--output` | `./runs` | Output directory for traces. | | `--clear-data` | `false` | Clear app data before launching so the run starts from a fresh install. | -## `sanderling inspect [run-or-runs-dir]` +## `sanderling replay [run-or-runs-dir]` Serve a local web UI for browsing traces. The positional argument is optional and may point at either a runs directory (the parent of many runs) or a single run directory (auto-detected by the presence of `meta.json`). Defaults to `./runs`. @@ -35,7 +35,7 @@ Serve a local web UI for browsing traces. The positional argument is optional an | `--no-open` | `false` | Skip opening the default browser on startup. | | `--dev` | `false` | Reverse-proxy non-API requests to the Vite dev server on `127.0.0.1:5173`. | -See [the inspect UI page](./inspect/) for the panel reference and keyboard shortcuts. +See [the replay UI page](./replay/) for the panel reference and keyboard shortcuts. ## `sanderling doctor` diff --git a/docs/manual/getting-started.md b/docs/manual/getting-started.md index d872fc2..b0fe8e4 100644 --- a/docs/manual/getting-started.md +++ b/docs/manual/getting-started.md @@ -92,6 +92,6 @@ runs/2026-04-18T12-34-56/ └── meta.json ``` -Browse it with `sanderling inspect` (see [inspect](./inspect/)), or read `trace.jsonl` step by step. +Browse it with `sanderling replay` (see [replay](./replay/)), or read `trace.jsonl` step by step. Next: [writing specs](./writing-specs/). diff --git a/docs/manual/inspect.md b/docs/manual/replay.md similarity index 83% rename from docs/manual/inspect.md rename to docs/manual/replay.md index 4767126..c34b298 100644 --- a/docs/manual/inspect.md +++ b/docs/manual/replay.md @@ -1,18 +1,18 @@ --- -title: sanderling inspect +title: sanderling replay --- -# sanderling inspect +# sanderling replay Local web UI for exploring runs produced by `sanderling test`. Reads `runs//meta.json` and `runs//trace.jsonl` from disk. ``` -sanderling inspect [run-or-runs-dir] [--port N] [--no-open] [--dev] +sanderling replay [run-or-runs-dir] [--port N] [--no-open] [--dev] ``` The positional argument can be a runs directory or a single run directory (auto-detected by `meta.json`). Defaults to `./runs`. -![sanderling inspect](../../_assets/inspect-ui.png) +![sanderling replay](../../_assets/replay-ui.png) ## Panels @@ -44,15 +44,15 @@ Arrow keys inside a tablist or listbox yield to those widgets. Use `j`/`k` when `/runs/:id/steps/:n` links to a specific step. Use it in issues or PRs when pointing at a violation. -The run index auto-refreshes over SSE as new runs land, so `sanderling inspect` and `sanderling test` can run side by side. +The run index auto-refreshes over SSE as new runs land, so `sanderling replay` and `sanderling test` can run side by side. ## Development Two-process loop while iterating on the UI: ``` -make web-dev # bun + vite on http://127.0.0.1:5173 -make inspect-dev # sanderling inspect --dev, proxies non-API to 5173 +make web-dev # bun + vite on http://127.0.0.1:5173 +make replay-dev # sanderling replay --dev, proxies non-API to 5173 ``` Single binary with the bundle embedded: diff --git a/internal/ltl/evaluator.go b/internal/ltl/evaluator.go index 01589b0..3f8fa07 100644 --- a/internal/ltl/evaluator.go +++ b/internal/ltl/evaluator.go @@ -265,7 +265,7 @@ func violated() reduceResult { return reduceResult{status: statusViolated} } // violatedWith reports a violation that originates at the given sub-formula // with the given reason. The reason distinguishes a thrown predicate from a -// plain false so callers (and the inspect UI) can render the cause. +// plain false so callers (and the replay UI) can render the cause. func violatedWith(formula Formula, reason string) reduceResult { return reduceResult{ status: statusViolated, diff --git a/internal/ltl/formula.go b/internal/ltl/formula.go index b60828c..c2653fb 100644 --- a/internal/ltl/formula.go +++ b/internal/ltl/formula.go @@ -23,7 +23,7 @@ type PredicateLabel interface { // ErrorFormula represents a thunk that threw during evaluation. The verifier // substitutes one of these into the residual when MarshalJSON would otherwise // have to encode an opaque thunk that already errored. It exists so that the -// inspect UI can render "predicate threw" inline. +// replay UI can render "predicate threw" inline. type ErrorFormula struct { Message string } diff --git a/internal/inspect/assets.go b/internal/replay/assets.go similarity index 58% rename from internal/inspect/assets.go rename to internal/replay/assets.go index 5442d2b..dbd32d5 100644 --- a/internal/inspect/assets.go +++ b/internal/replay/assets.go @@ -1,5 +1,5 @@ -// Package inspect serves the embedded web UI for browsing recorded runs. -package inspect +// Package replay serves the embedded web UI for browsing recorded runs. +package replay import ( "embed" @@ -11,11 +11,11 @@ var distFS embed.FS // Assets returns the embedded SPA bundle rooted at the dist directory. // In Stage 2 this contains a stub index.html. Stage 4 wires the real -// bundle in via Makefile (copy inspect-ui/dist -> internal/inspect/dist). +// bundle in via Makefile (copy replay-ui/dist -> internal/replay/dist). func Assets() fs.FS { sub, err := fs.Sub(distFS, "dist") if err != nil { - panic("inspect: dist embed missing: " + err.Error()) + panic("replay: dist embed missing: " + err.Error()) } return sub } diff --git a/internal/inspect/dev.go b/internal/replay/dev.go similarity index 96% rename from internal/inspect/dev.go rename to internal/replay/dev.go index 9d8b5ff..1b0c99d 100644 --- a/internal/inspect/dev.go +++ b/internal/replay/dev.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "net/http" diff --git a/inspect-ui/public/fonts/.gitkeep b/internal/replay/dist/.gitkeep similarity index 100% rename from inspect-ui/public/fonts/.gitkeep rename to internal/replay/dist/.gitkeep diff --git a/internal/inspect/runs.go b/internal/replay/runs.go similarity index 99% rename from internal/inspect/runs.go rename to internal/replay/runs.go index 91450a0..3414b5d 100644 --- a/internal/inspect/runs.go +++ b/internal/replay/runs.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "errors" diff --git a/internal/inspect/runs_cache.go b/internal/replay/runs_cache.go similarity index 99% rename from internal/inspect/runs_cache.go rename to internal/replay/runs_cache.go index 691dd9b..3cc87a5 100644 --- a/internal/inspect/runs_cache.go +++ b/internal/replay/runs_cache.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "bufio" diff --git a/internal/inspect/runs_decode.go b/internal/replay/runs_decode.go similarity index 99% rename from internal/inspect/runs_decode.go rename to internal/replay/runs_decode.go index 4b3e0de..553cffb 100644 --- a/internal/inspect/runs_decode.go +++ b/internal/replay/runs_decode.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "bufio" diff --git a/internal/inspect/runs_test.go b/internal/replay/runs_test.go similarity index 99% rename from internal/inspect/runs_test.go rename to internal/replay/runs_test.go index 62de640..c0ce1aa 100644 --- a/internal/inspect/runs_test.go +++ b/internal/replay/runs_test.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "encoding/json" diff --git a/internal/inspect/server.go b/internal/replay/server.go similarity index 99% rename from internal/inspect/server.go rename to internal/replay/server.go index 637720a..f06b9b1 100644 --- a/internal/inspect/server.go +++ b/internal/replay/server.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "encoding/json" @@ -22,7 +22,7 @@ type ServerOptions struct { AssetsFS fs.FS } -// Server holds the HTTP handlers for `sanderling inspect`. +// Server holds the HTTP handlers for `sanderling replay`. type Server struct { options ServerOptions cache *Cache diff --git a/internal/inspect/server_test.go b/internal/replay/server_test.go similarity index 99% rename from internal/inspect/server_test.go rename to internal/replay/server_test.go index d952f1c..d5e8647 100644 --- a/internal/inspect/server_test.go +++ b/internal/replay/server_test.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "context" diff --git a/internal/inspect/watcher.go b/internal/replay/watcher.go similarity index 99% rename from internal/inspect/watcher.go rename to internal/replay/watcher.go index 1e3c302..b7a8fdb 100644 --- a/internal/inspect/watcher.go +++ b/internal/replay/watcher.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "context" diff --git a/internal/inspect/watcher_test.go b/internal/replay/watcher_test.go similarity index 98% rename from internal/inspect/watcher_test.go rename to internal/replay/watcher_test.go index 570977f..237e195 100644 --- a/internal/inspect/watcher_test.go +++ b/internal/replay/watcher_test.go @@ -1,4 +1,4 @@ -package inspect +package replay import ( "testing" diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 25f8cc8..8b4b038 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -172,7 +172,7 @@ func Run(ctx context.Context, options Options) (Summary, error) { // one would poison the verifier's previous/current extractor // advance, so the next clean step would compare against this // transient state and emit false-positive violations. We still - // record the step (hierarchy + screenshot) for inspect-side + // record the step (hierarchy + screenshot) for replay-side // debugging, but skip the verifier entirely and pick the next // action against the unchanged prior state to keep the loop // progressing. diff --git a/internal/trace/writer.go b/internal/trace/writer.go index ffd6e7b..384a446 100644 --- a/internal/trace/writer.go +++ b/internal/trace/writer.go @@ -50,7 +50,7 @@ type Witness struct { // ExtractorChange records the prev/curr JSON values of an extractor whose // observation differed between two consecutive steps. Surfaced under -// violation rows in the inspect UI as a "what changed at this step" +// violation rows in the replay UI as a "what changed at this step" // breadcrumb. type ExtractorChange struct { Prev json.RawMessage `json:"prev"` diff --git a/internal/verifier/types.go b/internal/verifier/types.go index a69aaa6..5b35eb7 100644 --- a/internal/verifier/types.go +++ b/internal/verifier/types.go @@ -53,7 +53,7 @@ type Exception struct { // ExtractorChange records a single extractor's value transition across one // step. Used to surface "what changed at this step" breadcrumbs at violation -// markers in the inspect UI. +// markers in the replay UI. type ExtractorChange struct { Prev []byte Curr []byte diff --git a/internal/verifier/worker.go b/internal/verifier/worker.go index 20c7465..24bfebd 100644 --- a/internal/verifier/worker.go +++ b/internal/verifier/worker.go @@ -321,7 +321,7 @@ func encodeExtractorValue(value goja.Value) []byte { // ChangedExtractors returns the named extractors whose value changed between // the prior PushSnapshot and the current one. The map is keyed by extractor -// name; unnamed extractors (extractor_N fallback) are included so the inspect +// name; unnamed extractors (extractor_N fallback) are included so the replay // UI can still display them under a numeric label. The very first snapshot // emits every non-null extractor as a change (Prev=null, Curr=current) since // the runner can otherwise misread "no diff yet" as "nothing initialized". @@ -525,7 +525,7 @@ func (v *Verifier) NewlyViolatedProperties() []string { // Residuals returns the residual formula for each registered property after // the most recent EvaluateProperties call. Properties whose violation was // caused by a thrown predicate surface as ErrorFormula, sourced from the -// captured witness, so the inspect UI can render "predicate threw" inline. +// captured witness, so the replay UI can render "predicate threw" inline. func (v *Verifier) Residuals() map[string]ltl.Formula { residuals := map[string]ltl.Formula{} for name, evaluator := range v.evaluators { diff --git a/inspect-ui/bun.lock b/replay-ui/bun.lock similarity index 100% rename from inspect-ui/bun.lock rename to replay-ui/bun.lock diff --git a/inspect-ui/index.html b/replay-ui/index.html similarity index 92% rename from inspect-ui/index.html rename to replay-ui/index.html index 8fa93f0..962237a 100644 --- a/inspect-ui/index.html +++ b/replay-ui/index.html @@ -3,7 +3,7 @@ - sanderling inspect + sanderling replay diff --git a/inspect-ui/package.json b/replay-ui/package.json similarity index 92% rename from inspect-ui/package.json rename to replay-ui/package.json index 04a266b..b09867a 100644 --- a/inspect-ui/package.json +++ b/replay-ui/package.json @@ -1,5 +1,5 @@ { - "name": "@sanderling/inspect-web", + "name": "@sanderling/replay-web", "private": true, "version": "0.0.0", "type": "module", diff --git a/internal/inspect/dist/.gitkeep b/replay-ui/public/fonts/.gitkeep similarity index 100% rename from internal/inspect/dist/.gitkeep rename to replay-ui/public/fonts/.gitkeep diff --git a/inspect-ui/src/App.tsx b/replay-ui/src/App.tsx similarity index 100% rename from inspect-ui/src/App.tsx rename to replay-ui/src/App.tsx diff --git a/inspect-ui/src/__tests__/api.test.ts b/replay-ui/src/__tests__/api.test.ts similarity index 100% rename from inspect-ui/src/__tests__/api.test.ts rename to replay-ui/src/__tests__/api.test.ts diff --git a/inspect-ui/src/api.ts b/replay-ui/src/api.ts similarity index 100% rename from inspect-ui/src/api.ts rename to replay-ui/src/api.ts diff --git a/inspect-ui/src/components/ResidualNode.css b/replay-ui/src/components/ResidualNode.css similarity index 100% rename from inspect-ui/src/components/ResidualNode.css rename to replay-ui/src/components/ResidualNode.css diff --git a/inspect-ui/src/components/ResidualNode.tsx b/replay-ui/src/components/ResidualNode.tsx similarity index 100% rename from inspect-ui/src/components/ResidualNode.tsx rename to replay-ui/src/components/ResidualNode.tsx diff --git a/inspect-ui/src/components/Tabs.css b/replay-ui/src/components/Tabs.css similarity index 100% rename from inspect-ui/src/components/Tabs.css rename to replay-ui/src/components/Tabs.css diff --git a/inspect-ui/src/components/Tabs.tsx b/replay-ui/src/components/Tabs.tsx similarity index 100% rename from inspect-ui/src/components/Tabs.tsx rename to replay-ui/src/components/Tabs.tsx diff --git a/inspect-ui/src/hooks/useKeyboardNav.ts b/replay-ui/src/hooks/useKeyboardNav.ts similarity index 100% rename from inspect-ui/src/hooks/useKeyboardNav.ts rename to replay-ui/src/hooks/useKeyboardNav.ts diff --git a/inspect-ui/src/hooks/useSse.ts b/replay-ui/src/hooks/useSse.ts similarity index 100% rename from inspect-ui/src/hooks/useSse.ts rename to replay-ui/src/hooks/useSse.ts diff --git a/inspect-ui/src/hooks/useStep.ts b/replay-ui/src/hooks/useStep.ts similarity index 100% rename from inspect-ui/src/hooks/useStep.ts rename to replay-ui/src/hooks/useStep.ts diff --git a/inspect-ui/src/hooks/useTheme.ts b/replay-ui/src/hooks/useTheme.ts similarity index 95% rename from inspect-ui/src/hooks/useTheme.ts rename to replay-ui/src/hooks/useTheme.ts index aab0d27..9471c6b 100644 --- a/inspect-ui/src/hooks/useTheme.ts +++ b/replay-ui/src/hooks/useTheme.ts @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; export type ThemeMode = "light" | "dark"; -const STORAGE_KEY = "sanderling-inspect-theme"; +const STORAGE_KEY = "sanderling-replay-theme"; function detectInitial(): ThemeMode { if (typeof window === "undefined") { diff --git a/inspect-ui/src/main.tsx b/replay-ui/src/main.tsx similarity index 100% rename from inspect-ui/src/main.tsx rename to replay-ui/src/main.tsx diff --git a/inspect-ui/src/panels/ActionList.css b/replay-ui/src/panels/ActionList.css similarity index 100% rename from inspect-ui/src/panels/ActionList.css rename to replay-ui/src/panels/ActionList.css diff --git a/inspect-ui/src/panels/ActionList.tsx b/replay-ui/src/panels/ActionList.tsx similarity index 100% rename from inspect-ui/src/panels/ActionList.tsx rename to replay-ui/src/panels/ActionList.tsx diff --git a/inspect-ui/src/panels/ExceptionsPanel.css b/replay-ui/src/panels/ExceptionsPanel.css similarity index 100% rename from inspect-ui/src/panels/ExceptionsPanel.css rename to replay-ui/src/panels/ExceptionsPanel.css diff --git a/inspect-ui/src/panels/ExceptionsPanel.tsx b/replay-ui/src/panels/ExceptionsPanel.tsx similarity index 100% rename from inspect-ui/src/panels/ExceptionsPanel.tsx rename to replay-ui/src/panels/ExceptionsPanel.tsx diff --git a/inspect-ui/src/panels/HierarchyPanel.css b/replay-ui/src/panels/HierarchyPanel.css similarity index 100% rename from inspect-ui/src/panels/HierarchyPanel.css rename to replay-ui/src/panels/HierarchyPanel.css diff --git a/inspect-ui/src/panels/HierarchyPanel.tsx b/replay-ui/src/panels/HierarchyPanel.tsx similarity index 100% rename from inspect-ui/src/panels/HierarchyPanel.tsx rename to replay-ui/src/panels/HierarchyPanel.tsx diff --git a/inspect-ui/src/panels/MetricsChart.css b/replay-ui/src/panels/MetricsChart.css similarity index 100% rename from inspect-ui/src/panels/MetricsChart.css rename to replay-ui/src/panels/MetricsChart.css diff --git a/inspect-ui/src/panels/MetricsChart.tsx b/replay-ui/src/panels/MetricsChart.tsx similarity index 100% rename from inspect-ui/src/panels/MetricsChart.tsx rename to replay-ui/src/panels/MetricsChart.tsx diff --git a/inspect-ui/src/panels/Screenshot.css b/replay-ui/src/panels/Screenshot.css similarity index 100% rename from inspect-ui/src/panels/Screenshot.css rename to replay-ui/src/panels/Screenshot.css diff --git a/inspect-ui/src/panels/Screenshot.tsx b/replay-ui/src/panels/Screenshot.tsx similarity index 100% rename from inspect-ui/src/panels/Screenshot.tsx rename to replay-ui/src/panels/Screenshot.tsx diff --git a/inspect-ui/src/panels/SnapshotTable.css b/replay-ui/src/panels/SnapshotTable.css similarity index 100% rename from inspect-ui/src/panels/SnapshotTable.css rename to replay-ui/src/panels/SnapshotTable.css diff --git a/inspect-ui/src/panels/SnapshotTable.tsx b/replay-ui/src/panels/SnapshotTable.tsx similarity index 100% rename from inspect-ui/src/panels/SnapshotTable.tsx rename to replay-ui/src/panels/SnapshotTable.tsx diff --git a/inspect-ui/src/panels/Timeline.css b/replay-ui/src/panels/Timeline.css similarity index 100% rename from inspect-ui/src/panels/Timeline.css rename to replay-ui/src/panels/Timeline.css diff --git a/inspect-ui/src/panels/Timeline.tsx b/replay-ui/src/panels/Timeline.tsx similarity index 100% rename from inspect-ui/src/panels/Timeline.tsx rename to replay-ui/src/panels/Timeline.tsx diff --git a/inspect-ui/src/panels/ViolationsPanel.css b/replay-ui/src/panels/ViolationsPanel.css similarity index 100% rename from inspect-ui/src/panels/ViolationsPanel.css rename to replay-ui/src/panels/ViolationsPanel.css diff --git a/inspect-ui/src/panels/ViolationsPanel.tsx b/replay-ui/src/panels/ViolationsPanel.tsx similarity index 100% rename from inspect-ui/src/panels/ViolationsPanel.tsx rename to replay-ui/src/panels/ViolationsPanel.tsx diff --git a/inspect-ui/src/routes/RunDetail.tsx b/replay-ui/src/routes/RunDetail.tsx similarity index 98% rename from inspect-ui/src/routes/RunDetail.tsx rename to replay-ui/src/routes/RunDetail.tsx index 4028ee8..8063816 100644 --- a/inspect-ui/src/routes/RunDetail.tsx +++ b/replay-ui/src/routes/RunDetail.tsx @@ -15,6 +15,11 @@ import { useStep } from "../hooks/useStep"; import { useKeyboardNav } from "../hooks/useKeyboardNav"; import { useTheme } from "../hooks/useTheme"; +function basename(specPath: string): string { + const index = specPath.lastIndexOf("/"); + return index >= 0 ? specPath.slice(index + 1) : specPath; +} + interface RunHistory { names: string[]; lanes: PropertyLane[]; @@ -242,7 +247,7 @@ export default function RunDetail() { runs {run.id} - {run.spec_path} seed={run.seed} + {basename(run.spec_path)} seed={run.seed} step {stepIndex} / {stepCount ?? 0} diff --git a/inspect-ui/src/routes/RunList.tsx b/replay-ui/src/routes/RunList.tsx similarity index 92% rename from inspect-ui/src/routes/RunList.tsx rename to replay-ui/src/routes/RunList.tsx index 4b7e2d7..57f5670 100644 --- a/inspect-ui/src/routes/RunList.tsx +++ b/replay-ui/src/routes/RunList.tsx @@ -28,6 +28,11 @@ function formatStartedAt(value: string): string { return date.toLocaleString(); } +function basename(specPath: string): string { + const index = specPath.lastIndexOf("/"); + return index >= 0 ? specPath.slice(index + 1) : specPath; +} + export default function RunList() { const [runs, setRuns] = useState(null); const [error, setError] = useState(null); @@ -76,7 +81,7 @@ export default function RunList() { {formatStartedAt(run.started_at)} - {run.spec_path} + {basename(run.spec_path)} {run.seed} {run.platform} {formatDuration(run.duration_millis)} diff --git a/inspect-ui/src/styles/app.css b/replay-ui/src/styles/app.css similarity index 100% rename from inspect-ui/src/styles/app.css rename to replay-ui/src/styles/app.css diff --git a/inspect-ui/src/styles/tokens.css b/replay-ui/src/styles/tokens.css similarity index 100% rename from inspect-ui/src/styles/tokens.css rename to replay-ui/src/styles/tokens.css diff --git a/inspect-ui/src/styles/typography.css b/replay-ui/src/styles/typography.css similarity index 100% rename from inspect-ui/src/styles/typography.css rename to replay-ui/src/styles/typography.css diff --git a/inspect-ui/src/types.ts b/replay-ui/src/types.ts similarity index 100% rename from inspect-ui/src/types.ts rename to replay-ui/src/types.ts diff --git a/inspect-ui/tsconfig.json b/replay-ui/tsconfig.json similarity index 100% rename from inspect-ui/tsconfig.json rename to replay-ui/tsconfig.json diff --git a/inspect-ui/vite.config.ts b/replay-ui/vite.config.ts similarity index 100% rename from inspect-ui/vite.config.ts rename to replay-ui/vite.config.ts