Sign in to edit tickets from this page.

← all tickets · home

Build the Benac C1 Hello World installable PWA from the current static/docs repo

resolved 618d387c-52e6-4958-a059-c523f977c89c

created_at
2026-05-02
updated_at
2026-05-03
priority
P1
ticket_type
feature
resolved_at
2026-05-03
resolution
accepted

Body

Ticket: Build the Benac C1 Hello World installable PWA from the current static/docs repo

Summary

Build the first real Benac Host Station as a Rust-authored, HTTPS-served, installable Progressive Web App. The app must run in iOS and Android mobile browsers using browser-available capabilities only. It must implement the C1 Hello World kernel slice: local Station identity, local document store, local content-addressed blob store, package import/inspection, manifest/schema validation, signed claim fixture verification, descriptor creation, local no-risk trust approval, explicit capability grant, declarative execution, WASM execution, invocation/evidence/effect ledgers, trace inspection, trace capsule export/import, tamper detection, and fail-closed negative tests.

The current repository is not yet an application. It contains SyRS/GraphMD requirement records, a static index.html, Node scripts for compiling/validating requirements, and a Rust operator sidecar under tools/gravitational_lens. This ticket creates the actual Benac Rust workspace and PWA.

Source of truth

The implementation is governed by BENAC-SYRS-0.4. The relevant baseline is C1 Portable Execution Station on the mobile browser PWA floor. The SyRS requires an HTTPS-served installable PWA for iOS/Android, local-first operation, Station profiles, no server authority, local document/blob stores, declarative and WASM execution, trust/capability governance, invocation/evidence/effect records, export/import capsules, offline app shell behavior, and the day-one Hello World demonstration.

Product outcome

A user can open https://benac.benac.dev/, install Benac to the iOS Home Screen, go offline, reopen the installed app, import or load the Hello World package bundle, inspect it, approve narrowly scoped no-risk execution, run both the declarative and WASM implementations, inspect the exact trace, export a trace capsule, import the capsule back, and see tampering or unauthorized execution fail closed.

Non-goals for this ticket

This ticket does not implement C2 replication, C3 remote storage, C3 remote compute, encrypted private capsules, private blob encryption, native/container execution, same-origin package JavaScript, external accounts, OAuth, provider adapters, LLM providers, central package registries, central identity providers, telemetry, high-risk physical-world capabilities, or production-grade key recovery.

This ticket must not add provider-specific behavior to Benac Core. No OpenAI, Anthropic, Gemini, MCP, cloud object store, cloud compute, smart-home, or device-specific behavior belongs in this milestone.


Architectural decisions

1. Rust workspace shape

Create a root Cargo workspace while preserving the existing Node/GraphMD docs pipeline.

Required tree:

Cargo.toml
rust-toolchain.toml
.cargo/config.toml
apps/
  pwa/
    Cargo.toml
    Trunk.toml
    index.html
    public/
      manifest.webmanifest
      icon.svg
      icon-180.png
      icon-192.png
      icon-512.png
      sw.template.js
    src/
      main.rs
      app.rs
      routes.rs
      ui/
      worker_bridge.rs
crates/
  benac-core/
    Cargo.toml
    src/
      lib.rs
      canonical_json.rs
      crypto.rs
      ids.rs
      principal.rs
      station_profile.rs
      document.rs
      blob.rs
      package.rs
      descriptor.rs
      claim.rs
      auth.rs
      trust.rs
      capability.rs
      invocation.rs
      evidence.rs
      effect.rs
      audit.rs
      declarative.rs
      capsule.rs
      errors.rs
  benac-browser/
    Cargo.toml
    src/
      lib.rs
      indexeddb_doc_store.rs
      indexeddb_blob_store.rs
      browser_clock.rs
      browser_random.rs
      browser_station.rs
      file_io.rs
      wasm_runner.rs
  benac-fixtures/
    Cargo.toml
    src/
      lib.rs
      hello_world.rs
      signed_claims.rs
      capsules.rs
  benac-conformance/
    Cargo.toml
    src/
      lib.rs
      hello_world_suite.rs
packages/
  hello-world-wasm/
    Cargo.toml
    src/lib.rs
xtask/
  Cargo.toml
  src/main.rs

tools/gravitational_lens remains untouched unless it is being used as a ticketing sidecar. It is not Benac Core.

2. PWA framework and build

Use Leptos in client-side-rendered mode, compiled to wasm32-unknown-unknown and bundled with Trunk.

