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
1 change: 1 addition & 0 deletions docs/TODO-unified.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ The Trust residential runs the **prod profile**, not the dev profile with dev mo
- `CORS_ALLOWED_ORIGINS`: **required on a LAN host.** Set it to the Trust box's own origin, for example `http://<host>:3001`; the compose default names the owner's public domain.
- Security profile: a production artefact may not bind with findings. Set `VISIONCLAW_SECURITY_PROFILE` (`src/config/security_profile.rs:596`) and the six flags that profile fixes (`:133-138`): `RBAC_PUBLIC_READS`, `RBAC_ALLOW_OWNERLESS`, `RBAC_OWNER_PUBKEY`, `RBAC_DEFAULT_ROLE`, `PUBKEY_VISIBILITY_FILTER=1` and `RBAC_GATE_MODE=enforce`. `single-tenant` or `multi-user-locked` both require `RBAC_OWNER_PUBKEY`.
- Optional, and empty by default: `VISIONCLAW_NOSTR_PRIVKEY` (bead provenance, `:234`). The binary also warns without `JWT_SECRET` and `CORS_ALLOWED_ORIGINS` (`src/main.rs:70`).
- Governance signing key (K_broker): **the Trust box mints its own and never copies one.** After the first start, run `visionclaw-server mint-nostr-key --out /app/data/keys/k_broker.key` inside the prod container (`/app/visionclaw-server`, on the `visionclaw-data` volume, under `umask 077`), and set `ACSP_PANEL_NOSTR_KEY_FILE` to that path in `.env.prod`. The command writes the secret at 0600, refuses to overwrite, and prints only the pubkey and `did:nostr`. The loader refuses a key file that group or other can read, and a key file beats any inline `ACSP_PANEL_NOSTR_PRIVKEY`/`VISIONCLAW_NOSTR_PRIVKEY` (`src/services/acsp/key_file.rs`). Register the printed pubkey in the Trust relay's `agent_registry`. Never paste a key from the owner's estate or from agentbox: those events would be signed by somebody else's identity (G-5, W8v).
- The headset's `XR_NOSTR_SECRET` must belong to an Owner or Admin key. HUD physics writes need `WriteSettings` (`src/middleware/rbac_gate.rs:169`), and an `editor` resolves only to `Authenticated` (`src/models/rbac.rs:87`).

**Forbidden.** `.env.prod` must not define `SETTINGS_AUTH_BYPASS`, `ALLOW_INSECURE_DEFAULTS`, `VISIONCLAW_DEV_MODE` or `DEV_AUTH_LOOPBACK`, even as `0`, in either ingress mode (`scripts/launch.sh:195`, host ADR-2119). The release binary refuses the same four (`src/config/security_profile.rs:59-64`). So the ADR-2039/2108 dev bypass cannot exist on Trust hardware, and headset writes must carry a NIP-98 signature (owner decision 2026-10-02, Q3).
Expand Down
6 changes: 5 additions & 1 deletion docs/adr/ADR-2004-oxigraph-sqlite-persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: complete
activation_status: live
supersedes: []
superseded_by: []
verified_commit: fdcbc9120fda25fd93fdaee744d68d2c00713d6b
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [Cargo.toml, src/app_state.rs]
owner: jjohare
review_trigger: a scale requirement that exceeds a single-node embedded store, or any proposal to reintroduce a networked graph database
Expand Down Expand Up @@ -201,3 +201,7 @@ sit beside is unchanged. `verified_commit` moved to the CI-repair commit.
## Re-verification — 2026-10-03 at fdcbc9120fda25fd93fdaee744d68d2c00713d6b

