Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 0 additions & 59 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,59 +217,6 @@ jobs:
${{ runner.temp }}/algal-idb-evidence/*.json
if-no-files-found: ignore

surface-renderers:
name: Surface renderer contract (ubuntu-24.04)
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ env.BUN_VERSION }}
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2
with:
shared-key: surface-renderers
save-if: ${{ github.ref == 'refs/heads/main' }}
workspaces: |
examples/malleable-site/renderers -> target
examples/local-triage/renderers -> target
- run: bun examples/malleable-site/renderers/fixtures/generate.ts --check
- run: cargo fmt --manifest-path examples/malleable-site/renderers/Cargo.toml -- --check
- run: cargo test --manifest-path examples/malleable-site/renderers/Cargo.toml --locked
- run: cargo clippy --manifest-path examples/malleable-site/renderers/Cargo.toml --locked --all-targets -- -D warnings

- run: cargo fmt --manifest-path examples/local-triage/renderers/Cargo.toml -- --check
- run: cargo test --manifest-path examples/local-triage/renderers/Cargo.toml --locked
- run: cargo clippy --manifest-path examples/local-triage/renderers/Cargo.toml --locked --all-targets -- -D warnings

# macOS runs only the desktop feature surface; the generic renderer checks
# run once on Linux above.
surface-renderers-macos:
name: Surface renderer contract (macos-14)
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: macos-14
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
components: clippy
- uses: Swatinem/rust-cache@v2
with:
shared-key: surface-renderers-desktop
save-if: ${{ github.ref == 'refs/heads/main' }}
workspaces: examples/local-triage/renderers -> target
- run: cargo test --manifest-path examples/local-triage/renderers/Cargo.toml --locked --features desktop
- run: cargo clippy --manifest-path examples/local-triage/renderers/Cargo.toml --locked --all-targets --features desktop -- -D warnings

# One Linux build of the kernel: fmt, clippy, the test suite (which builds
# the debug binary) and the debug binary as an artifact that the parity,
# application-parity and demo jobs download instead of compiling again.
Expand Down Expand Up @@ -512,8 +459,6 @@ jobs:
- test
- coding-harness
- browser-grow
- surface-renderers
- surface-renderers-macos
- native
- native-parity-build
- native-macos
Expand All @@ -533,8 +478,6 @@ jobs:
TEST: ${{ needs.test.result }}
CODING_HARNESS: ${{ needs.coding-harness.result }}
BROWSER_GROW: ${{ needs.browser-grow.result }}
SURFACE_RENDERERS: ${{ needs.surface-renderers.result }}
SURFACE_RENDERERS_MACOS: ${{ needs.surface-renderers-macos.result }}
NATIVE: ${{ needs.native.result }}
NATIVE_PARITY_BUILD: ${{ needs.native-parity-build.result }}
NATIVE_MACOS: ${{ needs.native-macos.result }}
Expand All @@ -560,8 +503,6 @@ jobs:
require test "$TEST" false
require coding-harness "$CODING_HARNESS" "$code_skip"
require browser-grow "$BROWSER_GROW" "$browser_skip"
require surface-renderers "$SURFACE_RENDERERS" "$code_skip"
require surface-renderers-macos "$SURFACE_RENDERERS_MACOS" "$code_skip"
require native "$NATIVE" "$code_skip"
require native-parity-build "$NATIVE_PARITY_BUILD" "$code_skip"
require native-macos "$NATIVE_MACOS" "$code_skip"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ promoted/
coverage/
.env*
site/.production-browser/
**/target/
4 changes: 2 additions & 2 deletions docs/browser-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,5 @@ Rust expression evaluator runs as WebAssembly. A secure browser context and
those storage APIs are required. The browser renderer and application checks
remain trusted software; the editable workflow cannot replace them.

See [local triage](local-triage.md) for the same task model in a local Bun host,
Dioxus desktop interface, and Ratatui terminal interface.
See [local triage](local-triage.md) for the same task model in a local Bun host
and its served browser workspace.
24 changes: 11 additions & 13 deletions docs/local-triage.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Local triage is a second ALGAL application with persistent tasks, typed forms,
filtering, grouping, ordering and an editable reopening policy. The same captured
state and typed commands drive its browser, Dioxus desktop and Ratatui terminal
presentations. Schema v2 adds task categories through a replayable memory migration.
state and typed commands drive its served browser presentation and the standalone
host CLI. Schema v2 adds task categories through a replayable memory migration.