Rationale: this keeps the first Benac Host as a static web app with no server runtime, while still letting us write the actual application in Rust.

The PWA must be buildable with:

rustup target add wasm32-unknown-unknown
cargo test --workspace
cargo run -p xtask -- build-hello-world-fixtures
trunk build apps/pwa/index.html --release --dist dist
cargo run -p xtask -- finalize-pwa-dist dist
cargo run -p xtask -- validate-pwa-dist dist

3. Static-only deployment

The deployed app is a static PWA. The server serves bytes. The server is not authority for identity, package trust, package execution, invocation evidence, or local policy.

The deployment target for this ticket is:

https://benac.benac.dev/

The static server must serve:

/                         -> app shell
/index.html               -> app shell
/manifest.webmanifest     -> PWA manifest
/sw.js                    -> generated service worker
/assets/...               -> Trunk output
/fixtures/...             -> optional static public fixture bundles only

No backend API is introduced in this ticket.

4. Routing

Use hash routes for the first PWA:

/#/
/#/station
/#/packages
/#/packages/<package-id>
/#/descriptors/<descriptor-id>
/#/trust
/#/invoke
/#/traces
/#/traces/<invocation-id>
/#/capsules
/#/conformance

Rationale: hash routing avoids static-server rewrite dependency and makes the initial iOS PWA deployment less fragile.

5. Browser storage

Use IndexedDB for both logical document storage and local CAS blob storage.

Do not use localStorage for authoritative Benac records. localStorage may only store non-authoritative UI preferences.

Create one IndexedDB database:

name: benac-station-v0-hw1
version: 1
stores:
  docs        key: _id
  blobs       key: content_id
  meta        key: key
  migrations  key: id

The document store must use Couch/Pouch-compatible logical object shapes: JSON documents with stable _id, object_type, schema_version, timestamps where relevant, and content IDs for immutable objects. Replication is not implemented in this ticket, but the schema must not make replication impossible later.

The blob store stores raw bytes as Uint8Array/browser Blob values under content-addressed IDs. Every read before execution verifies the bytes against the expected hash.

6. Content identity profile

Implement benac.crypto.v0.hw1.

Hash ID string format:

bencid:v0:<domain>:sha256:<lowercase-hex-digest>

Examples:

bencid:v0:package:sha256:...
bencid:v0:schema:sha256:...
bencid:v0:descriptor:sha256:...
bencid:v0:claim:sha256:...
bencid:v0:blob:sha256:...
bencid:v0:invocation:sha256:...
bencid:v0:evidence:sha256:...
bencid:v0:effect:sha256:...
bencid:v0:capsule:sha256:...

Hash input rule:

hash_input = utf8("benac.crypto.v0.hw1\n" + domain + "\n") || bytes

For structured documents, bytes is canonical JSON. For blobs, bytes is the exact raw byte sequence.

7. Canonical JSON profile

Implement benac.cjson.v0.hw1:

8. Principal and signature profile

Use Ed25519 for the HW1 signed claim and Station principal profile.

Principal ID format:

benac-principal:v0:ed25519:<base64url-public-key-no-padding>

On first PWA launch, generate a Station Ed25519 keypair using browser-backed randomness via Rust getrandom with the JS/WASM feature enabled. Store the private key in IndexedDB under the meta store for HW1. Mark the Station profile honestly:

{
  "protected_key_storage": "browser_indexeddb_best_effort_hw1",
  "private_keys_package_readable": false,
  "private_keys_replicated_by_default": false
}

Do not expose private keys to packages. Do not include private keys in capsule export.

9. Local authentication profile

Implement a minimal C1-compatible local approval context:

method_class: local_user_gesture_no_risk_approval
issuer: local Station principal
scope: approve_no_risk_hello_world_execution
expires_after: 30 minutes

This is not a central identity provider. It is a local policy equivalent for the no-risk Hello World approval path.

A trust approval requires a visible user gesture in the PWA. The app creates:

auth_session
authenticated_approval
authentication_event
trust_decision
capability_grant
audit_event

Agent authentication is simulated as a local scoped agent session for this ticket. The agent may create a trust request. The agent may not create an active trust decision or capability grant.

10. Package/capsule file format

For HW1, use a single JSON capsule file for import/export:

.benac-capsule.json

Shape:

