mirror of
https://github.com/ruvnet/RuView
synced 2026-08-09 20:21:43 +00:00
56265023dc
cron iter 1. Three things landed atomically because they cross-cite:
P1 — research dossier complete
Deep-researcher agent (a4dd35950ffd) shipped
docs/research/ADR-116-ha-matter-cog-research.md: 8 sections,
30+ citations across Matter / HACS / cog arch / local-AI /
federation / competitors / regulatory / v1 scope. Key
findings folded into ADR-116 §3 and §4:
- Matter device class: OccupancySensor (0x0107) +
RFSensing feature on cluster 0x0406 (1.4 rev 5)
- ESP32-C6 Thread Border Router: one Kconfig flag away
(CONFIG_OPENTHREAD_BORDER_ROUTER=y)
- HACS quality tier: target Gold (repairs + diagnostics +
reconfiguration), start from hacs.integration_blueprint
- CSA cert: ~$30-42k/yr — skip for v1, "Works with HA"
positioning instead
- Cog RAM/CPU: 128 MB / 15% on the Seed; 10 KB INT8
semantic-primitive classifier fits without PSRAM
- SONA: <100 µs/query confirmed by ruvllm-esp32 v0.3.3
- FDA Jan 2026 wellness guidance covers HR / sleep / activity
anomaly when marketed as "anomaly notification" not "diagnosis"
- Competitor moat: Aqara FP300 / TOMMY / ESPectre all lack
HR + BR + pose + semantic + witness simultaneously
P2 — cog crate scaffold compiles
v2/crates/cog-ha-matter/ created with cog-pose-estimation as
precedent shape (ADR-101). Files:
- Cargo.toml: depends on wifi-densepose-sensing-server with
--features mqtt + wifi-densepose-hardware for the ADR-110
SyncPacket bridge.
- src/lib.rs: COG_ID = "ha-matter", MDNS_SERVICE_TYPE
"_ruview-ha._tcp", DEFAULT_CONTROL_PORT 9180.
- src/manifest.rs: typed CogManifest (8 fields) mirroring
cog-pose-estimation's manifest.template.json. Round-trip
test locks the JSON wire shape; id-constant test guards
against rename drift.
- src/main.rs: clap CLI with --sensing-url / --mqtt-host /
--mqtt-port / --privacy-mode / --print-manifest. The
--print-manifest flag emits the build-time template with
{{VERSION}} / {{ARCH}} placeholders for the signer.
- v2/Cargo.toml: cog-ha-matter added as workspace member.
Verification:
cargo check -p cog-ha-matter --no-default-features → green
cargo test -p cog-ha-matter --no-default-features --lib
→ 2/2 manifest tests pass
ADR-116 §3 + §4 + §5 (phases) updated to mark P1+P2 ✅ done and
seat the recommended v1 scope (privacy-mode audit-only → cog
signing → SONA loop → HACS gold → Matter Bridge as v0.8) ranked
by build cost × user impact per the dossier.
P3 (next iter): wrap the existing ADR-115 MQTT publisher as the
cog's main loop. The scaffold returns SUCCESS immediately today.
Co-Authored-By: claude-flow <ruv@ruv.net>
100 lines
3.7 KiB
Rust
100 lines
3.7 KiB
Rust
//! Cog manifest — same shape as `cog-pose-estimation/cog/manifest.template.json`
|
|
//! per ADR-101 / ADR-102 / ADR-116. Generated at build time by the cog's
|
|
//! Makefile, signed by the project's Ed25519 release key, uploaded to
|
|
//! `gs://cognitum-apps/cogs/<arch>/cog-ha-matter-<arch>` for Seeds to fetch
|
|
//! via `app-registry.json`.
|
|
//!
|
|
//! The runtime ships the typed view here so the cog can self-report its
|
|
//! manifest to the Seed's control plane (`/api/v1/cog/status`).
|
|
//!
|
|
//! Kept in lib.rs's nearest sibling module so manifest format drift between
|
|
//! build-time template and runtime serializer fires a named test.
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Wire-format mirror of `cog/manifest.template.json`.
|
|
///
|
|
/// Every field is required at install time; `binary_signature` is the
|
|
/// Ed25519 sig over `binary_sha256` so the Seed can verify the cog
|
|
/// binary wasn't tampered with between GCS and the device.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct CogManifest {
|
|
/// Stable cog identifier ("ha-matter"). Becomes the directory name
|
|
/// under `/var/lib/cognitum/apps/<id>/` on the Seed.
|
|
pub id: String,
|
|
/// SemVer of the cog binary. Bumped by the Makefile from
|
|
/// `cargo pkgid` at release time.
|
|
pub version: String,
|
|
/// Where the Seed fetches the binary from. Arch-specific URL with
|
|
/// the `{{ARCH}}` template slot filled in (e.g. `arm`, `x86_64`).
|
|
pub binary_url: String,
|
|
/// Bytes of the binary blob. Set at build time after `wc -c`.
|
|
pub binary_bytes: u64,
|
|
/// SHA-256 of the binary, hex-lowercase, no `0x` prefix. The Seed
|
|
/// verifies this before exec().
|
|
pub binary_sha256: String,
|
|
/// Ed25519 signature over `binary_sha256`, base64-encoded. Optional
|
|
/// for unsigned dev builds; required for cogs listed in
|
|
/// `app-registry.json`.
|
|
pub binary_signature: String,
|
|
/// Unix epoch seconds at install time. The Seed stamps this when it
|
|
/// completes a successful install/upgrade.
|
|
pub installed_at: u64,
|
|
/// One of `"installed"`, `"upgrading"`, `"degraded"`, `"removed"`.
|
|
pub status: String,
|
|
}
|
|
|
|
impl CogManifest {
|
|
pub fn id() -> &'static str {
|
|
super::COG_ID
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
/// Lock the JSON wire shape against accidental field renames. Both
|
|
/// the Seed's control plane and the build-time signer parse this —
|
|
/// any drift fires a named test instead of silently breaking ops.
|
|
#[test]
|
|
fn manifest_round_trip_matches_template() {
|
|
let m = CogManifest {
|
|
id: "ha-matter".into(),
|
|
version: "0.1.0".into(),
|
|
binary_url:
|
|
"https://storage.googleapis.com/cognitum-apps/cogs/arm/cog-ha-matter-arm"
|
|
.into(),
|
|
binary_bytes: 4_200_000,
|
|
binary_sha256:
|
|
"a".repeat(64),
|
|
binary_signature: "Zm9v".into(),
|
|
installed_at: 1_779_512_400,
|
|
status: "installed".into(),
|
|
};
|
|
let json = serde_json::to_value(&m).unwrap();
|
|
// Eight required fields, no extras.
|
|
for key in [
|
|
"id",
|
|
"version",
|
|
"binary_url",
|
|
"binary_bytes",
|
|
"binary_sha256",
|
|
"binary_signature",
|
|
"installed_at",
|
|
"status",
|
|
] {
|
|
assert!(json.get(key).is_some(), "missing manifest field `{key}`");
|
|
}
|
|
let m2: CogManifest = serde_json::from_value(json).unwrap();
|
|
assert_eq!(m, m2);
|
|
}
|
|
|
|
#[test]
|
|
fn manifest_id_constant_matches_cog_id() {
|
|
// The id helper must agree with the crate-level COG_ID constant
|
|
// (regression guard for a future rename).
|
|
assert_eq!(CogManifest::id(), super::super::COG_ID);
|
|
}
|
|
}
|