`1d3e14a30` and `fdcbc9120` change `Cargo.toml`: solid-pod-rs and its siblings move to `=0.5.0-alpha.12` with feature `mrc20`, and `nostr-bbs-core` is patched to nostr-rust-forum `b73ec8c` (ADR-2111, S4 amendment). No oxigraph, rusqlite or persistence feature changed, and `src/app_state.rs` is untouched. The decision holds unchanged.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`1e55daebb` drops the `[patch.crates-io]` git override for `nostr-bbs-core` from `Cargo.toml` in favour of the crates.io `=1.0.0-beta.13` pin. That changes no storage dependency. In `780eb3edb`, `src/app_state.rs` changes only the decision-projection client's key lookup (`:1362-1368`, now `load_panel_secret`). Oxigraph and the per-writer SQLite wiring are untouched. The decision holds.
6 changes: 5 additions & 1 deletion docs/adr/ADR-2005-hexagonal-crate-split.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: partial
activation_status: live
supersedes: []
superseded_by: []
verified_commit: fdcbc9120fda25fd93fdaee744d68d2c00713d6b
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [Cargo.toml, src/actors, crates/visionclaw-actors/src]
owner: jjohare
review_trigger: completion of the actor extraction into crates/visionclaw-actors, or a new subsystem that does not map to an existing crate layer
Expand Down Expand Up @@ -220,3 +220,7 @@ the root binary are unchanged. `verified_commit` moved to the CI-repair commit.
## Re-verification — 2026-10-03 at fdcbc9120fda25fd93fdaee744d68d2c00713d6b

`1d3e14a30` and `fdcbc9120` change `Cargo.toml` (the solid-pod-rs pin, feature `mrc20`, a `[patch.crates-io]` for `nostr-bbs-core`; ADR-2111, S4 amendment). Workspace members are unchanged, nothing moves between crates, and `src/actors` and `crates/visionclaw-actors/src` are untouched. The decision holds unchanged.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`1e55daebb` (`Cargo.toml`: the `nostr-bbs-core` git patch is removed and the crates.io pin used) leaves `[workspace].members` unchanged. In `780eb3edb`, `src/actors/elevation_actor.rs` and `decision_elevation_actor.rs` change only their panel-key lookup. The new loader is in the root `src/services/acsp/`, beside the ACSP client it serves. That adds nothing to the extraction backlog and moves nothing across a crate boundary. `implementation: partial` stands. The decision holds.
6 changes: 5 additions & 1 deletion docs/adr/ADR-2026-fail-closed-security-posture.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: complete
activation_status: live
supersedes: []
superseded_by: []
verified_commit: a32abac57f3a7cfe66ab68ea1b0faca013c0d6b2
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [src/middleware/rbac_gate.rs, src/main.rs, src/services/role_store.rs]
owner: jjohare
review_trigger: any new security-relevant env flag, or a request to soften the release boot-abort to a warning
Expand Down Expand Up @@ -172,3 +172,7 @@ line 170 are unmoved. `verified_commit` moved to the CI-repair commit.
**Governed changes since `997440cd0`:** `src/main.rs` changed only at the sync-service construction (`GitHubSyncService::new` now takes a `CorpusSource` from `source_from_env_with_github`, ADR-2114). `rbac_gate.rs` and `role_store.rs` are unchanged.