{
  "object_type": "capsule",
  "schema_version": "benac.capsule.v0.hw1",
  "profile": "benac.crypto.v0.hw1",
  "created_at": "...",
  "created_by_station_principal": "... or fixture principal ...",
  "documents": [],
  "blobs": [
    {
      "content_id": "bencid:v0:blob:sha256:...",
      "media_type": "application/wasm",
      "size_bytes": 1234,
      "base64url": "..."
    }
  ],
  "root_refs": [],
  "integrity_manifest": {
    "document_ids": [],
    "blob_ids": [],
    "capsule_content_id": "bencid:v0:capsule:sha256:..."
  }
}

Blob hashes are always computed over raw decoded bytes, not over base64 text.

This JSON capsule is acceptable for tiny Hello World. Large/chunked/multipart capsules are deferred.

11. WASM execution profile

Implement benac.wasm_abi.v0.hw1.

The Hello World WASM module is a pure transform. It must export:

memory
alloc(len: u32) -> u32
dealloc(ptr: u32, len: u32)
benac_invoke(request_ptr: u32, request_len: u32, config_ptr: u32, config_len: u32) -> u64

The returned u64 packs pointer and length:

(ptr << 32) | len

The browser host writes canonical request/config JSON bytes into guest memory, calls benac_invoke, reads output JSON bytes from guest memory, validates output schema, and deallocates guest memory.

Allowed imports for HW1: none.

Any WASM module declaring imports is denied before execution unless a future profile explicitly allows those imports. This denial must create an invocation record and denied effect record.

Run WASM execution in a dedicated Web Worker. The package never receives DOM access, IndexedDB access, localStorage access, raw document store access, raw blob store access, secrets, private keys, network fetch, remote storage, remote compute, signing, or decryption.

12. UI style

The UI does not need polish, but it must be inspectable. Every authority-bearing object and every denial must be visible.

Required screens:

Station dashboard
Package import/fixture loader
Package inspection
Claim inspection
Descriptor creation
Trust/capability approval
Invocation runner
Trace inspection
Capsule export/import
Conformance checklist

No “magic success” screens. Show hashes, scopes, and records.


Phase 0 — Repository and toolchain bootstrap

Goal

Turn the current docs/static repo into a Rust workspace that can build, test, and ship a static PWA without breaking the existing requirements pipeline.

Implementation tasks

  1. Add root Cargo.toml workspace.
  2. Add rust-toolchain.toml pinned to Rust 1.88.0 or the project-approved Rust version, with wasm32-unknown-unknown, rustfmt, and clippy.
  3. Add .cargo/config.toml with WASM-friendly config.
  4. Add crates:
    • benac-core
    • benac-browser
    • benac-fixtures
    • benac-conformance
    • xtask
  5. Add apps/pwa as a Trunk-built Leptos CSR app.
  6. Keep existing package.json scripts for GraphMD docs validation.
  7. Add root scripts/docs:
    • README.md section: “Building the C1 PWA”
    • docs/decisions/0001-c1-pwa-rust-workspace.md
  8. Add CI workflow .github/workflows/pwa-ci.yml.
  9. CI must run:
    • npm ci
    • npm test
    • cargo fmt --check
    • cargo clippy --workspace --all-targets -- -D warnings
    • cargo test --workspace
    • cargo build -p hello-world-wasm --target wasm32-unknown-unknown --release
    • trunk build apps/pwa/index.html --release --dist dist
    • cargo run -p xtask -- validate-pwa-dist dist

Done means


Phase 1 — Installable PWA shell

Goal

Serve a real installable PWA shell before implementing the Benac kernel. This phase proves the host can be installed and opened offline.

Implementation tasks

  1. Build a minimal Leptos app with routes:
    • /#/
    • /#/station
    • /#/packages
    • /#/traces
    • /#/conformance
  2. Add manifest.webmanifest:
    • name: Benac
    • short_name: Benac
    • start_url: ./
    • scope: ./
    • display: standalone
    • background_color
    • theme_color
    • icons: 180, 192, 512
  3. Add iOS-friendly metadata in index.html:
    • apple-mobile-web-app-capable=yes
    • apple-mobile-web-app-title=Benac
    • apple-touch-icon
    • viewport tag with mobile-safe settings
  4. Add service worker template.
  5. Add xtask finalize-pwa-dist:
    • compute hash of all build assets;
    • write /sw.js with a precache manifest;
    • ensure index.html, manifest, icons, app JS/WASM assets, and CSS are cached.
  6. Add offline fallback to index.html for app shell routes.
  7. Add PWA status panel in UI:
    • service worker registration status;
    • controller status;
    • cache version;
    • offline capability state;
    • storage API availability;
    • WebAssembly availability;
    • IndexedDB availability.
  8. Add xtask validate-pwa-dist:
    • confirms manifest exists and parses;
    • confirms manifest has installability fields;
    • confirms service worker exists;
    • confirms icons exist;
    • confirms app WASM asset exists;
    • confirms no accidental backend API dependency is referenced.