The [browser task workspace](browser-tasks.md) runs this task model with
IndexedDB storage and an offline page. The commands below use the filesystem
Expand All @@ -23,17 +23,15 @@ commands for that serving process. The browser removes the token from the addres
bar; the server checks the exact host and origin. Task state is stored in the
selected local directory. Stop the server to revoke access.

The macOS arm64 package contains `ALGAL Triage.app`, `bin/triage-tui` and a
standalone `bin/triage-host`. The host embeds Bun and the exact ALGAL expression
WASM, so running an extracted package needs neither a checkout nor an installed
Bun. Build it with `bun examples/local-triage/package.ts`; the repository's
host scheduling rules apply to native builds. Packaging refuses to overwrite
an existing artifact directory. The package manifest records byte hashes.

The desktop adapter uses the system WebView. The local artifact is ad-hoc signed,
not notarized; other desktop operating systems and mobile distribution are not
qualified by this package. See the [renderer guide](../examples/local-triage/renderers/README.md)
for keyboard controls, build commands and the exact supported profiles.
The macOS arm64 package contains the standalone `bin/triage-host` CLI. The host
embeds Bun and the exact ALGAL expression WASM, so running an extracted package
needs neither a checkout nor an installed Bun. Build it with
`bun examples/local-triage/package.ts`; the repository's host scheduling rules
apply to native builds. Packaging refuses to overwrite an existing artifact
directory. The package manifest records byte hashes.

The local artifact is unsigned; other desktop operating systems and mobile
distribution are not qualified by this package.

## Tasks, drafts and revisions

Expand Down
5 changes: 3 additions & 2 deletions docs/malleable-roadmap-progress.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ and session drafts remain separate, with explicit stale-head rebase and conflict
The profile is bounded to 32 tasks and 128 states; forks copy no mutable custody,
dispatch ledger or external authority. The package is ad-hoc signed, not notarized.

[Renderer measurements](../examples/local-triage/renderers/performance/README.md)
use budgets declared before execution. The embed passed nine checks: 95,438 gzip
The 2026-09-23 renderer measurements (removed with the renderer experiments;
the git history retains `examples/local-triage/renderers/performance/`)
used budgets declared before execution. The embed passed nine checks: 95,438 gzip
bytes, 40.8 ms local cold readiness p95, 0.2 ms synchronous update p95, 772,676
bytes retained JS growth after 1,000 revision swaps and 100 mount cycles, zero DOM
growth and no measured host interference. Packaged host capture and TUI snapshot
Expand Down
2 changes: 1 addition & 1 deletion docs/malleable-site.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ or navigation contract.

The site build emits the starting [revision](/living/initial.json), [signals](/living/signals.json), [semantic view](/living/view.json), [manifest](/living/manifest.json), [portable bundle](/living/bundle.json) and [replay-verified receipt](/living/receipt.json). These files describe the starting example, not later unexported browser edits.

The renderer spike under `examples/malleable-site/renderers/` consumes the same semantic tree. Its results distinguish a web renderer, a desktop WebView and a terminal presentation. Renderer compatibility does not imply identical pixels, full native widgets or general interactive application portability.
Earlier renderer spikes under `examples/malleable-site/renderers/` (web, desktop WebView and terminal) were removed after the feasibility measurements concluded; the git history retains them. Renderer compatibility does not imply identical pixels, full native widgets or general interactive application portability.

## Scope

