Watch
0
0
Fork
You've already forked hyperhive
0
Commit graph hyperhive/hive-c0re/src/agent_config/topology.rs
Author SHA1 Message Date
atlas
6fac00dcc5 hive-c0re: fail on an unparseable resource-limits or topology file, write both atomically
resource-limits.json and topology.json were read with parse errors
folded into an empty map, and written in place with std::fs::write. One
truncated resource-limits.json followed by a single set_limits call
rewrote the file with only that agent's entry, erasing every other
agent's CPU and memory overrides without a log line. topology.json had
the same shape: reconcile rebuilt it from the live set, losing pending
(provisioned, never spawned) names.

- agent_config::read_map / write_map are generic over the stored type.
  tool-groups and capabilities behave as before.
- resource_limits::read / effective return an error for an existing but
  unreadable file; a missing file is still the empty map. set_limits
  fails without writing on such a file, and writes atomically.
- topology: reconcile fails without writing on an unreadable file and
  writes atomically. all_agents logs the error and returns no agents,
  so a ManageRootAgent holder starts without cross-agent mounts.

Read-path behaviour on an unreadable resource-limits.json, per caller:
- write_dropins (every spawn / swap / WriteDropin): logs the error and
  keeps the limits drop-in already under /run; the agent still starts.
  With no drop-in yet (first start since boot) it writes the hive
  defaults, because no drop-in means an uncapped container.
- render_flake: propagates, so sync_agents (and spawn/rebuild/destroy
  jobs) fail. An empty map would give tighter-capped agents the hive
  memoryMaxBytes.
- container_view::build_all: logs the error each scan and renders the
  rows at the hive defaults (no ContainerView wire change).
- set_resource_limits reply: propagates.

Closes #4731
2026-09-27 02:41:38 +02:00
atlas
336ed5a010 docs+comments: say what changed instead of tagging the tracker item
The prose added by this branch named the tracker item in seventeen
places, which check-issue-refs.sh rejects: a `#N` tag is dead weight for
anyone reading the public mirror, where no issue data exists. Each one
now states the fact it was pointing at — the parent field is gone — so
the sentence stands on its own.

Two of those lines also carried a rustdoc break: `[`write`]` in
topology.rs is ambiguous between the module's own `write` fn and the
`write!` macro, which `-D rustdoc::broken-intra-doc-links` fails. Spelled
`[`write()`]`, per rustdoc's own suggestion.

The host_config.rs rewrite is two lines rather than three so the doc
block stays under check-comment-blocks.sh's 30-line ceiling.
2026-09-21 22:43:16 +02:00
atlas
179f873722 docs: retire the agent hierarchy from every page that described it
The topology doc keeps its filename and its second half (manager
special-casing, harness unit shape) — both are cross-referenced from
other pages and neither is about the parent field. Its first half is
rewritten: what topology.json is now, and a table of what the removal
took with it, so a reader who finds `<parent>` or `set-parent` in an old
issue thread learns it went away rather than moved.

The dashboard's tree-rendering section is marked dormant rather than
deleted: the walk is still in swarm.js and retiring it is the frontend
owner's call.
2026-09-21 22:08:47 +02:00
atlas
d94bc2188d topology: drop the parent field and the hierarchy it fed
`topology.json` was a map of `name -> parent | null`, and that value fed
the whole agent hierarchy: `<parent>` / `<children>` recipient sentinels,
the reparenting API (CLI verb, wire verb, dashboard endpoints, DAG node),
the dashboard tree, the rebuild depth sort, and an unconditional
bind-mount grant giving every agent RW on its direct children's state.

Per the operator's ruling the field goes, and with it all of the above.
The file survives as what remains once the value is gone: the roster of
agent names, which is the set `ManageRootAgent` grants mounts over. It is
now a JSON array; `read` still accepts the old map shape and keeps its
keys, so a hive that upgrades across this does not blank its roster (and
so no capability holder loses its mounts for the length of that window).

Two sites kept their behaviour under a different recipient rather than
losing it. Both addressed `<parent>`, which the broker already resolved to
`operator` for a root agent, and every agent is now what that fallback
called a root:

- the harness's turn-failure / plugin-failure notification
  (`Surface::send_to_parent` -> `send_to_operator`), and
- the send allow-list's always-permitted escape hatch, so an agent with a
  restrictive allow-list still has a way to say it is stuck.

What is NOT preserved, deliberately: an agent with no capability no longer
sees any other agent's dirs. `ManageRootAgent`'s own grant is unchanged --
still every agent in the roster, still state RW + config RO, still no
`harness`.

The dashboard's reparenting control (the M0V3 picker) is deleted with its
CSS. The tree rendering that reads `ContainerView.parent` is left for the
frontend owner -- it degrades to a flat list with the field gone.
2026-09-21 22:08:47 +02:00
atlas
4f6407fdea collapse the roles.json mount grant into the ManageRootAgent capability
The hive had two spellings of "this agent may act on agents that aren't
its children": the `ManageRootAgent` capability, which nothing checked,
and a `can_manage_top_level_agents` role in a third meta store,
`roles.json`, which owned the real grant — the bind mounts that put
another agent's state (rw) and config (ro) inside the holder's
container. The two drifted independently, and with the parent/child
hierarchy removed the role's set (`parent.is_none()`) silently became
every agent while nothing said so.