Done means


Phase 2 — Core identity, canonicalization, local stores, and Station profile

Goal

Implement the minimum Benac C1 kernel foundation: content IDs, canonical JSON, Station principal, Station profile, local document store, local blob store, and stable errors.

Implementation tasks

benac-core

  1. Implement CanonicalJson.
  2. Implement domain-separated SHA-256 content IDs.
  3. Implement typed IDs:
    • ContentId
    • PrincipalId
    • DocumentId
    • BlobId
    • InvocationId
  4. Implement object domains:
    • package
    • schema
    • descriptor
    • claim
    • station_profile
    • trust_decision
    • capability_grant
    • invocation
    • evidence
    • effect
    • audit_event
    • capsule
    • blob
  5. Implement Ed25519 principal metadata and verification helpers.
  6. Implement stable error shape:
{
  "code": "benac.error.missing_blob",
  "message": "...",
  "object_ref": "...",
  "details": {}
}
  1. Implement logical document structs for:
    • principal
    • station_profile
    • blob_availability
    • audit_event
  2. Implement test vectors for:
    • canonical JSON;
    • domain-separated hash;
    • blob hash over raw bytes;
    • content ID parse/format;
    • principal ID parse/format.

benac-browser

  1. Implement IndexedDB document store.
  2. Implement IndexedDB blob store.
  3. Implement database migration version 1.
  4. Implement first-run Station initialization:
    • generate Station Ed25519 keypair;
    • create principal document;
    • create Station profile document;
    • create audit event station_initialized.
  5. Implement Station profile for browser PWA:
{
  "object_type": "station_profile",
  "schema_version": "benac.station_profile.v0.hw1",
  "host_platform": "browser_pwa",
  "host_target": "ios_android_mobile_browser_floor",
  "supports_installable_pwa": true,
  "supports_offline_app_shell": true,
  "supports_local_document_store": true,
  "supports_local_cas_blob_store": true,
  "supports_declarative_execution": true,
  "supports_wasm_execution": true,
  "supports_native_execution": false,
  "supports_same_origin_package_js": false,
  "supports_network_capability": false,
  "supports_remote_storage": false,
  "supports_remote_compute": false,
  "supports_decryption_capability": false,
  "storage_persistence_guarantee": "best_effort_browser_storage",
  "protected_key_storage": "browser_indexeddb_best_effort_hw1"
}

UI

  1. Add Station dashboard.
  2. Show Station principal.
  3. Show Station profile.
  4. Show local storage status.
  5. Add “Reset local Station” dev-only control behind explicit confirmation.

Done means


Phase 3 — Hello World package bundle, manifest validation, claim verification, and inspection

Goal

Create and import the Hello World package as a content-addressed Benac package, but do not execute it yet.

Implementation tasks

Package schema

Implement benac.package_manifest.v0.hw1 with these required fields:

{
  "object_type": "package",
  "schema_version": "benac.package_manifest.v0.hw1",
  "label": "hello-world",
  "version_label": "0.0.1-hw1",
  "interfaces": ["transform"],
  "schemas": {
    "config": { "content_id": "..." },
    "request": { "content_id": "..." },
    "output": { "content_id": "..." }
  },
  "implementations": [],
  "declared_capabilities": [],
  "forbidden_capabilities": [],
  "fixtures": [],
  "claim_refs": []
}

Unknown required fields must fail validation unless the app supports the extension profile.

Hello World schemas

Generate schema documents:

Config schema:

{
  "type": "object",
  "additionalProperties": false,
  "properties": {}
}

Request schema:

{
  "type": "object",
  "required": ["message"],
  "additionalProperties": false,
  "properties": {
    "message": { "const": "hello" }
  }
}

Output schema:

{
  "type": "object",
  "required": ["message", "reply"],
  "additionalProperties": false,
  "properties": {
    "message": { "const": "hello" },
    "reply": { "const": "world" }
  }
}

Declarative implementation

Define declarative transform grammar benac.declarative_transform.v0.hw1:

{
  "kind": "declarative_transform.v0",
  "output": {
    "message": { "from_request": "/message" },
    "reply": { "const": "world" }
  }
}

