Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Vixen development mode

This document defines dev for this repo: how to move quickly during alpha without creating long-term maintenance debt.

Project focus is defined in PROJECT_DIRECTION.md. Autonomous commit/push policy is defined in AUTONOMOUS_WORK.md. Git lifecycle gates are enforced by hk via the checked-in ../hk.pkl.

Definitions

  • Dev / alpha means partial browser capability is allowed when it is executable, tested, fail-closed, and honestly documented. Alpha work may be incomplete; it must not be vague, hidden, or unbounded.
  • A slice is the smallest reviewable unit that makes one browser-visible seam better: usually one Page/headless/CDP/WPT fixture path plus the pure engine code it consumes.
  • A tock is a cleanup-only follow-up after capability work: delete dead shims, split modules nearing 1 kLOC, move duplicated parsing to one helper, tighten docs, and retire stale fixtures.
  • Release mode is stricter than dev mode and is governed by ACCEPTANCE.md. Do not use this document to lower release gates.

Alpha development contract

Every alpha slice should satisfy these rules:

  1. Visible seam first. Prefer code that reaches the engine-owned browser/ context/document path, vixen-headless, CDP, or a committed WPT/fixture check. A Page slice must preserve BrowserCore ownership and name the live document seam it advances. Pure prep is fine only when the next visible seam is named.
  2. One trust boundary at a time. For security-sensitive paths, name the boundary, validate near it, fail closed, and surface stable error codes.
  3. Reuse pure modules without duplicating ownership. JS host objects, Page projections, CLI, and CDP should call the same Rust implementation, but only the browser core decides lifecycle, commit, cancellation, and persistence.
  4. Partial APIs must be explicit. A subset may ship in alpha if unsupported inputs fail closed and the supported behavior is documented in COMPAT.md. Interface shape without a backing subsystem must be labeled shape-only.
  5. No silent architecture drift. New dependencies, crate edges, rendering paths, process boundaries, or storage/network policy changes must be backed by an ADR/update in DECISIONS.md or an explicit plan note.
  6. Tests travel with behavior. Unit tests prove pure logic; one integration check proves the user-visible seam. If a fixture manifest assertion is the seam, keep it committed.
  7. Flutter is the renderer, not the browser owner. Dart owns bounded formatting/Paragraph/Canvas state, atomic renderer commits, chrome, Semantics presentation, and host-service UI. BrowserCore owns DOM/runtime/navigation, computed styles, policy/persistence, web-event semantics, accepted resources, and accessibility meaning. Bridge payloads, queues, commits, queries, and handles are bounded with explicit revision/lifetime tests.

Gate tiers

Use the cheapest gate that matches the risk, then escalate before review or push.

TierUse whenCommand shape
Inner loopEditing one crate/modulecargo check -p <crate> plus focused cargo test ... <name>
Pre-commitA commit is being madehk pre-commit: cargo fmt, merge-conflict/private-key scan, staged diff whitespace check
Alpha sliceA coherent partial capability is readyfocused tests + relevant just gate-phaseN
Pre-pushWork is ready to leave the machinehk pre-push: just gate-push
ReleaseVersioned release readinessevery gate in ACCEPTANCE.md

just gate-push is the long integration gate. Keep long gates out of the inner loop and pre-commit path so iteration stays fast.

Current pre-push composition:

just gate-alpha
just gate-phase6
just gate-smoke
git diff --check
git diff --cached --check

Adjust just gate-push as the alpha architecture changes; hk should keep calling that single recipe.

GUI shell environment blockers

Ubuntu 24.04 is the CI and release baseline; a Distrobox is not required. On a host with the native Linux packages listed in guidance/mise.md, run the shell recipes directly. Debian, Fedora, and Ubuntu 26.04 runs are compatibility evidence only unless the Linux baseline and CI move in the same reviewed change.

The Linux Flutter project and focused gate are checked in. Install the exact official Flutter 3.47.1 stable archive declared in .mise.toml, then run its gate. The pin supplies Dart 3.13, the standard GTK3 Linux embedder, and required Linux Impeller support (Impeller is the default desktop renderer since stable 3.47); do not replace it with another SDK or accept a Skia-backed smoke without updating the renderer decision and evidence:

