mirror of
https://github.com/ruvnet/RuView
synced 2026-06-09 10:13:17 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e469aa336 | |||
| d4f0e12073 |
@@ -87,6 +87,7 @@ Ranked by build cost × user impact:
|
||||
| 3 | **Local SONA fine-tuning loop** (HA feedback → LoRA gradient steps) | ~2-3 weeks | Reduces false positives, closes #1 user complaint | P5 (this cog) |
|
||||
| 4 | **HACS gold-tier integration** (config flow + repairs + diagnostics) | ~4-6 weeks | Removes MQTT prerequisite for mainstream users | P9 (separate repo `hass-wifi-densepose`) |
|
||||
| 5 | **Matter Bridge with OccupancySensor + dynamic endpoints** | ~6-8 weeks | Apple Home / Google Home / Alexa native | **v0.8** dedicated sprint (after HACS adoption data) |
|
||||
| 6 | **Embedded MQTT broker (rumqttd) inside the cog** | ~1 week | "Works without external broker" but every HA install already has mosquitto / built-in | **v0.7** deferred — adds ~2 MB binary + ACL config surface for marginal user benefit. Dossier ranking did not include this in the prioritised v1 scope. |
|
||||
|
||||
## 4. Implementation phases
|
||||
|
||||
@@ -95,7 +96,7 @@ Ranked by build cost × user impact:
|
||||
| **P1** | Research dossier ([`docs/research/ADR-116-ha-matter-cog-research.md`](../research/ADR-116-ha-matter-cog-research.md)) | ✅ **done** — 8 sections, 30+ citations, v1 scope ranked |
|
||||
| **P2** | Cog crate scaffold (`v2/crates/cog-ha-matter/`) — Cargo.toml + `src/{lib,main,manifest}.rs`, workspace member, CLI args, `--print-manifest` flag, 2 manifest unit tests | ✅ **done** — `cargo check` + `cargo test` green |
|
||||
| **P3** | Wrap existing ADR-115 MQTT publisher as cog entry point | ✅ **wiring done** — `main.rs` boots ADR-115's `publisher::spawn` via `runtime::spawn_publisher` thin wrapper, holds a long-lived `broadcast::Sender<VitalsSnapshot>`, awaits Ctrl-C. Live-handle test green without a broker. Next (P3.5): subscribe to sensing-server `/v1/snapshot` WS and republish into the channel. |
|
||||
| **P4** | Seed-native enhancements (embedded broker, mDNS, witness) | in progress — **mDNS half complete:** record-builder ✅, ServiceInfo conversion ✅, **live responder ✅** (`runtime::start_mdns_responder` binds multicast, registers, returns `MdnsResponderHandle` with explicit `shutdown()` + best-effort Drop). **Witness half complete:** hash-chain ✅, JSONL line serializer ✅, file persistence + chain-level verify ✅, Ed25519 signing ✅. **Remaining:** embedded rumqttd broker. |
|
||||
| **P4** | Seed-native enhancements (mDNS, witness; embedded broker deferred) | ✅ **shipped** — mDNS half: record-builder + ServiceInfo conversion + live responder wired into `main.rs` (HA auto-discovery on `_ruview-ha._tcp` works out of the box, `--no-mdns` flag for restrictive networks). Witness half: hash-chain + JSONL + file persistence + chain-level verify + Ed25519 signing. **Embedded rumqttd broker deferred to v0.7** per dossier §8 ranking — not in the prioritised v1 scope; v1 ships with external-broker only (mosquitto or HA's built-in broker). See §4 v1 scope table. |
|
||||
| **P5** | RuVector-backed threshold learning (SONA adaptation) | pending |
|
||||
| **P6** | Multi-Seed federation (cross-Seed dedup + witness) | pending |
|
||||
| **P7** | Matter Bridge mode (depends on matter-rs / esp-matter readiness) | pending |
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# Build / sign / upload pipeline for cog-ha-matter.
|
||||
# See ADR-100 §"Build pipeline" + ADR-116 §"Phases" for the contract.
|
||||
# Mirrors cog-pose-estimation/cog/Makefile so the Seed runtime treats
|
||||
# both cogs identically — `cognitum cog install ha-matter` works the
|
||||
# same as `cognitum cog install pose-estimation`.
|
||||
|
||||
CRATE := cog-ha-matter
|
||||
VERSION := $(shell cargo pkgid -p $(CRATE) 2>/dev/null | sed -E 's/.*#([0-9.]+).*/\1/')
|
||||
GCS_BUCKET := gs://cognitum-apps/cogs
|
||||
|
||||
ARCHES := arm x86_64
|
||||
|
||||
# --- Build targets ---
|
||||
|
||||
.PHONY: build build-arm build-x86_64
|
||||
|
||||
build: build-arm build-x86_64
|
||||
|
||||
build-arm:
|
||||
mkdir -p dist
|
||||
cargo build -p $(CRATE) --release --target aarch64-unknown-linux-gnu
|
||||
cp ../../target/aarch64-unknown-linux-gnu/release/$(CRATE) ./dist/cog-$(CRATE)-arm
|
||||
|
||||
build-x86_64:
|
||||
mkdir -p dist
|
||||
cargo build -p $(CRATE) --release --target x86_64-unknown-linux-gnu
|
||||
cp ../../target/x86_64-unknown-linux-gnu/release/$(CRATE) ./dist/cog-$(CRATE)-x86_64
|
||||
|
||||
# --- Sign ---
|
||||
|
||||
.PHONY: sign sign-arm sign-x86_64
|
||||
|
||||
sign: sign-arm sign-x86_64
|
||||
|
||||
sign-arm: dist/cog-$(CRATE)-arm
|
||||
sha256sum dist/cog-$(CRATE)-arm | cut -d' ' -f1 > dist/cog-$(CRATE)-arm.sha256
|
||||
# Signature: gcloud secrets versions access latest --secret=COGNITUM_OWNER_SIGNING_KEY \
|
||||
# | openssl pkeyutl -sign -inkey /dev/stdin -rawin -in dist/cog-$(CRATE)-arm.sha256 \
|
||||
# | base64 -w0 > dist/cog-$(CRATE)-arm.sig
|
||||
@echo "TODO: wire Ed25519 sign step once COGNITUM_OWNER_SIGNING_KEY is provisioned to CI."
|
||||
|
||||
sign-x86_64: dist/cog-$(CRATE)-x86_64
|
||||
sha256sum dist/cog-$(CRATE)-x86_64 | cut -d' ' -f1 > dist/cog-$(CRATE)-x86_64.sha256
|
||||
@echo "TODO: wire Ed25519 sign step once COGNITUM_OWNER_SIGNING_KEY is provisioned to CI."
|
||||
|
||||
# --- Upload to GCS ---
|
||||
|
||||
.PHONY: upload upload-arm upload-x86_64
|
||||
|
||||
upload: upload-arm upload-x86_64
|
||||
|
||||
upload-arm: dist/cog-$(CRATE)-arm
|
||||
gsutil cp dist/cog-$(CRATE)-arm $(GCS_BUCKET)/arm/cog-$(CRATE)-arm
|
||||
|
||||
upload-x86_64: dist/cog-$(CRATE)-x86_64
|
||||
gsutil cp dist/cog-$(CRATE)-x86_64 $(GCS_BUCKET)/x86_64/cog-$(CRATE)-x86_64
|
||||
|
||||
# --- Manifest ---
|
||||
|
||||
.PHONY: manifest
|
||||
|
||||
manifest:
|
||||
@cargo run -p $(CRATE) --release -- --print-manifest
|
||||
|
||||
# --- Convenience ---
|
||||
|
||||
.PHONY: release verify clean
|
||||
|
||||
release: build sign upload manifest
|
||||
@echo "Release pipeline complete for cog-$(CRATE) v$(VERSION)"
|
||||
|
||||
verify:
|
||||
@for arch in $(ARCHES); do \
|
||||
f=dist/cog-$(CRATE)-$$arch; \
|
||||
if [ ! -f $$f ]; then echo " MISSING $$f"; continue; fi; \
|
||||
actual=$$(sha256sum $$f | cut -d' ' -f1); \
|
||||
expected=$$(cat $$f.sha256 2>/dev/null); \
|
||||
if [ "$$actual" = "$$expected" ]; then echo " OK $$f ($$actual)"; \
|
||||
else echo " FAIL $$f (expected $$expected, got $$actual)"; fi; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -rf dist/cog-$(CRATE)-*
|
||||
@@ -0,0 +1,71 @@
|
||||
# HA-Matter Cog Packaging
|
||||
|
||||
Build / sign / upload pipeline for `cog-ha-matter`, mirroring the
|
||||
[`cog-pose-estimation`](../../cog-pose-estimation/cog/) precedent so the
|
||||
Seed runtime treats both cogs identically.
|
||||
|
||||
See [ADR-100 — Cog Packaging Specification](../../../../docs/adr/ADR-100-cog-packaging-specification.md)
|
||||
and [ADR-116 — HA-Matter Seed Cog](../../../../docs/adr/ADR-116-cog-ha-matter-seed.md).
|
||||
|
||||
## What this cog does
|
||||
|
||||
Wraps the ADR-115 HA-DISCO + HA-MIND MQTT publisher as a Seed-installable
|
||||
artifact with:
|
||||
|
||||
- mDNS auto-discovery (`_ruview-ha._tcp`)
|
||||
- Ed25519-signed witness chain for tamper-evident audit logs
|
||||
- Privacy-mode flag (only semantic primitives, no biometrics)
|
||||
- One-flag deferral to v0.7 for the embedded broker / v0.8 for the Matter Bridge
|
||||
|
||||
## Layout
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `manifest.template.json` | Build-time manifest with `{{VERSION}}` / `{{ARCH}}` slots; `make manifest` substitutes them |
|
||||
| `Makefile` | `build` / `sign` / `upload` / `release` / `verify` / `clean` targets |
|
||||
| `dist/` | Created by `make build`; gitignored, holds release binaries + sha256 + sig |
|
||||
|
||||
## Local build (dry-run)
|
||||
|
||||
```sh
|
||||
cd v2/crates/cog-ha-matter/cog
|
||||
make build # builds aarch64 + x86_64 release binaries
|
||||
make sign # writes .sha256 + (TODO) .sig sidecars
|
||||
make manifest # prints the manifest the Seed would record
|
||||
```
|
||||
|
||||
`make sign` is currently a no-op for the signature itself — the
|
||||
`COGNITUM_OWNER_SIGNING_KEY` provisioning is the same TODO that
|
||||
blocks [`cog-pose-estimation`](../../cog-pose-estimation/cog/Makefile).
|
||||
Until then, dev cogs ship unsigned and `app-registry.json` lists
|
||||
them with `"binary_signature": ""`.
|
||||
|
||||
## Upload (requires `gcloud auth`)
|
||||
|
||||
```sh
|
||||
gcloud auth login
|
||||
make upload # gsutil cp dist/* gs://cognitum-apps/cogs/{arch}/
|
||||
```
|
||||
|
||||
The GCS bucket is shared with `cog-pose-estimation` and is part of
|
||||
the `cognitum-apps` project. Write access requires membership in the
|
||||
`cog-publishers` IAM group.
|
||||
|
||||
## app-registry.json
|
||||
|
||||
Lives in the [`cognitum-one`](https://github.com/ruvnet/cognitum-one)
|
||||
repo, **not here**. After `make upload` succeeds, file a PR there
|
||||
that appends:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "ha-matter",
|
||||
"version": "<the version make manifest printed>",
|
||||
"binary_url": "https://storage.googleapis.com/cognitum-apps/cogs/{arch}/cog-ha-matter-{arch}",
|
||||
"binary_sha256": "<from dist/cog-cog-ha-matter-{arch}.sha256>",
|
||||
"binary_signature": "<from dist/cog-cog-ha-matter-{arch}.sig — empty until signing is wired>",
|
||||
"description": "Home Assistant + Matter Cognitum Seed cog (mDNS + witness chain)",
|
||||
"min_seed_version": "0.6.0",
|
||||
"installable_on": ["arm", "x86_64"]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "ha-matter",
|
||||
"version": "{{VERSION}}",
|
||||
"binary_url": "https://storage.googleapis.com/cognitum-apps/cogs/{{ARCH}}/cog-ha-matter-{{ARCH}}",
|
||||
"binary_bytes": 0,
|
||||
"binary_sha256": "",
|
||||
"binary_signature": "",
|
||||
"installed_at": 0,
|
||||
"status": "installed"
|
||||
}
|
||||
@@ -48,6 +48,24 @@ struct Args {
|
||||
/// control plane and exit. Useful for the build-time signer.
|
||||
#[arg(long)]
|
||||
print_manifest: bool,
|
||||
|
||||
/// mDNS hostname for the Seed advertisement. Must end with
|
||||
/// `.local.` per RFC 6762. Default lets HA's discovery find a
|
||||
/// dev cog on localhost without LAN config.
|
||||
#[arg(long, default_value = "cog-ha-matter.local.")]
|
||||
mdns_hostname: String,
|
||||
|
||||
/// LAN-routable IPv4 the cog binds the control plane on. The
|
||||
/// mDNS responder advertises this; HA reaches back to it for
|
||||
/// MQTT + Matter Bridge.
|
||||
#[arg(long, default_value = "127.0.0.1")]
|
||||
mdns_ipv4: String,
|
||||
|
||||
/// Skip the mDNS responder. Useful in containerised CI where
|
||||
/// multicast bind is filtered, or when running multiple cog
|
||||
/// instances on the same loopback.
|
||||
#[arg(long)]
|
||||
no_mdns: bool,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -115,6 +133,35 @@ async fn main() -> ExitCode {
|
||||
// HA install with no nodes online looks like.
|
||||
let _ = &state_tx;
|
||||
|
||||
// P4: mDNS responder. HA's auto-discovery picks the cog up on
|
||||
// `_ruview-ha._tcp` so users don't need to type broker host/port.
|
||||
let _mdns_handle = if args.no_mdns {
|
||||
None
|
||||
} else {
|
||||
let identity = runtime::CogIdentity::default_for_build();
|
||||
let service = cog_ha_matter::mdns::build_mdns_service(
|
||||
&identity,
|
||||
cog_ha_matter::DEFAULT_CONTROL_PORT,
|
||||
args.mqtt_port,
|
||||
args.privacy_mode,
|
||||
);
|
||||
match runtime::start_mdns_responder(&service, &args.mdns_hostname, &args.mdns_ipv4) {
|
||||
Ok(h) => {
|
||||
info!(
|
||||
fullname = h.fullname(),
|
||||
hostname = %args.mdns_hostname,
|
||||
ipv4 = %args.mdns_ipv4,
|
||||
"mDNS responder registered — HA auto-discovery should find the cog now"
|
||||
);
|
||||
Some(h)
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(error = ?e, "mDNS responder failed to start — discovery disabled, falling back to manual HA config");
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Wait on Ctrl-C so the cog runs as a long-lived daemon under
|
||||
// the Seed's process supervisor.
|
||||
tokio::select! {
|
||||
@@ -125,5 +172,8 @@ async fn main() -> ExitCode {
|
||||
warn!(?joined, "publisher task exited unexpectedly");
|
||||
}
|
||||
}
|
||||
|
||||
// _mdns_handle drops here, sending the mDNS goodbye packet so
|
||||
// HA's discovery integration sees the service leave cleanly.
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user