WASM artifact

  1. Add packages/hello-world-wasm.
  2. Compile to wasm32-unknown-unknown.
  3. Implement the HW1 WASM ABI.
  4. Generate the .wasm artifact during fixture build.
  5. Store artifact bytes in the capsule under a blob content ID.

Signed claim fixture

  1. Add fixture author principal.
  2. Generate a signed claim:
{
  "object_type": "signed_claim",
  "schema_version": "benac.signed_claim.v0.hw1",
  "claim_type": "package_authoring_fixture",
  "target_object_type": "package",
  "target_content_id": "...",
  "issuer_principal": "...",
  "profile": "benac.crypto.v0.hw1",
  "payload": {
    "statement": "Fixture author claims this is the Benac Hello World package for C1 testing."
  },
  "signature": {
    "algorithm": "ed25519",
    "signature_base64url": "..."
  }
}
  1. Signature covers the canonical claim envelope excluding the signature field.
  2. Verification result is stored as evidence/inspection state.
  3. Verified claim does not create trust.

Import flow

  1. Add “Load bundled Hello World fixture” button.
  2. Add “Import capsule file” file picker.
  3. On import:
    • parse capsule;
    • verify capsule integrity manifest;
    • decode blobs;
    • verify blob hashes;
    • validate package manifest;
    • validate schemas;
    • verify signed claims;
    • store documents and blobs;
    • create blob availability records;
    • create audit events.
  4. Show package inspection page:
    • package content ID;
    • manifest;
    • schema refs;
    • implementation refs;
    • WASM artifact hash and availability;
    • declared and forbidden capabilities;
    • fixtures;
    • claim verification status;
    • trust status: untrusted.

Done means


Phase 4 — Descriptor, local approval, trust decision, and capability grant

Goal

Implement the local authority boundary: imported packages do not run until a locally authenticated approval creates a scoped trust decision and explicit capability grant.

Implementation tasks

Descriptor

Implement descriptor snapshot schema:

{
  "object_type": "descriptor",
  "schema_version": "benac.descriptor.v0.hw1",
  "package_content_id": "...",
  "config": {},
  "created_at": "...",
  "created_by_station_principal": "..."
}

Descriptor snapshots are content-addressed.

Auth session and approval

Implement:

auth_session
authenticated_approval
authentication_event

For HW1, the approval flow is:

  1. User opens package review.
  2. User selects “Approve no-risk Hello World execution.”
  3. App shows exact scope.
  4. User confirms with visible gesture.
  5. App creates a local auth session with 30-minute expiry.
  6. App creates authenticated approval record.

Trust decision

Trust decision schema must include:

{
  "object_type": "trust_decision",
  "schema_version": "benac.trust_decision.v0.hw1",
  "issuer_principal": "...",
  "auth_context_ref": "...",
  "target": {
    "package_content_id": "...",
    "descriptor_content_id": "..."
  },
  "scope": {
    "interfaces": ["transform"],
    "implementations": ["...decl...", "...wasm..."],
    "data_classes": ["public"],
    "capabilities": [
      "local_execution",
      "local_blob_read_exact",
      "evidence_emit",
      "effect_emit"
    ],
    "forbidden": [
      "network",
      "secret",
      "remote_storage",
      "remote_compute",
      "native_execution",
      "same_origin_package_js",
      "decryption",
      "signing",
      "raw_document_store_access",
      "raw_blob_store_access"
    ]
  },
  "expires_at": "...",
  "revoked_at": null
}

Capability grant

Capability grant schema must include:

{
  "object_type": "capability_grant",
  "schema_version": "benac.capability_grant.v0.hw1",
  "issuer_principal": "...",
  "auth_context_ref": "...",
  "package_content_id": "...",
  "descriptor_content_id": "...",
  "grants": [
    {
      "capability": "local_execution",
      "scope": { "implementations": ["...decl...", "...wasm..."] }
    },
    {
      "capability": "local_blob_read_exact",
      "scope": { "blob_content_ids": ["...wasm blob..."] }
    },
    {
      "capability": "evidence_emit",
      "scope": { "invocation_bound": true }
    },
    {
      "capability": "effect_emit",
      "scope": { "invocation_bound": true }
    }
  ],
  "expires_at": "...",
  "revoked_at": null
}

Agent self-authorization denial

Implement a fixture agent session:

agent_id: benac-dev-agent
session_scope: inspect, author_trust_request, run_fixture_tests

The agent can create a trust_request document, but cannot create active trust_decision or capability_grant documents.

Done means


