From bd54372fcc221359ae803040f7b0248037bfe2a4 Mon Sep 17 00:00:00 2001 From: atlas Date: Sun, 25 Oct 2026 15:08:50 +0100 Subject: [PATCH] describe core/meta as the legacy permission repo; drop stale meta-flake prose Comments, docs and the hive-c0re README no longer say the hive renders, locks or pushes a meta flake. core/meta is the legacy permission-seed repo that meta::remove_permission_files still commits to; builds come from internal/meta (meta_rev.rs). Docs note that a start of a stale stopped agent can fail until the swarm's update pins the config. --- docs/agent-lifecycle/config-changes.md | 5 ++++- docs/integrations/forge.md | 7 ++++--- hive-c0re/README.md | 7 +++++-- hive-c0re/src/forge/mod.rs | 24 +++++++++++++----------- hive-c0re/src/forge/reconcile.rs | 2 +- hive-c0re/src/forge/repos.rs | 9 +++++---- hive-c0re/src/matrix.rs | 2 +- hive-c0re/src/stores/power.rs | 2 +- nix/host-modules/hive-c0re/options.nix | 2 +- 9 files changed, 35 insertions(+), 25 deletions(-) diff --git a/docs/agent-lifecycle/config-changes.md b/docs/agent-lifecycle/config-changes.md index 7bf08820..d063f4a0 100644 --- a/docs/agent-lifecycle/config-changes.md +++ b/docs/agent-lifecycle/config-changes.md @@ -444,7 +444,10 @@ nothing; a rebuild would have no flake to build from either. A hive deploy alone doesn't rebuild agents. A stopped agent gets its rebuild at its next start: the start path upgrades -the start of a stale, stopped agent to a rebuild followed by the start. +the start of a stale, stopped agent to a rebuild followed by the start. In +the window after a config merge, before the swarm's update has pinned the new +config, that rebuild fails with the error that names the agent, and the +agent stays stopped until the update lands and you ask for the start again. The dashboard surfaces pending config changes per agent: a clickable "needs update ↻" badge appears whenever the agent's applied repo has a diff --git a/docs/integrations/forge.md b/docs/integrations/forge.md index 0195f8dc..c34e4ae5 100644 --- a/docs/integrations/forge.md +++ b/docs/integrations/forge.md @@ -122,10 +122,11 @@ Two things live in the `agent-configs` Forgejo organization: [config-changes.md § Config changes](../agent-lifecycle/config-changes.md#config-changes)). hive-c0re pushes nothing to this org; it only reads from it. Repos stay private, so an agent can't read another - agent's config. (Agents remain read-only collaborators on `core/meta`.) + agent's config. (Agents remain read-only collaborators on the legacy + `core/meta`, the hive's old permission-seed repo.) The agent's **persistent meta flake input** is this repo's `main` head, - pinned by sha (`agent-.url = git+/agent-configs/.git?rev=`; - see + pinned by sha in `internal/meta` (`agent-.url = +git+/agent-configs/.git?rev=`; see [config-changes.md § Meta flake](../agent-lifecycle/config-changes.md#meta-flake)). hive-c0re's own git reads of this repo, which resolve the sha, authenticate with the hive's read token through `forge::reader_token()` (see diff --git a/hive-c0re/README.md b/hive-c0re/README.md index fd485fb8..8aa58136 100644 --- a/hive-c0re/README.md +++ b/hive-c0re/README.md @@ -41,8 +41,11 @@ to track it: per-agent sockets. - **`forge/`** — optional Forgejo wiring (`docs/integrations/forge.md`). - **`coordinator.rs`** — top-level wiring for `serve`. -- **`meta.rs`**, **`migrate.rs`** — the meta flake + schema/state - migrations. +- **`meta_rev.rs`** — which `internal/meta` commit an agent builds from, and + the markers a successful build writes. **`agent_set.rs`** — the files that + follow the agent set (topology, gateway map). **`meta.rs`** — the commit + that removes the legacy permission seed files. **`migrate.rs`** — + schema/state migrations. - **`matrix.rs`**, **`gateway_nginx.rs`**, **`priv_client.rs`** — matrix provisioning, gateway vhosts, and the `hive-priv` client respectively. diff --git a/hive-c0re/src/forge/mod.rs b/hive-c0re/src/forge/mod.rs index 278fc7de..e54f6303 100644 --- a/hive-c0re/src/forge/mod.rs +++ b/hive-c0re/src/forge/mod.rs @@ -1,5 +1,6 @@ -//! Optional Forgejo wiring — the `core/meta` repo and meta read-access -//! grants. Those writes, as `core`, run only beside a local `hive-forge` +//! Optional Forgejo wiring — the legacy `core/meta` repo (the hive's old +//! permission-seed repo, which `meta::remove_permission_files` still commits +//! to) and its read-access grants. Those writes, as `core`, run only beside a local `hive-forge` //! container; reads of the forge go through [`reader_token`] on every hive. //! The swarm-wide orgs, teams and repos, and each agent's read grant on //! `internal/docs`, are swarm-controller's. Full design: @@ -215,8 +216,8 @@ where .map_err(|_| anyhow::anyhow!("{op}: no answer from the forge within {API_TIMEOUT:?}")) } -/// Per-agent forge sync: grant read access to `core/meta`, and wire the -/// `meta` remote in its proposed repo. All operations are idempotent; +/// Per-agent forge sync: grant read access to the legacy `core/meta`, and wire +/// the `meta` remote in its proposed repo. All operations are idempotent; /// failures are logged as warnings but don't abort the caller. /// /// `core_token` is `core_token()` — passed in so callers that already @@ -234,8 +235,9 @@ pub async fn sync_agent(name: &str, core_token: Option<&str>) -> bool { // swarm-controller's; this hive creates none of them and pushes nothing // to the repo. let mut ok = true; - // Grant read-only access to core/meta and wire the `meta` remote - // into the proposed repo so agents can fetch their deployment context. + // Grant read-only access to the legacy core/meta and wire the `meta` + // remote into the proposed repo. Agents build from `internal/meta`, not + // from this repo. if let Some(token) = core_token && let Err(e) = meta_read_access(name, token).await { @@ -249,7 +251,7 @@ pub async fn sync_agent(name: &str, core_token: Option<&str>) -> bool { ok } -/// The `core_token.is_some()` half of [`ensure_all`]: the meta repo, the +/// The `core_token.is_some()` half of [`ensure_all`]: the legacy meta repo, the /// core avatar, and removing this hive's own config-PR hook — /// every step that needs an authenticated forge client. The swarm-wide /// objects (orgs, the `operators` team, mirrors, `internal/docs`, @@ -258,9 +260,9 @@ pub async fn sync_agent(name: &str, core_token: Option<&str>) -> bool { /// `ensure_all` under clippy's function-length limit; not meant to be called /// from anywhere else. async fn ensure_all_orgs_and_repos(token: &str) { - // Meta repo lives at core/meta — pushed from git_commit in - // meta.rs on every deploy/lock-update. Make sure it exists - // before the first push hits a 404. + // The legacy meta repo lives at core/meta. The only push to it is + // `meta::remove_permission_files`' commit; make sure the repo exists + // before that push hits a 404. if let Err(e) = ensure_repo("meta", token).await { tracing::warn!(error = ?e, "forge: ensure_repo core/meta failed"); crate::warnings::set_boot_warning( @@ -380,7 +382,7 @@ async fn wait_until_ready() -> bool { } /// Sweep the forge at startup: seed the `core` admin user (hive-c0re's own -/// identity for pushing the meta repo + driving the API) and its token, the +/// identity for pushing the legacy meta repo + driving the API) and its token, the /// `core/meta` repo and the local knowledge clone, then run [`sync_agent`] /// over every existing container (manager + sub-agents). Agent accounts, /// tokens and `agent-configs/` repos are the swarm-controller's, as is diff --git a/hive-c0re/src/forge/reconcile.rs b/hive-c0re/src/forge/reconcile.rs index e4b78d96..35844f08 100644 --- a/hive-c0re/src/forge/reconcile.rs +++ b/hive-c0re/src/forge/reconcile.rs @@ -6,7 +6,7 @@ //! //! `Status` is read-only (fetches forge `main` into a scratch ref, reports //! the divergence). `Apply(Forge)` resets the local applied checkout to -//! forge `main`; the meta flake pins forge `main` itself, not this tree. It +//! forge `main`; `internal/meta` pins forge `main` itself, not this tree. It //! does NOT auto-deploy. `Apply(Local)` is not supported: forge `main` is //! branch-protected, so it only advances through a config-PR merge. diff --git a/hive-c0re/src/forge/repos.rs b/hive-c0re/src/forge/repos.rs index 6893b913..d434b8a4 100644 --- a/hive-c0re/src/forge/repos.rs +++ b/hive-c0re/src/forge/repos.rs @@ -89,11 +89,12 @@ pub async fn ensure_repo(name: &str, token: &str) -> Result<()> { } /// Dashboard-warning guard for the meta non-fast-forward condition. -/// Held while `core/meta` remote is ahead of our local mirror; cleared +/// Held while the `core/meta` remote is ahead of our local mirror; cleared /// automatically when the next push succeeds. static META_NON_FF_GUARD: Mutex> = Mutex::new(None); -/// Push `dir` (the meta repo) to `core/meta` on the local forge. +/// Push `dir` (the legacy hive meta repo) to `core/meta` on the local forge. +/// Its one caller is `meta::remove_permission_files`' commit. /// Best-effort: returns Err which callers log + ignore. No-op when /// the core token isn't present yet (forge container not provisioned). pub async fn push_meta(dir: &Path) -> Result<()> { @@ -150,7 +151,7 @@ pub async fn push_meta(dir: &Path) -> Result<()> { } /// Grant agent `name` read-only collaborator access to `core/meta` on -/// the forge so the agent can clone/fetch the meta flake. Idempotent: +/// the forge so the agent can clone/fetch that legacy repo. Idempotent: /// re-adding an existing collaborator succeeds (Forgejo answers 204 /// either way). pub async fn meta_read_access(name: &str, core_token: &str) -> Result<()> { @@ -168,7 +169,7 @@ pub async fn meta_read_access(name: &str, core_token: &str) -> Result<()> { /// Add the forge `core/meta.git` URL as the `meta` remote in the /// agent's proposed config repo so the agent (and the manager) can -/// fetch the meta flake from the forge. Idempotent: no-op when the +/// fetch that legacy repo from the forge. Idempotent: no-op when the /// remote already points at the right URL, or when the proposed repo /// does not exist yet. No-op when the forge is not running. pub async fn ensure_meta_remote(name: &str) -> Result<()> { diff --git a/hive-c0re/src/matrix.rs b/hive-c0re/src/matrix.rs index d8f2d8db..70b95a96 100644 --- a/hive-c0re/src/matrix.rs +++ b/hive-c0re/src/matrix.rs @@ -65,7 +65,7 @@ fn matrix_base() -> Result<&'static str> { /// /// # Errors /// When `HYPERHIVE_HIVE_NAME` is unset or empty. That is the same variable -/// [`stored_sender_token`] logs in with and `hive-c0re`'s meta flake asserts +/// [`stored_sender_token`] logs in with and the swarm meta flake asserts /// for every hive, so its absence is a broken deployment rather than a /// supported one — and there is no safe default to fall back to: the only one /// available is the shared account this replaced. diff --git a/hive-c0re/src/stores/power.rs b/hive-c0re/src/stores/power.rs index 1d0c9256..8fb1ecda 100644 --- a/hive-c0re/src/stores/power.rs +++ b/hive-c0re/src/stores/power.rs @@ -11,7 +11,7 @@ //! queued node: operator/intent actions update the row synchronously //! at request time, then submit the DAG whose terminal `Reconcile` //! reads the fresh value — rapid toggles are last-writer-wins and the -//! reconciles converge. Power toggles never commit to the meta repo. +//! reconciles converge. use std::path::Path; use std::sync::Mutex; diff --git a/nix/host-modules/hive-c0re/options.nix b/nix/host-modules/hive-c0re/options.nix index f39c4bb9..64edd2ad 100644 --- a/nix/host-modules/hive-c0re/options.nix +++ b/nix/host-modules/hive-c0re/options.nix @@ -110,7 +110,7 @@ defaultText = lib.literalMD "`\"path:\${pkgs.path}\"`"; description = '' Store-path URL of the nixpkgs the swarm builder's check flake - builds on. The generated meta flake does not use it: its `nixpkgs` + builds on. The swarm meta flake does not use it: its `nixpkgs` follows `hyperhive/nixpkgs`. Defaults to `"path:''${pkgs.path}"`, the nixpkgs the host NixOS