just setup-flutter
just gate-flutter-shell

just build-flutter-linux and just run-flutter additionally need CMake, Ninja, pkg-config, and GTK3 development headers. Missing host packages are an environment limitation; they do not turn Rust or Dart-only checks into Linux bundle proof. The direct build and run recipes use release mode because the official stable archive contains the reviewed Linux engine; the pinned GNOME builder remains authoritative for distributable artifacts. The Linux runner requires native Wayland. just run-flutter-cage additionally uses Cage with wlroots' headless backend for isolated local Wayland testing; X11 and XWayland are intentionally unsupported.

The released Linux shell is Flutter. Local and CI release builds use the same plain Docker workflow and digest-pinned GNOME builder image. CI runs host-only Wayland, IME, AT-SPI, and archive smoke checks on Ubuntu 24.04. Flutter is the sole rendered frontend target; the Rust workspace has no GTK/ libadwaita/Relm4 feature or fallback GUI. just check and just clippy cover every Rust target and feature without GNOME development packages. Verify Linux Flutter release changes with:

just docker-builder-pull
just linux-release-prefetch
just linux-release-smoke
just linux-at-spi-smoke
just linux-interaction-smoke

Native GTK3 development packages are needed only for direct host Flutter Linux builds; the pinned release container supplies them for official archive work. scripts/docker-flutter.sh uses only docker pull, docker image inspect, and docker run: prefetch is network-capable, release/size builds use --network=none, the source mount is read-only, and no host Flutter/Rust toolchain is mounted.

GitHub Releases publish the deterministic x86_64 archive built with the SHA-256-pinned official Flutter stable SDK, locked application/Cargo dependencies, and pinned rusty_v8 input. FlatPark repackages those bytes as a signed convenience Flatpak. The release validator requires GTK3 linkage and rejects debug/JIT artifacts; direct GTK code remains limited to Flutter's native runner boundary.

The safe Rust controller and handwritten C ABI can be developed without Flutter installed:

just test-flutter-controller
just gate-native-abi
just gate-architecture

These gates prove the bounded JSON/renderer wire, registry, worker, commit-bound input, native smoke, and architecture rules. just test-api proves the renderer protocol model; just test-flutter-formatter-impeller proves formatter/scene behavior. just test-r7 adds the final deletion scan and native/Flutter suites; just gate-r7 composes all rendered transition evidence.

Larger alpha batches

Larger batches are encouraged when they reduce handoff overhead and stay coherent. A batch is coherent if it has:

  • one feature family or one host-object family,
  • one primary visible seam,
  • one docs/compat story,
  • one verification story.

Stop and split when the next addition would introduce a second trust boundary, a second unrelated feature family, or a second independent rollback concern.

Maintainability budget

Alpha speed is acceptable only while these budgets stay visible:

  • Non-test modules should stay below 1,000 lines. If a module crosses that while moving fast, create the split in the next tock before widening the feature.
  • Prefer boring data flow over framework gravity: DTOs in vixen-api, lifecycle and pipeline state in the engine-owned browser/context/document graph, and browser-facing adapters in headless/CDP/shell.
  • Keep Dart DTOs and native bridge code mechanical. Renderer box/fragment/scene state is ephemeral and commit-bound; do not mirror profile, navigation, DOM, permissions, policy, script state, or accessibility meaning in Flutter.
  • Avoid duplicate parsers/matchers. Runtime host objects and BrowserCore/Page operations must extract or call the same Rust implementation.
  • Do not reintroduce string-expression shims. Retire transitional runtime/ document snapshots as live resources replace them.
  • Keep COMPAT.md honest: partial support is fine, overclaiming is not.

Alpha definition of done

A dev/alpha slice is done when:

  • the supported subset is named,
  • unsupported inputs fail closed,
  • docs mention the current state and next widening step,
  • focused tests and the relevant gate pass,
  • hk pre-commit/pre-push gates are clean before commit/push,
  • any known debt is either removed immediately or named as the next tock.