Phase 5 — Declarative Hello World invocation, ledgers, and trace inspection

Goal

Run the declarative implementation and leave complete receipts.

Implementation tasks

Invocation lifecycle

Implement invocation states:

created
request_validated
policy_checked
implementation_selected
running
output_produced
output_validated
succeeded
failed

Every execution attempt creates an invocation record, including validation failures and denied attempts.

Invocation record must include:

{
  "object_type": "invocation",
  "schema_version": "benac.invocation.v0.hw1",
  "invocation_id": "...",
  "station_principal": "...",
  "initiating_actor": "local_user | local_agent | system_fixture",
  "station_profile_content_id": "...",
  "package_content_id": "...",
  "descriptor_content_id": "...",
  "selected_implementation_id": "...",
  "selected_implementation_content_id": "...",
  "skipped_implementations": [],
  "request_content_id": "...",
  "request_body": { "message": "hello" },
  "trust_decision_ref": "...",
  "capability_grant_refs": [],
  "auth_context_ref": "...",
  "started_at": "...",
  "finished_at": "...",
  "status": "succeeded | failed | denied",
  "output_content_id": "...",
  "output_body": { "message": "hello", "reply": "world" },
  "evidence_refs": [],
  "effect_refs": [],
  "validation_status": {
    "request": "valid | invalid",
    "output": "valid | invalid"
  },
  "failure": null
}

Evidence records

Emit evidence records for:

request_received
request_schema_validated
package_manifest_validated
claim_verified_not_trusted
trust_scope_matched
capability_scope_matched
implementation_selected
declarative_output_produced
output_schema_validated

Effect records

Emit effect records for:

local_execution_attempted
local_execution_completed
evidence_record_written
effect_record_written

No network, secret, remote storage, remote compute, native execution, decryption, signing, same-origin package JS, or raw store access effects may occur.

Declarative executor

Implement the minimal grammar:

const
from_request JSON pointer
object construction

The Hello World declarative transform must produce:

{ "message": "hello", "reply": "world" }

Negative tests

Implement these negative cases:

  1. Invalid request fails before execution and records invocation/evidence.
  2. Missing trust fails closed and records denial.
  3. Missing capability grant fails closed and records denial.
  4. Revoked trust fails closed and records denial.
  5. Declarative implementation requesting an undeclared or forbidden effect fails closed and records denied effect.

UI

Add invocation runner:

Add trace inspection page:

Done means


Phase 6 — WASM Hello World invocation and package isolation

Goal

Run the WASM implementation from the verified CAS blob through the HW1 WASM ABI, isolated from Benac UI/storage/keys/secrets/network.

Implementation tasks

  1. Build packages/hello-world-wasm as a pure Rust WASM artifact.
  2. Fixture generation stores the .wasm bytes as a CAS blob in the Hello World capsule.
  3. Browser WASM runner:
    • reads blob by content ID;
    • verifies raw bytes against expected blob hash;
    • parses declared imports;
    • rejects any import for HW1;
    • instantiates the module in a dedicated Web Worker;
    • writes request/config bytes into guest memory;
    • invokes benac_invoke;
    • reads output bytes;
    • validates output schema;
    • terminates worker on timeout or failure.
  4. Add implementation selection record:
    • selected WASM implementation;
    • declarative implementation skipped only when explicitly selecting WASM;
    • compatibility checks;
    • policy checks;
    • blob availability checks;
    • hash verification result;
    • import whitelist result.
  5. Add WASM-specific evidence:
    • artifact_blob_present;
    • artifact_hash_verified;
    • wasm_imports_checked;
    • wasm_invocation_started;
    • wasm_output_produced;
    • output_schema_validated.
  6. Add WASM-specific effects:
    • local_blob_read_attempted;
    • local_blob_read_completed;
    • local_execution_attempted;
    • local_execution_completed.
  7. Add negative WASM fixtures:
    • tampered blob;
    • missing blob;
    • WASM module with forbidden import;
    • WASM output invalid schema.

Done means


Phase 7 — Trace capsule export/import and tamper detection

Goal

Make the Hello World receipts portable. Export the package/trace as a capsule, import it back, and verify integrity.