**Decision unaffected.** No security flag was added, read or defaulted; `enforce_release_env_hygiene` and the fail-closed boot order are untouched. `verified_commit` moved to the CI-repair commit.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`780eb3edb` (W8v, VisionClaw's own K_broker) inserts eight lines at `src/main.rs:195-202`: `visionclaw-server mint-nostr-key --out <path>` is dispatched first and exits. That path loads no `.env`, reads no environment, binds no listener, and rejects every argument other than `--out`/`--help` with exit 2, so `--allow-skip-auth` cannot ride along. Every path that serves still runs `enforce_release_env_hygiene()` (now `:209`) and `assert_effective_profile_or_exit` (now `:931`) before `HttpServer::new` (`:951`) and `.bind()` (`:1232`). Every `main.rs` citation after `:195` in this record moves down by eight lines. The new panel-key loader (`src/services/acsp/key_file.rs`) also fails closed: a key-file variable that is set but unusable, such as a file that group or other can read, disables the signers and never falls through to an inline key. `rbac_gate.rs` and `role_store.rs` are unchanged. The decision holds. Tests: `--lib key_file` 14, `--test mint_nostr_key_cli` 2.
6 changes: 5 additions & 1 deletion docs/adr/ADR-2027-three-deployment-profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: partial
activation_status: live
supersedes: []
superseded_by: []
verified_commit: 920401379719cff87023be5bab6c7c6233fc63ed
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [src/config/security_profile.rs, src/middleware/rbac_gate.rs, src/main.rs, src/services/role_store.rs, src/handlers/socket_flow_handler/position_updates.rs, docker-compose.unified.yml]
owner: jjohare
review_trigger: adding a fourth profile, machine-selecting a profile at boot, or changing a compose security default
Expand Down Expand Up @@ -309,3 +309,7 @@ moved down by six lines. `verified_commit` moved to the CI-repair commit.
**Governed changes since `b39b1a626`:** `docker-compose.unified.yml` moved the `cloudflared` service from the `production`/`prod` profiles to its own `tunnel` profile (host ADR-2119).

**Decision unaffected.** No compose security default moved: `VISIONCLAW_DEV_MODE`, the `RBAC_*` flags and the profile selection are as before; the change is ingress, not security posture. `verified_commit` moved to `920401379`.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`780eb3edb` (W8v, VisionClaw's own K_broker) inserts eight lines at `src/main.rs:195-202`: `visionclaw-server mint-nostr-key --out <path>` is dispatched first and exits. That path loads no `.env`, reads no environment, binds no listener, and rejects every argument other than `--out`/`--help` with exit 2, so `--allow-skip-auth` cannot ride along. Every path that serves still runs `enforce_release_env_hygiene()` (now `:209`) and `assert_effective_profile_or_exit` (now `:931`) before `HttpServer::new` (`:951`) and `.bind()` (`:1232`). Every `main.rs` citation after `:195` in this record moves down by eight lines. No profile flag, selector or compose service changed. The decision holds.
6 changes: 5 additions & 1 deletion docs/adr/ADR-2037-production-build-excludes-dev-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: partial
activation_status: staged
supersedes: []
superseded_by: []
verified_commit: 920401379719cff87023be5bab6c7c6233fc63ed
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [src/config/security_profile.rs, src/main.rs, .github/workflows/ci.yml, Dockerfile.production]
owner: jjohare
review_trigger: any change to the production Dockerfile build line, the dev-auth feature gates, or enforce_release_env_hygiene
Expand Down Expand Up @@ -144,3 +144,7 @@ that run was red. `verified_commit` moved to the CI-repair commit.
**Governed changes since `a32abac57`:** `.github/workflows/ci.yml` adds the `prod_ingress` target to the hermetic integration-contract step (host ADR-2119). The `dev-auth-release-gate` job is untouched. In the same commit `scripts/launch.sh` (`:195`) also refuses `DEV_AUTH_LOOPBACK` in `.env.prod`, so its list now matches the release binary's four `FORBIDDEN_DEV_VARS`, in LAN and tunnel ingress alike.

**Decision unaffected.** `verified_commit` moved to `920401379`.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`780eb3edb` (W8v, VisionClaw's own K_broker) inserts eight lines at `src/main.rs:195-202`: `visionclaw-server mint-nostr-key --out <path>` is dispatched first and exits. That path loads no `.env`, reads no environment, binds no listener, and rejects every argument other than `--out`/`--help` with exit 2, so `--allow-skip-auth` cannot ride along. Every path that serves still runs `enforce_release_env_hygiene()` (now `:209`) and `assert_effective_profile_or_exit` (now `:931`) before `HttpServer::new` (`:951`) and `.bind()` (`:1232`). Every `main.rs` citation after `:195` in this record moves down by eight lines. The subcommand is the same in every feature closure, and nothing in it is gated on `dev-auth`. `security_profile.rs`, `ci.yml` and `Dockerfile.production` are unchanged. The decision holds.
6 changes: 5 additions & 1 deletion docs/adr/ADR-2038-boot-time-profile-assertion.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: partial
activation_status: live
supersedes: []
superseded_by: []
verified_commit: a32abac57f3a7cfe66ab68ea1b0faca013c0d6b2
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [src/config/security_profile.rs, src/main.rs]
owner: jjohare
review_trigger: adoption of a production deployment, or any change to the profile env vars (RBAC_PUBLIC_READS, PUBKEY_VISIBILITY_FILTER, RBAC_DEFAULT_ROLE)
Expand Down Expand Up @@ -281,3 +281,7 @@ CI-repair commit.
**Governed changes since `997440cd0`:** `src/main.rs` changed only at the sync-service construction (ADR-2114 `CorpusSource`).

**Decision unaffected.** The boot-time profile assertion and its illegal-combination abort are not on the changed lines. `verified_commit` moved to the CI-repair commit.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`780eb3edb` (W8v, VisionClaw's own K_broker) inserts eight lines at `src/main.rs:195-202`: `visionclaw-server mint-nostr-key --out <path>` is dispatched first and exits. That path loads no `.env`, reads no environment, binds no listener, and rejects every argument other than `--out`/`--help` with exit 2, so `--allow-skip-auth` cannot ride along. Every path that serves still runs `enforce_release_env_hygiene()` (now `:209`) and `assert_effective_profile_or_exit` (now `:931`) before `HttpServer::new` (`:951`) and `.bind()` (`:1232`). Every `main.rs` citation after `:195` in this record moves down by eight lines. The assertion is still unconditional on every path that binds. The mint path never reaches a bind, so it needs no profile. `security_profile.rs` is unchanged. The decision holds.
6 changes: 5 additions & 1 deletion docs/adr/ADR-2042-vault-migrate-converter.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: partial
activation_status: live
supersedes: []
superseded_by: [ADR-2113]
verified_commit: fdcbc9120fda25fd93fdaee744d68d2c00713d6b
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [crates/vault-migrate, Cargo.toml, docs/VAULT-corpus-format.md]
owner: jjohare
review_trigger: the in-place conversion of the corpus repo is committed, after which the crate is kept only as the round-trip/no-op checker
Expand Down Expand Up @@ -147,3 +147,7 @@ graph.
## Re-verification — 2026-10-03 at fdcbc9120fda25fd93fdaee744d68d2c00713d6b

`1d3e14a30` and `fdcbc9120` change `Cargo.toml` (the solid-pod-rs pin, feature `mrc20`, a `[patch.crates-io]` for `nostr-bbs-core`; ADR-2111, S4 amendment). None of it concerns the converter this superseded record describes, and `crates/vault-migrate` and `docs/VAULT-corpus-format.md` are untouched. Nothing to re-decide.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`1e55daebb` removes the `nostr-bbs-core` `[patch.crates-io]` from `Cargo.toml`, which the 2026-10-03 note above covered. It does not concern this superseded converter, and `docs/VAULT-corpus-format.md` is untouched. Nothing to re-decide.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: partial
activation_status: live
supersedes: []
superseded_by: []
verified_commit: fdcbc9120fda25fd93fdaee744d68d2c00713d6b
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [src/services/ontology_generation.rs, .github/workflows/ontology-publish.yml, src/services/ontology_pull.rs, src/main.rs, scripts/ontology/pack-pod-resources.py, client/src/features/ontology/services/jss/contextLoader.ts, client/src/features/ontology/services/jss/schemaParser.ts, env.example]
owner: jjohare
review_trigger: A pod that becomes reachable from CI (self-hosted runner or public endpoint); a change to the /public/ontology/ resource set; the release channel moving off GitHub (e.g. to the Loom or narrativegoldmine.com).
Expand Down Expand Up @@ -156,3 +156,7 @@ moved to the CI-repair commit.
## Re-verification — 2026-10-03 at fdcbc9120fda25fd93fdaee744d68d2c00713d6b

`1d3e14a30` adds `inherited: false` to the `AclDocument` literal in `public_read_acl` (`src/services/ontology_pull.rs`), the field solid-pod-rs 0.5.0-alpha.12 added. The document is the container's own sidecar, so `false` is its meaning, and it is never serialised. The ACL the pull writes is byte-identical. Tests: `cargo test -p visionclaw-server --lib -- ontology_pull ontology_generation` (16 pass). The decision holds unchanged.

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`780eb3edb` inserts the eight-line `mint-nostr-key` dispatch at `src/main.rs:195-202`, ahead of `.env` loading. The boot pull and `init_solid_state` are untouched, and they move down by eight lines. The other governed paths are unchanged. The decision holds.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ implementation_status: complete
activation_status: staged
supersedes: []
superseded_by: []
verified_commit: 3fd97572ad2433f195f5b98a8987355af4c18881
verified_commit: 780eb3edb788c9cb568d5756689a3c8455db79b7
verified_paths: [src/services/intent_match.rs, src/services/kpi_compute.rs, src/actors/elevation_actor.rs, src/adapters/sqlite_kpi_repository.rs, src/adapters/sqlite_enrichment_repository.rs, src/handlers/broker_inbox_handler.rs, client/src/features/control-center/governance/brokerCaseQueue.ts, client/src/features/control-center/governance/AcspCaseQueue.tsx]
owner: jjohare
review_trigger: The forum half of EXP-AC-002/004/006 landing, or the first live case queue with real decided cases
Expand Down Expand Up @@ -335,3 +335,7 @@ and the owner's live high-tier 31403 (cycle exit item 4) has not happened. It
moves to `live` on that receipt. The high-tier case for it is
`solid-pod-rs-1.0.0-beta.1-release-20261002` on the agentbox-release-ops panel,
raised 2026-10-02 (owner decision Q7).

## Re-verification — 2026-10-03 at 780eb3edb788c9cb568d5756689a3c8455db79b7

`780eb3edb` changes only how `src/actors/elevation_actor.rs` obtains its panel secret, at `:199-206`. It now goes through `services::acsp::key_file::load_panel_secret`, so a 0600 key file named by `ACSP_PANEL_NOSTR_KEY_FILE` wins over the inline env value, and an unusable file disables the actor with a logged error. Case handling, the approve path and the relay-admission trust noted in Consequences item 2 are unchanged. The other seven governed paths are unchanged. The decision holds. Tests: `--lib elevation` 62 pass.
4 changes: 3 additions & 1 deletion docs/explanation/agent-control-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ relay's `agent_registry` before any publish succeeds. The client logs the pubkey
at startup; a relay admin registers it via the NIP-98-gated
`POST /api/governance/agents/register`. Until then every publish is rejected with
`blocked: pubkey not in agent registry`. Signing uses a dedicated panel keypair
(`ACSP_PANEL_NOSTR_PRIVKEY`, falling back to `VISIONCLAW_NOSTR_PRIVKEY`) so that
(VisionClaw's own K_broker, minted by `visionclaw-server mint-nostr-key` and read
from `ACSP_PANEL_NOSTR_KEY_FILE`; the inline `ACSP_PANEL_NOSTR_PRIVKEY` and
`VISIONCLAW_NOSTR_PRIVKEY` remain as fallbacks) so that
panel production can be rate-limited and revoked independently of bead
provenance. The whole producer is env-gated — `FORUM_RELAY_URL` plus a signing
key present, with each actor behind its own flag (`ELEVATION_ACTOR_ENABLED=1`).
Expand Down
22 changes: 21 additions & 1 deletion docs/how-to/operations/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,28 @@ lifecycle with retry, outcome classification, and learning capture (see
[ADR-034](../../archive/adr/ADR-034-needle-bead-provenance.md) and
[PRD](../../archive/prd/prd-bead-provenance-upgrade.md)).

VisionClaw mints its own signing key; never copy one from another service.
Mint it inside the container, onto the persistent `visionclaw-data` volume:

```bash
docker exec visionclaw_container sh -c 'umask 077 && mkdir -p /app/data/keys && \
/app/target/dev-runtime/visionclaw-server mint-nostr-key --out /app/data/keys/k_broker.key'
```

(On the production image the binary is `/app/visionclaw-server` and the container
is `visionclaw_prod_container`.) The command writes the hex secret to a new file
at mode 0600, refuses to overwrite an existing file, and prints only two lines:
the x-only public key in hex and its `did:nostr:<hex>`. The secret is never
printed. Register that public key in the forum relay's `agent_registry`.

```bash
# Bridge bot private key (64-char hex). Generate with: openssl rand -hex 32
# Governance / ACSP panel signing key (kinds 31400-31405, decision projection,
# voice mandates). A key FILE wins over any inline key; see the reference.
ACSP_PANEL_NOSTR_KEY_FILE=/app/data/keys/k_broker.key

# Bead-provenance bridge key (64-char hex), read inline only by
# nostr_bridge.rs / nostr_bead_publisher.rs. Also the last-resort fallback for
# the panel key when no key file and no ACSP_PANEL_NOSTR_PRIVKEY is set.
VISIONCLAW_NOSTR_PRIVKEY=<64-char hex secret key>

# JSS integrated Nostr relay (default shown — matches docker-compose service name)
Expand Down
Loading
Loading