Expand Down
8 changes: 2 additions & 6 deletions examples/local-triage/package-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ try {
const types = await command(["/usr/bin/tar", "-tvzf", resolve(archive)]);
assert(types.trim().split("\n").every(line => line.startsWith("-") || line.startsWith("d")), "Archive contains only regular files/directories");
await command(["/usr/bin/tar", "-xzf", resolve(archive), "-C", temporary]);
const manifest = JSON.parse(await readFile(join(root, "manifest.json"), "utf8")) as { contract: string; files: { path: string; bytes: number; sha256: string }[]; provenance: { gitHead: string; gitWorktreeDirty: boolean; bunVersion: string; rustcVersion: string; source: { sha256: string; files: unknown[] } } };
const manifest = JSON.parse(await readFile(join(root, "manifest.json"), "utf8")) as { contract: string; files: { path: string; bytes: number; sha256: string }[]; provenance: { gitHead: string; gitWorktreeDirty: boolean; bunVersion: string; source: { sha256: string; files: unknown[] } } };
assert(manifest.contract === "algal.triage-package.v1", "Package manifest contract matches");
assert(/^[a-f0-9]{40,64}$/.test(manifest.provenance.gitHead) && typeof manifest.provenance.gitWorktreeDirty === "boolean" && !!manifest.provenance.bunVersion && !!manifest.provenance.rustcVersion && manifest.provenance.source.files.length > 0 && createHash("sha256").update(JSON.stringify(manifest.provenance.source.files)).digest("hex") === manifest.provenance.source.sha256, "Retained source identity and toolchain provenance match manifest");
assert(/^[a-f0-9]{40,64}$/.test(manifest.provenance.gitHead) && typeof manifest.provenance.gitWorktreeDirty === "boolean" && !!manifest.provenance.bunVersion && manifest.provenance.source.files.length > 0 && createHash("sha256").update(JSON.stringify(manifest.provenance.source.files)).digest("hex") === manifest.provenance.source.sha256, "Retained source identity and toolchain provenance match manifest");
for (const file of manifest.files) { const bytes = await readFile(join(root, file.path)); assert(bytes.length === file.bytes && createHash("sha256").update(bytes).digest("hex") === file.sha256, `Exact packaged bytes: ${file.path}`); }
for (const file of manifest.files.filter(item => item.path.startsWith("bin/") || item.path.includes("/Resources/bin/") || item.path.includes("/MacOS/"))) {
const dependencies = (await command(["/usr/bin/otool", "-L", join(root, file.path)])).trim().split("\n").slice(1).map(line => line.trim().split(" (", 1)[0]!);
Expand Down Expand Up @@ -66,8 +66,6 @@ try {
assert((await host<{ ok: boolean }>("verify", transfer)).ok, "Extracted package replays exported migration evidence");
const forked = await host<Capture>("fork", undefined, [file, "forked"]);
assert(forked.application === "forked" && forked.tasks.length === 1, "Extracted package forks into new authority-free identity");
const tui = await command([join(root, "bin/triage-tui"), "--dir", state, "--application", "smoke", "--snapshot"]);
assert(tui.includes("Extracted app task") && tui.includes("Keep this draft"), "Extracted TUI renders actual retained tasks and stale draft");
const server = Bun.spawn([join(root, "bin/triage-host"), state, "smoke", "serve"], { cwd: empty, env: { PATH: "/usr/bin:/bin", LANG: "en_US.UTF-8" }, stdin: "ignore", stdout: "pipe", stderr: "ignore" });
const serverTimer = setTimeout(() => server.kill("SIGKILL"), 30000);
const reader = server.stdout.getReader();
Expand All @@ -84,8 +82,6 @@ try {
assert(opened.status === 200 && body.capture.head === capture.head && body.capture.tasks[0]?.title === "Extracted app task", "Extracted browser host serves the same captured application");
assert((await fetch(`${url.origin}/api/open`, { signal: AbortSignal.timeout(5000) })).status === 403, "Extracted browser host requires owner authorization");
} finally { reader.releaseLock(); clearTimeout(serverTimer); if (server.exitCode === null) server.kill("SIGKILL"); await server.exited; }
await command(["/usr/bin/codesign", "--verify", "--deep", "--strict", join(root, "ALGAL Triage.app")]);
checks.push("Extracted .app ad-hoc signature verifies");
const report = { contract: "algal.triage-package-smoke.v1", ok: true, archive: resolve(archive), archiveSha256: createHash("sha256").update(await readFile(resolve(archive))).digest("hex"), sourceSha256: manifest.provenance.source.sha256, gitHeadAtBuild: manifest.provenance.gitHead, dirtyAtBuild: manifest.provenance.gitWorktreeDirty, platform: `${process.platform}-${process.arch}`, noSourceCheckoutRequired: true, noBunInstallationRequired: true, networkDenied: "not-tested-here", checks, finalHead: capture.head, states: transfer.states.length };
if (reportPath) await writeFile(reportPath, JSON.stringify(report, null, 2) + "\n");
console.log(JSON.stringify(report));
Expand Down
Loading
Loading