Collapse them. The mount grant now hangs off
`Capability::ManageRootAgent`, looked up through the one capability
path that already exists (`capabilities::has_cap` over
`capabilities.json`) rather than a second mechanism. `roles.json` and
everything that read, wrote or reconciled it is gone, along with its
`meta.rs` staging and commit-label wiring; nothing in the tree reads
that file any more.

The enum variant keeps its name deliberately. Renaming it would turn
every `manage_root_agent` already stored in `capabilities.json` into an
unrecognised name that `prune_unknown` drops without asking. Its
meaning, not its spelling, is what changed: "may manage any agent". The
doc comment and the description string now say that.

`top_level_agents()`/`top_level_agents_in()` are replaced by
`all_agents()`/`all_agents_in()`. Under "manage any agent" the mounted
set is every agent by definition, so the code states it instead of
deriving it from a predicate that no longer discriminates — and the
call-site comment explains that, because it otherwise reads as a
widening. The holder is no longer bound as its own virtual child: that
reproduced the own-state and own-config mounts exactly, so dropping it
loses nothing.
2026-09-21 19:04:14 +02:00
atlas
4121e11d87 hive-c0re: drop the subtree check from the scheduling verbs
The topology predicate `is_descendant_of` gated the four schedule-
managing verbs: a caller could only name a schedule owned by an agent at
or below itself in `topology.json`. Those gates now permit any requester,
so the predicate, its pure `_in` form and the `schedule_authorized`
wrapper built on it are gone rather than left returning a constant. The
other two wrappers went earlier with the verbs they served —
`require_descendant` with the lifecycle MCP verbs in 87970a8c, and
`resolve_agent_state_target` with `get_loose_ends`'s agent parameter.

`require_group(agent, "scheduling", ...)` is untouched and still fires at
dispatch for every one of the five scheduling verbs, so holding the tool
group remains the gate; what goes is the ownership restriction layered on
top of it.

The three schedule-mutating verbs keep their row lookup as a plain
existence check, so a caller naming a schedule that does not exist still
gets `not found` rather than a message from deeper in the cancel path.
`list_schedules` stops filtering per row: it would only have hidden rows
the requester may act on anyway.

Error messages, tool descriptions and docs that described the subtree
relation are reworded — a refusal message naming a topology that no
longer decides anything is worse than none.

The six `is_descendant_of_in` unit tests go with the function they test;
the permit behaviour they leave unasserted is picked up by the next
commit.

Refs #4472
2026-09-21 17:20:44 +02:00
atlas
a3b672d1d5 refactor(hive-c0re): drop the request_init_config tool and InitConfig approval
swarm-controller's `InitAgentConfigRepo` node already covers config-repo
creation, so this deletes a duplicate rather than a capability; old
`init_config` rows are skipped by `collect_lenient` with no migration, by
operator decision.

Refs #4398
2026-09-14 19:03:44 +02:00
atlas
5b27aa18c2 docs: repoint eighteen pointers whose section no longer exists
`check-doc-refs.sh` resolves the PATH half of a `docs/x.md::Section`
pointer and stops there. The section half rots the same way, and more
quietly: the file still exists, so every path-shaped check stays green
while the pointer names nothing.

