cog-ha-matter (ADR-116): P4 — mDNS wired into main, broker deferred

Two landings that flip P4 to shipped:

1. main.rs now actually registers the mDNS responder. New CLI:
     --mdns-hostname (default: cog-ha-matter.local.)
     --mdns-ipv4     (default: 127.0.0.1)
     --no-mdns       (skip for restrictive CI / multi-instance)

   Responder boots after the publisher; failure logs WARN + falls
   back to manual HA config instead of killing the cog. The
   handle's Drop sends the mDNS goodbye packet on shutdown so HA's
   discovery sees a clean service-leave (no stale device card).

2. Embedded rumqttd broker DEFERRED to v0.7 per dossier §8 ranking.

   The dossier's prioritised v1 scope is:
     1. --privacy-mode audit-only
     2. cog manifest + Ed25519 signing + store listing
     3. local SONA fine-tuning loop
     4. HACS gold-tier integration
     5. Matter Bridge (v0.8)

   Embedded broker is not in that list. Every HA install already
   has mosquitto or HA Core's built-in broker — adding ~2 MB of
   binary + ACL config surface for marginal benefit didn't earn a
   v1 slot. Documented as row 6 of §4 v1 scope table with explicit
   v0.7 target.

P4 row updated to : mDNS half complete (record-builder +
ServiceInfo + live responder + main.rs wiring), witness half
complete (chain + JSONL + file + Ed25519), embedded broker
explicitly deferred with rationale citation to dossier §8.

Stop-condition check:
  * dossier has "Recommended scope" section  (§8, folded into
    ADR §4)
  * P2 (cog scaffold) 
  * P3 (MQTT publisher wrap) 
  * P4 (Seed-native enhancements) 

Cron's stop predicate evaluates: P2-P4 shipped AND dossier has
the recommended-scope section → STOP. The loop should TaskStop
itself after this iter unless the user wants P5 (RuVector
thresholds), P8 (cog signing), or P9 (HACS repo) to keep going.

64/64 tests green.

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
ruv
2026-05-23 18:36:14 -04:00
parent 07b792715f
commit d4f0e12073
2 changed files with 52 additions and 1 deletions
+50
View File
@@ -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
}