feat(spaces): add spatial memory and governed actions (#1650)

This commit is contained in:
rUv
2026-08-19 13:23:29 -04:00
committed by GitHub
parent d36f346bba
commit c929bbc8b3
28 changed files with 3192 additions and 94 deletions

View File

@@ -1,6 +1,6 @@
# ADR-325: Cognitum Spaces activation and governed spatial exchange
- **Status**: Accepted — read path implemented; write path remains policy-gated
- **Status**: Accepted — legacy read live; versioned hierarchy, local memory, and governed-action implementation validated on feature branches; deployment pending
- **Date**: 2026-08-17
- **Deciders**: ruv
- **Tags**: cognitum-spaces, oauth, spatial-state, privacy, ruvector, policy, autogenous
@@ -423,10 +423,43 @@ Identity metadata deliberately advertises `spaces:read` for RuView but not
publisher surface. RuView therefore has no OAuth write, command, policy-approval,
or actuator capability.
This evidence does not claim implementation of sites/buildings/floors/zones,
entities, semantic event or alert resources, tenant-scoped RuVector spatial
history, MQTT reconciliation, governed actions, commands, or actuators. Those
remain separately reviewed milestones.
This production evidence does not claim deployment of sites/buildings/floors/
zones, entities, semantic event or alert resources, tenant-scoped RuVector
spatial history, MQTT reconciliation, governed actions, commands, or actuators.
The first three are implemented and locally validated in the 2026-08-19 feature
branches described below, but remain non-production until their workflow and
readback gates pass. Commands and actuators remain out of scope.
## Feature-branch implementation evidence (2026-08-19)
- Cognitum API ADR-101 implements all eight `/v1/spatial` collections, coherent
transactional hierarchy checks, stable pagination, event/alert retention,
strict P2/P3 admission, API-key-only writes, and OAuth/API-key reads. The
Firestore emulator passed both the legacy and versioned verification scripts,
including cross-resource message replay denial.
- `ruview-cognitum-spaces` adds a strictly decoded, paged, read-only client for
every versioned collection. `wifi-densepose spaces --resource ...` exposes it
while preserving the legacy flat command. The focused client suite and the
CLI no-default-features test gate pass.
- The contributor metaharness now accepts `resource`, `limit`, and opaque
`cursor` on `ruview_spaces_list`, fixes the API origin, strips API-key
compatibility authority, and revalidates hierarchy/event/alert contracts.
Full metaharness, security, brain, flywheel, manifest, audit, and pack gates
pass for the `@ruvnet/ruview` 0.5.0 release candidate.
- ADR-326 adds `ruview-spatial-memory`: one RuVector HNSW index per authenticated
tenant/workspace, replay/derivation/retention gates, cascading erasure,
bounded explanations, and XChaCha20-Poly1305 snapshots with reload-verified
key rotation. Its focused crate suite passes with `SYNTHETIC` evidence.
- ADR-327 extends `ruview-policy` with typed observe/recommend/execute intents,
exact host grants, signed approvals, nonce/idempotency defense, the existing
ADR-321 assurance matrix, and signed hash-chained receipts. `spaces:read` is
explicitly denied as execution authority. Its focused crate suite passes.
- The required whole-workspace Rust command was attempted twice on Windows:
parallel compilation ended in a compiler-process stack-buffer-overrun and a
single-job retry reached the configured timeout without a source/test
diagnostic. This is not recorded as a green gate; Linux CI remains required.
- No OAuth write/action scope, actuator callback, MQTT deployment claim, sensing
accuracy claim, or real-hardware claim is introduced.
## Consequences
@@ -445,8 +478,8 @@ remain separately reviewed milestones.
- Two credential types coexist during migration and must stay visibly distinct.
- OAuth depends on Identity JWKS availability and correct key rotation.
- The current API exposes spaces only; the full hierarchy/events/alerts model
remains staged work.
- Production currently exposes the legacy spaces slice; the implemented full
hierarchy/events/alerts model remains staged until deployment/readback.
- OAuth workspace IDs will return only documents populated with `workspaceId`;
legacy owner-only documents require an explicit migration, never a broad query.
- The RuView client exposes no write, command, or agent execution surface. The

View File

@@ -0,0 +1,137 @@
# ADR-326: Tenant-scoped RuVector spatial memory and anomaly explanations
- **Status**: Accepted — implementation complete; repository-wide and deployment gates pending
- **Date**: 2026-08-19
- **Decision owners**: RuView maintainers
- **Extends**: ADR-312, ADR-319, ADR-325
- **Implements**: ruvnet/RuView#1640
- **Tags**: cognitum-spaces, ruvector, memory, tenant-isolation, explanation, privacy
## Context
ADR-325 requires anomaly explanations grounded in tenant-local spatial history,
but the deployed client only returns a current list. A global vector index would
be unsafe: filtering nearest-neighbor results after the search can reveal that a
different tenant has a close match, even when identifiers are removed. A memory
record can also launder returned RuView-derived state into a second independent
observation, reset freshness, or form circular evidence.
Spatial memory must be useful without storing OAuth/API credentials, raw CSI/CIR,
RF tensors, pose frames, vital waveforms, recordings, identity observations, or
unbounded agent transcripts. Persistence also needs explicit retention,
deletion, provenance, and key-rotation behavior.
## Decision
### 1. Partition before similarity
`ruview-spatial-memory` owns a `SpatialMemory` map keyed by the exact authenticated
`(tenant_id, workspace_id)` pair. Each partition owns its own RuVector HNSW index.
Ingest and search resolve the partition first; no global ANN query exists. Site,
space, schema version, and time-window constraints narrow within the selected
partition before results are returned.
### 2. Bounded semantic records
An accepted record contains:
- tenant/workspace/site/space and stable record identity;
- source ID, message ID, record ID, monotonic event sequence, schema version;
- original `observed_at`/`expires_at` and a retention deadline;
- a bounded finite semantic feature vector, uncertainty, and evidence label;
- provenance and witness digests, plus bounded derivation references;
- explicit observation/inference classification.
Credentials and P0/P1 fields have no representation in the type. Strings,
features, references, record counts, and query `k` are bounded. Non-finite
features and uncertainty fail closed.
### 3. Lineage and replay
The partition rejects:
- changed reuse of `(source_id, message_id)`;
- a non-increasing sequence for the same source;
- duplicate derivation references;
- self-reference, missing/forward parents, and therefore every cycle;
- expired input or a provenance/witness substitution.
A recollection keeps its original lineage, timestamp, uncertainty, and evidence
label. It cannot increment corroborating-source count or become independent
support for its own ancestor.
### 4. Persistent encrypted storage
Snapshots are encrypted with XChaCha20-Poly1305 under a caller-supplied 256-bit
key and a non-secret key ID. The authenticated associated data binds the storage
format and key ID. The envelope is bounded and versioned; plaintext spatial
records are never written to disk. Loading requires a keyring containing the
named key. Rotation decrypts with the old key, atomically creates a new
generation under the new key ID, reload-verifies that generation, and leaves
the source intact. Snapshots never overwrite an existing path implicitly.
Deletion supports a tenant/workspace partition, a record, and retention cutoff.
Every deletion rebuilds that partition's HNSW index so removed records cannot be
returned from stale graph nodes.
### 5. Explanations
`explain` compares a bounded query vector with nearest tenant-local history and
returns the exact authenticated partition, generation time, ordered record IDs,
RuVector distances, original uncertainty/evidence labels, and provenance/witness
digests. Its basis explicitly says that similarity is not causation. The API
does not expose the vectors or invent a causal explanation.
History provides context, not authority. An explanation cannot authorize an
action, increase certificate class, or replace a policy decision.
## Consequences
### Positive
- Cross-tenant ANN leakage is structurally unavailable.
- Explanations cite the exact tenant-local records used.
- Replay/cycle/provenance substitution are rejected before indexing.
- Encrypted persistence has explicit key IDs and rotation behavior.
### Costs and limitations
- Partition-local HNSW uses more indexes than a global graph.
- Deletes and key rotation rebuild indexes.
- No detection-quality or latency claim is made; tests are `SYNTHETIC` unless a
reproducer explicitly marks a measurement.
- Cloud Cognitum does not receive the local encrypted memory file.
## Validation
- cross-tenant and cross-workspace nearest-neighbor denial;
- duplicate record/message, stale-sequence, self/duplicate/missing-parent, and
provenance-substitution tests;
- expiry, retention deletion, whole-partition deletion, sealed round-trip,
tamper rejection, wrong-key rejection, and key-rotation tests;
- explanation citations and retained evidence/provenance labels;
- no forbidden raw-field or credential representation;
- the focused `ruview-spatial-memory` crate suite passes with `SYNTHETIC`
evidence on 2026-08-19;
- the whole-workspace Windows gate was non-terminal (compiler crash in parallel,
timeout when serialized), so Linux CI, a RustSec advisory scan, and package
review remain release gates.
## Alternatives considered
**One global HNSW followed by filtering.** Rejected: ranking itself crosses the
tenant boundary.
**Cloud vector memory.** Rejected as the default: it expands the privacy and
credential boundary without being needed for local explanations.
**Plain JSONL persistence.** Rejected because tenant spatial history is sensitive
even when raw sensing is excluded.
## References
- ADR-312: Long-term spatial memory
- ADR-319: Witness chain
- ADR-325: Cognitum Spaces activation and governed exchange
- Cognitum API ADR-101
- ruvnet/RuView#1640

View File

@@ -0,0 +1,133 @@
# ADR-327: Governed action intents, approvals, replay protection, and witness receipts
- **Status**: Accepted — implementation complete; repository-wide and deployment gates pending
- **Date**: 2026-08-19
- **Decision owners**: RuView maintainers
- **Extends**: ADR-318, ADR-319, ADR-321, ADR-325
- **Implements**: ruvnet/RuView#1641
- **Tags**: policy, governed-action, approval, idempotency, witness, cognitum-spaces
## Context
The current `ruview-policy` crate evaluates assurance for an action class, but it
does not define a complete action intent, tenant/workspace binding, policy
version, approval, nonce/idempotency replay behavior, or signed terminal receipt.
An agent recommendation can therefore be mistaken for execution authority, and
`spaces:read` could be accidentally treated as a general capability.
The system needs a framework that can prove why an action was allowed or denied
without adding any actuator. Real actuation remains a separate integration and
requires its own threat model and device evidence.
## Decision
### 1. Typed intent and registered policy
A governed `ActionIntent` binds:
- intent ID, tenant, workspace, action name/class, and exact target;
- requested policy version and parameter/evidence digests;
- creation/expiry, replay nonce, and requesting principal;
- the recommendation/explanation that motivated review, never a hidden command.
The gate accepts only a registered action policy. Unknown action, action-class
mismatch, policy-version mismatch, target mismatch, invalid timestamps, and
missing exact host authority deny before assurance is evaluated. Tenant and
workspace are part of the signed intent/receipt and nonce key. `spaces:read` is
explicitly tested as insufficient for an `alerts:execute` rule.
### 2. Assurance and approval
The existing ADR-321 certificate/domain/uncertainty/evidence gate remains the
assurance authority. The registered policy declares a bounded minimum of
distinct enrolled approvers. An absent, rejected, duplicated, expired,
wrong-intent, wrong-policy-version, or unverifiable approval denies. Approval
resolution fails closed.
Agents observe, explain, or recommend by default. `evaluate` returns a decision
receipt; it does not call an actuator. An executor may consume an `allow` receipt
only if a separate adapter verifies the receipt, target, expiry, and its own
device-specific authority.
### 3. Replay and idempotency
The bounded in-memory gate stores terminal receipts by intent ID and tracks
nonces by `(tenant, workspace, nonce)`.
- exact intent replay returns the original terminal receipt;
- changed reuse of an intent ID returns a fail-closed idempotency error;
- reuse of a nonce by another intent returns a fail-closed replay error;
- expired intents and approvals deny;
- failed or denied attempts are terminal and auditable.
The current state store is bounded and in-memory, intended for local/runtime use
rather than cross-process replay protection. A production executor must place
the same intent/nonce/receipt invariants behind a transactional durable store;
this ADR does not claim that adapter exists.
### 4. Witnessed terminal receipt
Every evaluated observe/recommend/execute request produces a canonical receipt
containing the intent digest, decision/reason, policy version, tenant/workspace,
decision/expiry time, intent ID and nonce, approval count, and previous receipt
digest. The receipt is signed through the `ruview-attest` signer interface and
can be independently verified. Hash chaining makes removal/reordering visible.
Malformed input, ID conflict, nonce replay, capacity exhaustion, and sequence
exhaustion are errors before receipt creation and must be audited by the host.
The reference keyed-BLAKE3 signer remains `SYNTHETIC` evidence only, as documented
by ADR-319. Production asymmetric signing and key custody must be supplied by the
deployment adapter; no symmetric test MAC is represented as hardware identity.
## Consequences
### Positive
- Recommendation, authorization, and execution are distinct typed stages.
- Default-deny covers missing policy, stale evidence, unavailable approval, and replay.
- Every decision has a terminal, verifiable explanation.
- `spaces:read` cannot silently expand into consequence.
### Costs and limitations
- Executors must implement a separate receipt-verifying adapter.
- Distributed replay protection needs a transactional durable store.
- This ADR implements no actuator, command transport, pairing mutation, or device control.
- Simulator tests are not hardware validation.
## Validation
- unknown/missing policy, stale intent, policy-version/target mismatch,
insufficient authority, and `spaces:read`-only denial;
- certificate/domain/uncertainty/evidence denial matrix from ADR-321;
- missing/rejected/expired/duplicate/wrong-intent approval tests;
- exact idempotent replay, changed reuse, nonce replay, and bounded-store tests;
- receipt signature, canonical digest, chain linkage, and tamper rejection;
- tests proving evaluation exposes no actuator callback or network/file side effect.
The focused `ruview-policy` suite passes on 2026-08-19. The reference signer
tests are `SYNTHETIC`; they are not hardware-identity evidence. The non-terminal
whole-workspace Windows gate still requires authoritative Linux CI evidence.
Any future actuator adds a separate ADR, credential boundary, failure/rollback
plan, allow/deny integration tests, and captured target-device evidence.
## Alternatives considered
**Let agents call actuators after a recommendation.** Rejected: recommendation
quality is not authorization.
**Treat OAuth scopes as action policy.** Rejected: `spaces:read` expresses read
consent only and carries no target-specific assurance or approval.
**Emit receipts only for successful actions.** Rejected: denial and unavailable
approval are security-relevant terminal facts.
## References
- ADR-318: Capability certificates
- ADR-319: Witness chain
- ADR-321: Decision policy action authorization
- ADR-325: Cognitum Spaces activation and governed exchange
- ADR-326: Tenant-scoped RuVector spatial memory
- ruvnet/RuView#1641

View File

@@ -22,6 +22,7 @@ WiFi DensePose turns commodity WiFi signals into real-time human pose estimation
- [ESP32-S3 (Full CSI)](#esp32-s3-full-csi)
- [ESP32 Multistatic Mesh (Advanced)](#esp32-multistatic-mesh-advanced)
- [Connect Mesh Data to the Dashboard and Observatory](#connect-mesh-data-to-the-dashboard-and-observatory)
- [Cognitum Spaces activation](#cognitum-spaces-activation)
- [Cognitum Seed Integration (ADR-069)](#cognitum-seed-integration-adr-069)
5. [REST API Reference](#rest-api-reference)
6. [WebSocket Streaming](#websocket-streaming)
@@ -425,6 +426,57 @@ curl http://localhost:3000/api/v1/sensing/latest
If the ESP32 nodes are provisioned with `--target-ip <AGGREGATOR_HOST>`, that IP must be the machine running `sensing-server`. Only one process can receive UDP `:5005` at a time, so leave the standalone hardware `aggregator` off while the dashboard or Observatory is live.
### Cognitum Spaces activation
Cognitum Spaces gives RuView a tenant/workspace-scoped semantic world model
without uploading raw RF/CSI, recordings, pose frames, vital waveforms, or
identity observations. It represents sites, buildings, floors, bounded
rooms/spaces, zones, anonymous entities, semantic events, and alerts.
Activate the public RuView OAuth client with Authorization Code + PKCE:
```bash
wifi-densepose login --spaces
wifi-densepose whoami
wifi-densepose spaces --resource sites --limit 50
wifi-densepose spaces --resource events --limit 25
```
The login requests `sensing:read spaces:read`. That consent is read-only: it
does not grant publication, pairing, policy approval, command, or actuator
authority. Versioned collections are `sites`, `buildings`, `floors`,
`spaces`, `zones`, `entities`, `events`, and `alerts`. A returned
`nextCursor` is opaque and valid only for the same collection.
The dependency-free contributor harness exposes the same read path:
```bash
npx @ruvnet/ruview@0.5.0 spaces --resource alerts --limit 25
npx @ruvnet/ruview@0.5.0 mcp start
```
Its MCP tool is `ruview_spaces_list`. MCP reads are OAuth-only, use the fixed
Cognitum API origin, and require the explicit guarded-tool opt-in. The harness
does not accept an arbitrary credential path or API origin.
For service compatibility, `wifi-densepose spaces` can read
`COGNITUM_SPACES_API` at request time. API-key access to a versioned collection
also requires `--workspace <uuid>`; OAuth derives the workspace from the
signed token. Never print or commit either credential.
Every response is bounded and revalidated. Raw-sensing aliases, malformed
hierarchy, non-anonymous person/track entities, invalid timestamps, stale
confidence, and oversized structures fail closed. Empty data means no
authorized state is present; it does not prove that a physical site is empty.
RuVector spatial memory remains physically separated by tenant and workspace.
Agents observe or recommend by default. Any consequential execution requires a
separate policy/grant/approval decision and produces a signed, hash-chained
receipt; the Spaces read token can never satisfy that gate.
See ADR-325, ADR-326, and ADR-327 for the activation, memory, and governed-action
decisions.
### Cognitum Seed Integration (ADR-069)
Connect an ESP32-S3 to a [Cognitum Seed](https://cognitum.one) (Pi Zero 2 W, ~$15) for persistent vector storage, kNN similarity search, cryptographic witness chain, and AI-accessible sensing via MCP proxy.