Implementation tasks

  1. Implement capsule export for selected invocation trace.
  2. Export must include:
    • package manifest;
    • schemas;
    • descriptor snapshot;
    • WASM artifact blob;
    • signed claim fixture;
    • trust decision;
    • capability grant;
    • auth session/authenticated approval metadata;
    • Station profile;
    • invocation record;
    • evidence records;
    • effect records;
    • audit events;
    • integrity manifest.
  3. Export must exclude:
    • Station private key;
    • raw secret material;
    • non-selected unrelated local records;
    • telemetry, because none exists.
  4. Implement browser file export:
    • creates .benac-capsule.json Blob;
    • downloads or shares through browser-supported flow.
  5. Implement capsule import:
    • parse JSON;
    • validate schema;
    • verify integrity manifest;
    • verify document hashes;
    • verify blob hashes;
    • verify signed claims;
    • store imported records as inactive/inspectable records;
    • imported trust does not automatically become active local trust.
  6. Implement tamper tests:
    • changed document body;
    • changed blob base64;
    • changed claim target;
    • removed required artifact;
    • changed integrity manifest.

Done means


Phase 8 — Deployment, HTTPS serving, and iOS install acceptance

Goal

Serve the completed PWA at the production/static host and verify install/offline/Hello World behavior on iOS.

Implementation tasks

  1. Add .github/workflows/pwa-build.yml:
    • build docs;
    • test Rust workspace;
    • build fixtures;
    • build PWA;
    • finalize service worker;
    • validate dist;
    • upload dist artifact.
  2. Add deploy job using project secrets:
BENAC_DEPLOY_HOST
BENAC_DEPLOY_USER
BENAC_DEPLOY_PATH=/srv/benac
BENAC_DEPLOY_SSH_KEY
  1. Deploy with atomic release directory:
/srv/benac/releases/<git-sha>/
/srv/benac/current -> releases/<git-sha>
  1. Configure static server:
    • HTTPS enabled;
    • HTTP redirects to HTTPS;
    • index.html not aggressively cached;
    • hashed assets cached long-term;
    • sw.js not aggressively cached;
    • .wasm served as application/wasm;
    • .webmanifest served as application/manifest+json or compatible manifest MIME;
    • compression enabled where safe.
  2. Add /health-static.txt with build SHA and timestamp.
  3. Add manual iOS test checklist to docs:
    • open URL in Safari;
    • add to Home Screen;
    • open installed PWA;
    • verify standalone display;
    • load bundled Hello World fixture;
    • approve trust;
    • run declarative;
    • run WASM;
    • inspect trace;
    • export capsule;
    • turn off network;
    • reopen installed PWA;
    • run already-imported Hello World offline;
    • import capsule;
    • verify tamper test.
  4. Add Android install checklist as secondary verification.

Done means


Phase 9 — Conformance and hardening pass

Goal

Make the milestone hard to accidentally regress.

Implementation tasks

  1. Implement benac-conformance Hello World suite.
  2. Add conformance checks for:
    • canonical JSON vectors;
    • domain-separated hash vectors;
    • blob raw-byte hash vectors;
    • package manifest validation;
    • schema validation;
    • signed claim verification;
    • signature does not mutate package identity;
    • import valid capsule;
    • reject tampered capsule;
    • missing blob fail-closed;
    • untrusted package denied;
    • approved declarative invocation succeeds;
    • approved WASM invocation succeeds;
    • invalid request fails before execution;
    • invalid output fails after execution;
    • forbidden WASM import denied;
    • attempted network/remote capability denied and recorded;
    • trace inspection contains required references;
    • export/import preserves hashes.
  3. Add PWA runtime conformance page:
    • run local conformance suite;
    • show pass/fail;
    • export conformance report capsule.
  4. Add performance smoke checks:
    • app shell load time budget recorded;
    • import Hello World capsule budget recorded;
    • run declarative budget recorded;
    • run WASM budget recorded;
    • trace render budget recorded.
  5. Add security review checklist:
    • no package JS execution;
    • no eval;
    • no raw private key exposure through package ABI;
    • no backend authority;
    • no default telemetry;
    • no silent remote fetch;
    • no trust from signature alone;
    • no trust from import alone;
    • no trust from authentication alone.

Done means


Whole-ticket definition of done