Eighteen sites, five distinct pointers, each retargeted at a heading
verified to exist rather than at the nearest plausible one:

  docs/web-ui.md::Container row
    -> docs/web-ui/dashboard.md::Container row
  docs/web-ui.md::Shared terminal pane
    -> docs/web-ui/shape.md::Shared terminal pane
      Both sections moved out when docs/web-ui.md became a two-heading
      index. The path still resolves, which is exactly why nothing
      caught them.

  approvals.md::Helper events to the manager
    -> approvals.md::Helper events to the submitting agent
      Renamed with the manager special-casing removal; the pointer kept
      the old vocabulary.

  approvals.md::Migration from the pre-tag
    -> approvals.md::Startup migrations (older hosts)
      Same content, including the HIVE_SKIP_META_MIGRATION kill switch
      the citing comment names.

  agent-hierarchy.md::Current state
    -> ::Where the tree lives   (topology.rs, container_view.rs)
    -> ::Reparenting            (topology.rs's set_parent, host-sock)
      Split by what each site actually asks for rather than repointed
      uniformly: two want the format and the source-of-truth rule, two
      want the reparenting validation.

Three known-dead pointers are deliberately left alone:

  * `docs/integrations/forge.md::Sources` sits on a line PR #3927
    rewrites; fixing it here would conflict for no gain.
  * `docs/web-ui/shape.md::One unified channel` names real text that is
    bold inline rather than a heading — which of those counts as
    resolvable is the open question on #3922.
  * `persistence.md::Harness state files` should point at a heading
    whose own text contains backticks, and the backticked-pointer form
    cannot nest them. That is a limit of the convention, not a typo.

Comments only; no behaviour change. Refs #3922.
2026-09-02 09:00:23 +02:00
iris
07b62612b0 docs: restructure into topic subdirectories, collapse duplicated index
Per mara's go-ahead on hyperhive#3902 ("getting started is good, but
terminal rendering does not go in there i think"):

Moved 21 top-level docs/*.md files into 7 new topic subdirectories
(existing web-ui/, turn-loop/, swarm/, tools/, crates/ untouched):
  getting-started/  setup.md
  agent-lifecycle/  agent-hierarchy.md, approvals.md, persistence.md
  trust-boundary/   boundary.md, security.md
  integrations/     forge.md, matrix.md, github.md, knowledge.md
  networking/       gateway.md, network.md, snapshot-store.md
  scheduler/        jobq.md, coordinator.md, ci.md, observability.md
  process/          conventions.md, gotchas.md, pr-review-gate.md
  web-ui/           terminal-rendering.md (moved into the EXISTING dir,
                    per mara's correction to the original getting-started
                    guess -- it's UI implementation detail, not onboarding)

The physical layout now matches docs/README.md's own topical headers,
which already amounted to this taxonomy -- see the scoping comment on
the issue for the two findings that motivated this (a genuine
duplication between CLAUDE.md's old "Reading paths" list and
docs/README.md's grouped one, since drifted out of sync with each
other; and the flat layout not matching the grouping we already had).

Fixed every cross-reference this moved across the whole repo (~120
files: docs/ internal links at every depth, Rust doc comments, nix
module option docs, crate READMEs) -- verified two ways: a grep sweep
confirming zero remaining references to any old path, and a script
that resolves every markdown link in docs/**/*.md + CLAUDE.md +
README.md against the filesystem and reports anything that doesn't
exist (zero broken links).

Collapsed CLAUDE.md's "Reading paths" section (the duplicate) down to
a pointer at docs/README.md, now the single index. Rewrote
docs/README.md itself to use the new subdirectory paths and added the
one doc it was missing that CLAUDE.md's old copy had (pr-review-gate.md).

Classified all 22 docs/*.md files first via a haiku subagent (mara's
suggestion) on two axes -- proposed grouping and operator-vs-
implementation focus -- before finalizing the taxonomy; spot-checked
the report and found internal inconsistencies (its classification
table disagreed with its own summary section for a few files), so this
taxonomy is my original proposal + the one correction mara gave
directly, not a blind application of the subagent's table. The
operator-focus data it gathered is still useful for a follow-up
content pass (docs skewing 'mixed' rather than pure operator-facing),
not addressed in this PR -- structure only.

nix fmt clean, both pre-push lints clean.
2026-09-02 01:55:37 +02:00
damocles
138f6b6c10 hive-sh4re: split manager-socket constants + HelperEvent into their own topic module 2026-08-10 23:05:18 +02:00
damocles
fd40138f5a topology: fix stale rustdoc link to deleted set_parent 2026-07-26 19:47:36 +02:00
damocles
18745f1a98 job_queue: finish reparent call-site swap, delete dead sync path 2026-07-26 19:47:36 +02:00
damocles
673aea4e50 fold hive-c0re module tree into the daemon binary + drop dead pub items surfaced by bin-only (#2513) 2026-07-16 10:43:08 +02:00
damocles
556a213320 refactor(#2285): inline remaining 1:1 path wrappers (meta_dir, marker fns, host_conf_path) 2026-07-10 20:32:03 +02:00
atlas
4d76305f2f fix(clippy): collapse nested if-let in build_graph (collapsible_if) 2026-07-10 15:16:22 +02:00
atlas
0af14d8ef8 refactor(#2281): petgraph for topology — replace bounded walks with graph algorithms
The is_descendant_of and apply_set_parent cycle detection both used
hand-rolled 32-hop bounded ancestor walks. Correct in practice (no
real hive exceeds 32 levels) but carried an arbitrary ceiling and were
harder to reason about than proven graph primitives.

Changes:
- Add build_graph(): converts BTreeMap<name, parent|null> → DiGraph
  with parent→child edges + BTreeMap<name, NodeIndex> index
- Add is_descendant_of_in(): pure (no disk I/O), uses
  petgraph::algo::has_path_connecting from ancestor to candidate
- Rewrite is_descendant_of(): delegates to is_descendant_of_in(&read())
- Rewrite apply_set_parent() cycle detection: build_graph() + speculative
  edge + is_cyclic_directed(); no depth limit
- Add tests for is_descendant_of_in (self, direct child, grandchild,
  parent-is-not-child, sibling, unknown)

petgraph was already a workspace dep (used elsewhere). On-disk format
unchanged (flat JSON map). Public API surface unchanged.
2026-07-10 15:16:22 +02:00
müde
0e4b5a1120 refactor(hive-c0re): group src-root files into submodules
stores/ (sqlite-backed host stores + db helper), stats/, agent_config/,
workers/ — pure git-mv moves; crate-root re-exports keep every
crate::<module> path compiling. flake_check stays at root (synchronous
approval-flow validation, not a background worker)
2026-07-06 22:38:47 +02:00
Renamed from hive-c0re/src/topology.rs (Browse further)