Watch
0
0
Fork
You've already forked hyperhive
0

an archetype carries its own notification-router flows for its agents

ArchetypeMeta gets flows, checked when the controller stores the record: every todo must go to the new members recipient, which the router expands to the agents of the archetype. The operator's flows document refuses members. The router reads the archetype records and each roster agent's archetype key, and its NATS grant gains read on both buckets.
This commit is contained in:
atlas 2026-11-11 04:36:25 +01:00 • committed by mara
commit 1efbb72fdd

View file

@ -292,9 +292,9 @@ impl Policy {
/// subjects, which is what makes the router their sole writer.
/// - **Its state bucket.** Create, look up, read and write
/// `notify-router-state`, and no other bucket.
/// - **The flows document.** `STREAM.INFO` and `DIRECT.GET` on
/// `notify-flows`, which it reads and never creates or writes: the
/// controller creates the bucket and is its one writer.
/// - **The flows document and the archetypes' flows.** `STREAM.INFO` and
/// `DIRECT.GET` on `notify-flows` and `agent-archetypes`, `DIRECT.GET` on
/// `agent-archetype`; it never creates or writes them: the controller does.
/// - **The roster.** `STREAM.INFO` on the agent-status bucket, which lists
/// its keys (`<hive>.<agent>`) and writes none.
/// - **Review requests.** Publish on the one sink subject
@ -313,6 +313,7 @@ impl Policy {
let consumer = forge_events::ROUTER_CONSUMER;
let state = format!("KV_{}", notify_router::STATE_BUCKET);
let flows = format!("KV_{}", notify_flows::BUCKET);
let archetypes = format!("KV_{}", swarm_queue_client::archetypes::BUCKET);
let mut publish = Self::jetstream_minimum().to_vec();
publish.extend([
format!("$JS.API.STREAM.INFO.{events}"),
@ -333,6 +334,12 @@ impl Policy {
format!("$KV.{}.>", notify_router::STATE_BUCKET),
format!("$JS.API.STREAM.INFO.{flows}"),
format!("$JS.API.DIRECT.GET.{flows}.>"),
format!("$JS.API.STREAM.INFO.{archetypes}"),
format!("$JS.API.DIRECT.GET.{archetypes}.>"),
format!(
"$JS.API.DIRECT.GET.{}.>",
swarm_queue_client::agent_archetype::STREAM
),
format!("$JS.API.STREAM.INFO.{}", Self::agent_status_stream()),
swarm_wire::router_sink::REQUEST_REVIEWER_SUBJECT.to_owned(),
format!("$JS.API.STREAM.MSG.GET.{events}"),
@ -1985,6 +1992,10 @@ mod tests {
"$JS.API.DIRECT.GET.KV_{flows}.$KV.{flows}.{}",
notify_flows::KEY
),
// The archetypes' records and each agent's archetype: read them.
"$JS.API.STREAM.INFO.KV_agent-archetypes".to_owned(),
"$JS.API.DIRECT.GET.KV_agent-archetypes.$KV.agent-archetypes.hyperhive".to_owned(),
swarm_queue_client::agent_archetype::direct_get_subject("atlas"),
] {
assert!(may(&allowed), "the router may not reach {allowed}");
}
@ -2022,6 +2033,11 @@ mod tests {
format!("$KV.{flows}.{}", notify_flows::KEY),
format!("$JS.API.STREAM.CREATE.KV_{flows}"),
format!("$JS.API.STREAM.DELETE.KV_{flows}"),
// The archetype buckets: not write them, nor make them.
"$KV.agent-archetypes.hyperhive".to_owned(),
"$JS.API.STREAM.CREATE.KV_agent-archetypes".to_owned(),
swarm_queue_client::agent_archetype::key_subject("atlas"),
"$JS.API.STREAM.CREATE.KV_agent-archetype".to_owned(),
swarm_queue_client::agent_input_subject("atlas"),
"$JS.API.STREAM.CREATE.KV_agent-status".to_owned(),
] {