This ticket is complete only when all of the following are true:

  1. A fresh Benac PWA installs on iOS from HTTPS.
  2. The installed app opens offline after first load.
  3. A fresh Station initializes local document and blob stores.
  4. The Station generates or imports a Station principal.
  5. The Station profile is inspectable and honestly reports browser/PWA limitations.
  6. The Hello World package imports from a bundled fixture and from a local file.
  7. The package manifest validates.
  8. Config, request, and output schemas validate.
  9. Package identity is content-addressed.
  10. The WASM artifact is stored as a content-addressed blob.
  11. Blob bytes verify before execution.
  12. A signed claim fixture verifies but does not create trust.
  13. A descriptor snapshot is created and content-addressed.
  14. Without trust, execution fails closed and leaves records.
  15. Local no-risk user approval creates auth, approval, trust, and capability records.
  16. Agent-authenticated/session-attributed trust request cannot self-authorize.
  17. Declarative invocation succeeds under scoped trust and capability grant.
  18. WASM invocation succeeds under scoped trust and capability grant.
  19. Both implementations return exactly { "message": "hello", "reply": "world" } for { "message": "hello" }.
  20. Invocation records exist for success and failure cases.
  21. Evidence records show request validation, artifact verification, output production, and output validation.
  22. Effect records show local execution/blob-read/logging only.
  23. Denied capability attempts are recorded.
  24. Trace UI shows package hash, implementation hash, descriptor hash, request, output, trust record, capability grant, auth context, evidence, effects, and Station profile.
  25. Trace capsule export works.
  26. Trace capsule import works.
  27. Tampering with package, schema, claim, artifact, invocation, evidence, effect, or capsule integrity metadata is detected.
  28. Imported trust records do not automatically become active authority.
  29. No network, secret, native execution, remote storage, remote compute, decryption, signing, external service, central identity provider, telemetry, or same-origin package JavaScript is used by Hello World.
  30. CI builds the PWA and uploads/deploys the static artifact.
  31. Manual iOS checklist passes and is recorded.

Requirements covered by this ticket

Fully or materially implemented:

BENAC-CRYPTO-001 through BENAC-CRYPTO-006
BENAC-ID-001
BENAC-ID-003
BENAC-SIGN-001 through BENAC-SIGN-003
BENAC-AUTH-001 through BENAC-AUTH-003
BENAC-AUTH-007 through BENAC-AUTH-009
BENAC-AUTH-013 through BENAC-AUTH-015
BENAC-SYS-001 through BENAC-SYS-006
BENAC-DOC-001, BENAC-DOC-002, BENAC-DOC-004 through BENAC-DOC-007
BENAC-BLOB-001 through BENAC-BLOB-004
BENAC-BLOB-006, BENAC-BLOB-009, BENAC-BLOB-010
BENAC-PKG-001 through BENAC-PKG-008
BENAC-DESC-001 through BENAC-DESC-004
BENAC-TRUST-001 through BENAC-TRUST-005
BENAC-CAP-001 through BENAC-CAP-005
BENAC-EXEC-001 through BENAC-EXEC-007
BENAC-INV-001 through BENAC-INV-006
BENAC-EVD-001, BENAC-EVD-002
BENAC-EFF-001, BENAC-EFF-002
BENAC-AUD-001, BENAC-AUD-CRYPTO-001
BENAC-IO-001, BENAC-IO-003 through BENAC-IO-005
BENAC-INT-001 through BENAC-INT-005
BENAC-UX-001 through BENAC-UX-004, BENAC-UX-007
BENAC-AVL-001 through BENAC-AVL-003
BENAC-PERF-001
BENAC-SAFE-001, BENAC-SAFE-003 through BENAC-SAFE-005
BENAC-SEC-001 through BENAC-SEC-005 as negative/no-secret/no-telemetry guarantees
BENAC-AGT-001 through BENAC-AGT-006, BENAC-AGT-009, BENAC-AGT-010 as minimal local agent/session support

Explicitly deferred:

C2 replication
C3 remote storage
C3 remote compute
private blob encryption
large blob chunking
encrypted capsules
encrypted document envelopes
remote Station authentication
remote storage receipts
remote compute evidence
advanced storage/compute plan UX
native/container/GPU/device extension profiles
production key recovery

Reviewer checklist

A reviewer must reject the work if any of these are true:

Proposed resolution

C1 Hello World closeout complete. All six P0 items from the 2026-05-02T13:10:37Z rejection comment are addressed in the codebase, all cargo + conformance tests pass, the kernel dist still passes validate-pwa-dist (no /api/, no telemetry), and a real iPhone session captured the seven required acceptance event kinds via the bolt-on /acceptance/ instrumentation served by gravitational_lens. Server-recorded evidence at /srv/benac/.gravitational_lens/acceptance_events.ndjson; live at https://benac.benac.dev/acceptance/events. Detailed justification per P0 in the preceding handler comment.

History (30 events)

Sign in as a human to drive this ticket from the page, or use the MCP tools.

← all tickets · home