This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
[alias]
|
||||||
|
xtest = "nextest run --workspace --all-features"
|
||||||
|
lint = "clippy --workspace --all-targets --all-features -- -D warnings"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[profile.default]
|
||||||
|
fail-fast = false
|
||||||
|
failure-output = "immediate-final"
|
||||||
|
slow-timeout = { period = "30s", terminate-after = 2 }
|
||||||
|
[profile.ci]
|
||||||
|
fail-fast = false
|
||||||
|
retries = 0
|
||||||
|
status-level = "pass"
|
||||||
|
final-status-level = "slow"
|
||||||
|
slow-timeout = { period = "30s", terminate-after = 2 }
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
rust:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install pinned Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: 1.94.1
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Format
|
||||||
|
run: cargo fmt --all --check
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: cargo test --workspace --all-features
|
||||||
@@ -37,8 +37,9 @@ workspace's `Research/` directory. They are references, not vendored code.
|
|||||||
Before committing Rust changes, run:
|
Before committing Rust changes, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo fmt --all --check
|
./scripts/ci.sh
|
||||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
||||||
cargo test --workspace --all-features
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Keep `bacon` running during development. Tests must use synthetic fixtures; real
|
||||||
|
agent transcripts, subscription state, private source, and credentials are never
|
||||||
|
test data.
|
||||||
|
|||||||
@@ -37,11 +37,17 @@ contracts before committing to a large implementation.
|
|||||||
|
|
||||||
Start with [the product spec](docs/PRODUCT_SPEC.md),
|
Start with [the product spec](docs/PRODUCT_SPEC.md),
|
||||||
[architecture](docs/ARCHITECTURE.md), [research map](docs/RESEARCH.md), and
|
[architecture](docs/ARCHITECTURE.md), [research map](docs/RESEARCH.md), and
|
||||||
[captured upstream revisions](docs/RESEARCH_SNAPSHOTS.md).
|
[captured upstream revisions](docs/RESEARCH_SNAPSHOTS.md). The native UI choice
|
||||||
|
is intentionally open; see [the measured decision plan](docs/UI_OPTIONS.md).
|
||||||
|
|
||||||
## Scaffold
|
## Scaffold
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo test --workspace
|
bacon # continuous check; t tests, c lints, v runs the full gate
|
||||||
|
cargo xtest # fast isolated tests with nextest
|
||||||
|
./scripts/ci.sh # format + strict Clippy + tests + doctests
|
||||||
cargo run -p lumbridge
|
cargo run -p lumbridge
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See [the testing strategy](docs/TESTING.md) for fake harnesses, ACP replay,
|
||||||
|
terminal conformance, UI driving, recovery, performance, and packaging tests.
|
||||||
|
|||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#:schema https://dystroy.org/bacon/.bacon.schema.json
|
||||||
|
|
||||||
|
default_job = "check"
|
||||||
|
env.CARGO_TERM_COLOR = "always"
|
||||||
|
|
||||||
|
[jobs.check]
|
||||||
|
command = ["cargo", "check", "--workspace", "--all-targets", "--all-features"]
|
||||||
|
need_stdout = false
|
||||||
|
|
||||||
|
[jobs.clippy]
|
||||||
|
command = [
|
||||||
|
"cargo", "clippy", "--workspace", "--all-targets", "--all-features",
|
||||||
|
"--", "-D", "warnings",
|
||||||
|
]
|
||||||
|
need_stdout = false
|
||||||
|
|
||||||
|
[jobs.test]
|
||||||
|
command = [
|
||||||
|
"cargo", "nextest", "run", "--workspace", "--all-features",
|
||||||
|
"--hide-progress-bar", "--failure-output", "final",
|
||||||
|
]
|
||||||
|
need_stdout = true
|
||||||
|
analyzer = "nextest"
|
||||||
|
|
||||||
|
[jobs.doc-test]
|
||||||
|
command = ["cargo", "test", "--workspace", "--all-features", "--doc"]
|
||||||
|
need_stdout = true
|
||||||
|
|
||||||
|
[jobs.run]
|
||||||
|
command = ["cargo", "run", "-p", "lumbridge"]
|
||||||
|
need_stdout = true
|
||||||
|
allow_warnings = false
|
||||||
|
background = true
|
||||||
|
show_command_error_code = true
|
||||||
|
|
||||||
|
[jobs.ci]
|
||||||
|
command = ["./scripts/ci.sh"]
|
||||||
|
need_stdout = true
|
||||||
|
|
||||||
|
[keybindings]
|
||||||
|
c = "job:clippy"
|
||||||
|
t = "job:test"
|
||||||
|
d = "job:doc-test"
|
||||||
|
r = "job:run"
|
||||||
|
v = "job:ci"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use lumbridge_core::{Platform, ProductStatus, UsageProvenance};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn downstream_crates_can_use_the_public_scaffold_contract() {
|
||||||
|
let status = ProductStatus::architecture_phase(Platform::ArchLinux);
|
||||||
|
|
||||||
|
assert_eq!(status.platform.to_string(), "Arch Linux / Omarchy");
|
||||||
|
assert!(status.message.contains("Architecture scaffold"));
|
||||||
|
assert_eq!(UsageProvenance::Estimated, UsageProvenance::Estimated);
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
# Testing strategy
|
||||||
|
|
||||||
|
Lumbridge controls shells, repositories, credentials, agents, and long-lived
|
||||||
|
processes. A test plan built only from UI clicks would be slow, flaky, and blind
|
||||||
|
to the failures that matter. The product is designed with programmatic testing
|
||||||
|
surfaces from the start.
|
||||||
|
|
||||||
|
## The central seam
|
||||||
|
|
||||||
|
The desktop UI and the test driver use the same versioned local IPC commands and
|
||||||
|
events exposed by the session runtime. UI tests can therefore:
|
||||||
|
|
||||||
|
1. start an isolated runtime with a temporary data directory;
|
||||||
|
2. issue real commands such as create workspace, split pane, launch harness,
|
||||||
|
resize PTY, approve tool, cancel turn, and restore session;
|
||||||
|
3. wait on semantic events rather than sleeps;
|
||||||
|
4. query a redacted state snapshot; and
|
||||||
|
5. separately confirm the visible/accessibility representation where needed.
|
||||||
|
|
||||||
|
The test API is not a back door. It uses the same validation and state machine as
|
||||||
|
the UI, binds locally, requires a per-run capability token, and is absent from
|
||||||
|
release builds unless explicitly enabled.
|
||||||
|
|
||||||
|
## Test layers
|
||||||
|
|
||||||
|
### Pure and property tests
|
||||||
|
|
||||||
|
Layouts, terminal grid transitions, usage windows, forecasts, event reduction,
|
||||||
|
path rules, and capability negotiation are deterministic functions. Test them
|
||||||
|
exhaustively without starting a window. Property tests should target split-tree
|
||||||
|
invariants, event replay, Unicode width, and usage aggregation.
|
||||||
|
|
||||||
|
### Contract tests
|
||||||
|
|
||||||
|
Every platform adapter implements the same suites for PTYs, process groups,
|
||||||
|
signals, resize, secret handles, notifications, paths, and atomic replacement.
|
||||||
|
Every harness adapter implements discovery, launch, resume, cancel, status, and
|
||||||
|
usage contracts. Unsupported capability is a valid explicit result.
|
||||||
|
|
||||||
|
### Fake harnesses
|
||||||
|
|
||||||
|
Small Rust fixture binaries behave like coding agents without network access or
|
||||||
|
subscriptions. Scripts cover partial frames, noisy stderr, permission prompts,
|
||||||
|
child processes, crashes, hangs, huge output, invalid bytes, and cancellation.
|
||||||
|
Tests assert both user-visible state and cleanup of the entire process tree.
|
||||||
|
|
||||||
|
### ACP replay
|
||||||
|
|
||||||
|
Synthetic ACP transcripts are replayed in both directions against the official
|
||||||
|
Rust SDK. Golden fixtures cover protocol versions and capability combinations.
|
||||||
|
Fuzzing targets frame decoding and state transitions; stdout must remain protocol
|
||||||
|
pure and diagnostics must stay on stderr.
|
||||||
|
|
||||||
|
### Terminal conformance
|
||||||
|
|
||||||
|
Byte-stream fixtures assert screen cells, styles, cursor, alternate screen,
|
||||||
|
scrollback, selection, hyperlinks, bracketed paste, keyboard modes, and Unicode.
|
||||||
|
PTY integration tests exercise real shells on each supported OS. Human typing
|
||||||
|
and agent automation are stressed concurrently to catch input-order corruption.
|
||||||
|
|
||||||
|
### Persistence and recovery
|
||||||
|
|
||||||
|
The runtime is interrupted after each durable event and external mutation, then
|
||||||
|
restarted. Tests prove accepted commands are not lost, incomplete work is
|
||||||
|
reconciled, migrations are forward-only, and corrupt/truncated tails fail safely.
|
||||||
|
|
||||||
|
### UI and rendering
|
||||||
|
|
||||||
|
Component tests drive semantic actions and accessibility identifiers. Golden
|
||||||
|
images cover a small set of high-value layouts at fixed fonts, scale, theme, and
|
||||||
|
GPU/software renderer. Snapshot updates require review; snapshots never replace
|
||||||
|
state assertions.
|
||||||
|
|
||||||
|
### Performance gates
|
||||||
|
|
||||||
|
Criterion and end-to-end probes record input-to-present latency, output ingest,
|
||||||
|
scrollback search, six-pane frame time, idle CPU, memory per pane, startup, and
|
||||||
|
restore. CI uses generous regression ceilings; dedicated metal/macOS runs retain
|
||||||
|
the detailed distributions.
|
||||||
|
|
||||||
|
### Packaging smoke tests
|
||||||
|
|
||||||
|
Fresh macOS, Ubuntu, and Omarchy/Arch environments install, launch, open a shell,
|
||||||
|
upgrade, roll back, and uninstall. Artifacts are checked for signatures,
|
||||||
|
checksums, SBOM, license notices, forbidden secrets, and source revision.
|
||||||
|
|
||||||
|
## Developer loop
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Continuous cargo check. Press t for nextest, c for strict Clippy, v for all.
|
||||||
|
bacon
|
||||||
|
|
||||||
|
# Direct fast test run.
|
||||||
|
cargo xtest
|
||||||
|
|
||||||
|
# Exactly what must pass before a commit.
|
||||||
|
./scripts/ci.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`cargo-watch` is no longer the project default because upstream archived it in
|
||||||
|
2025. `scripts/watch.sh` uses Bacon and retains a cargo-watch fallback for people
|
||||||
|
who already have the final cargo-watch release installed.
|
||||||
|
|
||||||
|
## CI matrix as the project grows
|
||||||
|
|
||||||
|
Every change runs format, Clippy, unit, contract, integration, and doctests on
|
||||||
|
Linux. Pull requests that touch platform/UI code also run macOS. Nightly jobs add
|
||||||
|
MSRV, coverage, dependency/license audit, fuzz smoke, renderer snapshots, soak,
|
||||||
|
and performance tracking. Release candidates must pass native packaging smoke on
|
||||||
|
macOS, Ubuntu, and Arch/Omarchy rather than treating cross-compilation as proof.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Native UI decision
|
||||||
|
|
||||||
|
Lumbridge will not use Electron, React, TypeScript, or a webview as its
|
||||||
|
application shell. The shell, layout engine, terminal, session runtime, and
|
||||||
|
editor surfaces must be native Rust. An isolated browser pane may host the
|
||||||
|
operating system web engine because rendering arbitrary web pages is a browser
|
||||||
|
problem, not an application-shell architecture.
|
||||||
|
|
||||||
|
This decision stays open until the finalists run the same workload. Choosing on
|
||||||
|
repository popularity or a polished demo would hide the risks that matter for a
|
||||||
|
terminal-heavy, accessibility-aware, cross-platform IDE.
|
||||||
|
|
||||||
|
## Finalists
|
||||||
|
|
||||||
|
### GPUI
|
||||||
|
|
||||||
|
GPUI is the closest architectural match to Zed: retained state, GPU rendering,
|
||||||
|
text-heavy native interfaces, and an Apache-2.0 framework crate. It is the
|
||||||
|
highest-upside choice if Lumbridge wants Zed-like responsiveness and is willing
|
||||||
|
to track a fast-moving framework.
|
||||||
|
|
||||||
|
Risks:
|
||||||
|
|
||||||
|
- it is pre-1.0 and tightly shaped by Zed's needs;
|
||||||
|
- framework documentation and third-party component coverage are still young;
|
||||||
|
- the complete dependency and license closure must be audited before adoption;
|
||||||
|
- Zed's editor, terminal, and Markdown application crates are GPL-3.0-or-later,
|
||||||
|
so Lumbridge cannot copy those implementations into an Apache-2.0 release.
|
||||||
|
|
||||||
|
### Floem
|
||||||
|
|
||||||
|
Floem is the strongest independent comparator. It is MIT-licensed, pure Rust,
|
||||||
|
fine-grained and reactive, renders through wgpu/Vello or Skia, and is proven in
|
||||||
|
the Lapce editor. Its editor primitives may shorten the path to a native
|
||||||
|
Markdown/code surface without binding Lumbridge to Zed's application code.
|
||||||
|
|
||||||
|
Risks:
|
||||||
|
|
||||||
|
- it is also pre-1.0 and has a smaller ecosystem;
|
||||||
|
- current releases carry custom windowing integration that needs maintenance
|
||||||
|
review;
|
||||||
|
- accessibility, IME, embedded-browser parenting, and multi-window behavior
|
||||||
|
still need validation on every target desktop.
|
||||||
|
|
||||||
|
## Viable fallback
|
||||||
|
|
||||||
|
Iced is MIT-licensed, cross-platform, and renderer-agnostic with a wgpu path. It
|
||||||
|
has approachable architecture and broad examples, but its own documentation
|
||||||
|
still calls it experimental. It is a sound fallback if GPUI and Floem fail the
|
||||||
|
spike, though Lumbridge would build more IDE/editor infrastructure itself.
|
||||||
|
|
||||||
|
## Useful building blocks, not the shell decision
|
||||||
|
|
||||||
|
- `winit + wgpu + cosmic-text` gives maximum renderer control and is a sensible
|
||||||
|
direction for a dedicated terminal canvas. Owning an entire desktop toolkit,
|
||||||
|
editor, IME, accessibility layer, menus, drag-and-drop, and window integration
|
||||||
|
in the first release would be too much product risk.
|
||||||
|
- `egui` is excellent for internal diagnostics and rapid prototypes. Its
|
||||||
|
immediate-mode model and non-native visual conventions make it a weaker main
|
||||||
|
IDE shell.
|
||||||
|
- `wry` can host a tightly isolated system-web-engine child for browser panes:
|
||||||
|
WKWebView on macOS and WebKitGTK on Linux. It must not become a web frontend or
|
||||||
|
a privileged bridge into the session runtime.
|
||||||
|
- `AccessKit` should provide the semantic accessibility tree regardless of the
|
||||||
|
rendering framework.
|
||||||
|
|
||||||
|
The Markdown experience remains native: a rope-backed editor, incremental
|
||||||
|
parsing and syntax trees, and a Rust Markdown renderer. Preview links and
|
||||||
|
embedded web content cross the browser boundary through a narrow, capability-
|
||||||
|
checked interface.
|
||||||
|
|
||||||
|
## The decision spike
|
||||||
|
|
||||||
|
Build the same disposable shell in GPUI and Floem before product implementation:
|
||||||
|
|
||||||
|
- workspace sidebar, tab strip, split tree, command palette, footer, and six
|
||||||
|
fake busy terminal panes;
|
||||||
|
- native Markdown edit and preview surface;
|
||||||
|
- browser placeholder followed by one isolated system-web-engine child;
|
||||||
|
- semantic test identifiers, keyboard-only navigation, accessibility tree, IME,
|
||||||
|
copy/paste, drag-and-drop, and window restore;
|
||||||
|
- package and launch on macOS, Ubuntu, and Omarchy/Arch.
|
||||||
|
|
||||||
|
Record, do not estimate:
|
||||||
|
|
||||||
|
- cold and warm startup;
|
||||||
|
- idle RSS and RSS with six panes;
|
||||||
|
- key-to-present p50/p95 and output-to-present latency;
|
||||||
|
- frame time while all panes stream output;
|
||||||
|
- binary and installed size;
|
||||||
|
- accessibility/IME correctness and native window behavior;
|
||||||
|
- build/package friction and the complete dependency/license closure.
|
||||||
|
|
||||||
|
Choose the framework whose measured result gives Lumbridge the best input and
|
||||||
|
streaming latency without failing accessibility, packaging, or maintainability.
|
||||||
|
If the results are close, prefer the smaller operational and licensing risk.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "1.94.1"
|
||||||
|
components = ["clippy", "rustfmt"]
|
||||||
|
profile = "minimal"
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
cargo fmt --all --check
|
||||||
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
|
if command -v cargo-nextest >/dev/null 2>&1; then
|
||||||
|
cargo nextest run --workspace --all-features --profile "${NEXTEST_PROFILE:-default}"
|
||||||
|
else
|
||||||
|
echo "cargo-nextest not installed; using cargo test" >&2
|
||||||
|
cargo test --workspace --all-features
|
||||||
|
fi
|
||||||
|
|
||||||
|
# nextest deliberately does not run doctests on stable Rust.
|
||||||
|
cargo test --workspace --all-features --doc
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if command -v bacon >/dev/null 2>&1; then
|
||||||
|
exec bacon "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compatibility for developers who still have the now-dormant cargo-watch.
|
||||||
|
if command -v cargo-watch >/dev/null 2>&1; then
|
||||||
|
exec cargo watch -x "check --workspace --all-targets --all-features" \
|
||||||
|
-x "test --workspace --all-features"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Install Bacon with: cargo install --locked bacon" >&2
|
||||||
|
exit 127
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Deterministic fixtures
|
||||||
|
|
||||||
|
Fixtures in this directory are synthetic and safe to publish. They must never be
|
||||||
|
copied from real subscription transcripts, private repositories, shell history,
|
||||||
|
or credentials.
|
||||||
|
|
||||||
|
Planned fixture families:
|
||||||
|
|
||||||
|
- `harness/`: scripted child processes covering stdout, stderr, exit, signals,
|
||||||
|
prompts, long lines, invalid UTF-8, backpressure, and process-tree cleanup.
|
||||||
|
- `acp/`: versioned initialize/session/prompt/cancel transcripts and capability
|
||||||
|
combinations, including malformed and out-of-order frames.
|
||||||
|
- `terminal/`: compact VT byte streams with expected screen and scrollback state.
|
||||||
|
- `usage/`: provider-, harness-, measured-, and estimated-usage observations.
|
||||||
|
- `recovery/`: event logs ending at every externally visible interruption point.
|
||||||
|
|
||||||
|
Large generated corpora belong in release artifacts or a dedicated test-data
|
||||||
|
repository, not in normal Git history.
|
||||||
Reference in New Issue
Block a user