Watch
0
0
Fork
You've already forked hyperhive
0
Commit graph hyperhive/docs/scheduler/ci.md
Author SHA1 Message Date
atlas
23807c5d0c swarm-ci-runner: keep the registration token on the host's /run, not in the container's root
swarm-bao-ci-runner still reads the token from bao under the runner's own
ci-runner leaf, but now writes it to /run/swarm-ci-runner on the host
(tmpfs), which the container bind-mounts read-only for the register
unit's LoadCredential. Before, it wrote the token to
/var/lib/nixos-containers/swarm-ci-runner/var/lib/swarm-ci-runner/registration-token
on persistent disk, where a superseded token stayed after rotation and
went into backups of the container root. The container's tmpfiles now
remove that old file.

Rotation is unchanged: the ten-minute timer rewrites the file when the
value differs and refresh_consumer restarts the runner. After a reboot
the token is fetched again; until the store answers, a runner that is
already registered keeps running and only a new registration waits.

Part of #4998 (slice 1).
2026-10-15 21:44:46 +02:00
atlas
4a3f21fc2b glue: forge's controller-dependent settings move out of the forge module 2026-10-13 22:14:28 +02:00
atlas
2f05e2db28 nix: re-run the host's store fetches on a ten-minute timer
Seven host oneshots fetch a secret from the swarm secret store into a file
their consumer loads at start: swarm-bao-grafana-oidc, swarm-bao-otel-oidc,
swarm-bao-matrix-oidc, swarm-bao-ci-runner, swarm-bao-forge-oidc,
swarm-bao-hive-otel-oidc and swarm-bao-forwarder-oidc. Each was
RemainAfterExit with no timer, so it ran at boot or deploy and never again:
a secret re-minted in the store reached its consumer only through an
operator restarting the fetch.

lib/store-refresh-timer.nix gives each one a timer (OnUnitInactiveSec 10min,
RandomizedDelaySec 1min, the agent's own store re-read interval), and each
drops RemainAfterExit so a timer start is not a no-op. Each script already
writes the file only when secret_differs, and refresh_consumer/refresh_unit
restart the consumer only when the file is newer than its last start, so a
run reading an unchanged value restarts nothing.

Two docs said these units do not run on a timer; credentials.md's
ci-runner row said the runner token is not re-pulled.

Part of #5017 (slice T).
2026-10-13 00:03:20 +02:00
atlas
9b711d5ffa hive-forge: mirror actions/upload-artifact alongside actions/checkout
With actionsFromSelf, Forgejo resolves bare `uses: actions/<name>` against
the forge itself, so every action a workflow names needs a mirror there.
Only actions/checkout was seeded, and coverage.yml's
`actions/upload-artifact@v3` has failed at job setup with "repository not
found" since the CI runner moved to swarm-ci-runner (e2da5509).

The single hardcoded checkout mirror becomes a list of action names both
share, mirrored from github.com/actions/* like checkout already was. v3
points at the same commit (ff15f03) on github.com and code.forgejo.org.

The controller's forge-objects pass creates any missing mirror on every
pass, and the changed SWARM_CONTROLLER_FORGE_MIRRORS env restarts the unit
on switch, so an existing forge picks the mirror up on deploy.

Closes #5040
2026-10-09 10:40:28 +02:00
atlas
4a289c62e7 docs/scheduler/ci: say it in the active voice where the forwarded enable is refused 2026-10-05 21:52:22 +02:00
atlas
65505f5235 deploy: forward swarm.forge.ci to deploy.ci-runner, say what the forwarded enable needs
swarm.forge.ci.* were per-host options that 4423da48 had already moved to deploy.forgejo.ci.*, so they rename straight to deploy.ci-runner like the forgejo.ci ones; ciRunnerRemoved goes with its last caller.

The forwarded enable now trips deploy.ci-runner's store-identity assertion on a host with no deploy.bao.enable. The assertion names both options and the default, the doc states the requirement, and a module-eval case pins the refusal.
2026-10-05 21:36:11 +02:00
atlas
b114c6b165 deploy: rename the old forgejo.ci options to ci-runner instead of removing them
deploy.forgejo.ci.{enable,name,concurrency,labels,package,jobTimeout} each
have a same-typed, same-meaning counterpart under deploy.ci-runner on the
same host, so they are mkRenamedOptionModule entries again and a config that
still sets them evaluates with the standard rename warning. The swarm.forge.ci
spellings stay removals.

docs/scheduler/ci.md states the rename, that the old hive-ci runner's entry
is deleted by hand in the forge admin panel, and that actionsFromSelf
defaults on where the controller runs.
2026-10-05 21:31:38 +02:00
atlas
8ffceea8e3 swarm-ci-runner: load the registration token in a register unit of its own
systemd hands a unit's credentials to every process of that unit, and a
host job is a process of the runner daemon, so the `LoadCredential=` on
gitea-runner-swarm still let any workflow read the registration token
from `$CREDENTIALS_DIRECTORY`.

swarm-ci-runner-register.service, a oneshot under the daemon's dynamic
user and state dir, now holds the only `LoadCredential=` and runs the
precond and `act_runner register` (only when `.runner` is missing). The
daemon unit has no credential, no `EnvironmentFile` and no `TOKEN`; its
pre-start step starts the register unit, so a missing token fails the
daemon's start and `Restart=on-failure` retries it.

The precond compares `.runner`'s labels in the form the daemon rewrites
them to (`nix` -> `nix:host`); compared verbatim, a scheme-less label
re-registered the runner on every start.

tmpfiles removes the unused `registration-token.env` and upstream's
`.token-hash`/`.labels` markers.
2026-10-05 16:33:24 +02:00
atlas
0302b29ca4 swarm-ci-runner: give the registration token only to the register step
The runner got its registration token through an `EnvironmentFile`
(`TOKEN=…`), so the daemon carried it for its whole life, and for a
`host` label act_runner copies its environment into every job step:
any workflow could read a token that registers runners on the forge.

The host unit now writes the bare token, and the runner unit loads it
with `LoadCredential=`. The upstream pre-start step, which registered
from `$TOKEN`, is replaced by one register step that reads the token
from `$CREDENTIALS_DIRECTORY` and runs `act_runner register` only when
`.runner` is missing, with the instance URL, name, labels and config
file upstream used. The precond now also removes `.runner` when its
labels differ from the configured ones, which upstream's step covered.
A changed token alone no longer re-registers.

Host jobs can still read `.runner` itself (#4979).

Closes #4974
2026-10-05 16:06:52 +02:00
atlas
84347f122c forgejo: actionsFromSelf defaults to whether this host runs the swarm-controller
The controller seeds the actions/checkout mirror from its own host's
mirror list, so a forge host without it got DEFAULT_ACTIONS_URL = self
and no mirror. The default now follows
deploy.swarm-controller.enable; the module-eval check pins forge-only
(false, no warning) and forge+controller (true, mirror seeded).
2026-10-05 13:55:37 +02:00
atlas
80bc92fb49 forgejo: actionsFromSelf defaults to true 2026-10-05 13:55:37 +02:00
atlas
e2da5509ae swarm-ci-runner: run the forge CI runner as a swarm service
The CI runner was a hive deploy module: hive-ci.nix ran it beside the
forge, and hive-c0re registered it through the forge's admin API with
the `core` token, writing the registration token through hive-priv. It
could only run on the forge's host, and it kept an admin-scoped forge
token on a hive.

Now the runner is a swarm service:

- swarm-ci-runner.nix runs it in a `swarm-ci-runner` container on the
  host that sets deploy.ci-runner.enable, reaching the forge by name.
  It needs neither the forge nor a hive there.
- swarm-controller reads the forge's runner registration token with its
  own admin token and writes it to swarm/services/ci-runner/
  registration-token whenever it differs from what it last wrote. Its
  grant on that path is create/update only.
- The runner's own leaf (CN swarm-ci-runner, role and policy of the same
  name) reads that one path. swarm-bao-ci-runner.service fetches it into
  the runner's EnvironmentFile and restarts the runner on a change.
- A pre-start step removes .runner when the daemon's journal since its
  last start holds Forgejo's "unregistered runner" refusal (the daemon
  exits 1 when its startup Declare gets it), or when .runner names
  another forge address; upstream's pre-start step then registers again.

Removed from the hive side: hive-ci.nix and deploy.forgejo.ci.*,
forge/ci_runner.rs, PrivRequest::RegisterCiRunner and its handler and
ReadWritePaths entry, InfraContainer::Ci with hivectl's --ci and the
dashboard's hive-ci journal entry, HYPERHIVE_FORGE_CI_ENABLED, and
read:admin,write:admin from CORE_TOKEN_SCOPES: nothing else in hive-c0re
calls /api/v1/admin/*. The old ci options, under both swarm.forge.ci and
deploy.forgejo.ci, now fail evaluation naming deploy.ci-runner.

The forge's half of the old ci.enable, the actions/checkout mirror and
DEFAULT_ACTIONS_URL = self, is deploy.forgejo.actionsFromSelf.

Closes #4954
2026-10-05 13:55:37 +02:00
atlas
ac592a5d23 forge: always behind the gateway; drop behindGateway
The forge always sits behind the gateway, so `deploy.forgejo.behindGateway`
(and its `swarm.forge.behindGateway` rename alias) is removed and its
true-branch behaviour is now unconditional within `deploy.forgejo.enable`:
https ROOT_URL on the gateway's httpsPort, the forge vhost and local DNS
name, the swarm-ui quick link, the published metrics scrape target, forgejo
metrics, the authelia `/metrics` rule, and `publicUrl` defaulting to
`https://<forge.domain>`.

Removed with it: the direct-port `http://<domain>:<httpPort>/` ROOT_URL
branch, the hive-ci assertion that the option is true, the core-toggle
cases that only exercised the false branch (the services-leaf case reads
`bare`, which never enabled the forge either). `hivectl open forge` now
points at `swarm.forge.publicUrl`, which can still be set to null.

Refs #4885
2026-10-02 18:50:42 +02:00
atlas
20419ccd41 swarm-controller: own the swarm-wide forge objects; hive-c0re stops creating them
The orgs agent-configs/internal/agents (plus mirror owners), the
operators team in agents and agent-configs, the pull-mirrors,
internal/docs, internal/knowledge (public, README-seeded) and the
agent-configs org avatar are one set per forge. hive-c0re ensured them in
its boot sweep, as the core admin, and only on the hive co-located with
the forge container.

swarm-controller now reconciles them at start and every 5 minutes
(forge/objects.rs: observe -> pure plan -> apply). A failed object logs
a warn line plus a pass summary and is retried next tick. create_repo
ensures the agent-configs org and its operators team first, so a config
repo's merge gate never depends on the periodic pass having run.

hive-c0re drops ensure_org, SEEDED_ORGS, ensure_mirrors/ensure_mirror_repo,
ensure_operators_team, ensure_shared_docs_repo, ensure_knowledge_repo/
set_repo_public, seed_readme, ensure_config_org_avatar and the one-shot
knowledge::remove_webhook cleanup, with their now-unused helpers.

nix: the mirror list moves from the hive-c0re unit
(HYPERHIVE_FORGE_MIRRORS) to the swarm-controller unit
(SWARM_CONTROLLER_FORGE_MIRRORS), with an eval warning when mirrors are
declared on a host that runs no controller. c0re.orgAvatarPng is renamed
to deploy.swarm-controller.configOrgAvatarPng.

Refs #3782
2026-09-25 08:36:05 +02:00
atlas
978164dc53 nix: run the forge on one host per swarm (deploy.forgejo.enable)
Every hive with hyperhive enabled ran its own hive-forge container, and
its gateway answered forge.<swarm> with its own bridge IP, so on a
multi-host swarm each hive talked to its own forge.

deploy.forgejo.enable defaults to false and allSwarmServices sets it with
mkDefault, like authelia and bao; singleHostSwarm gets it through that.
The forge's OIDC client moves to a glue module gated on authelia, so a
split authelia/forge swarm still registers it. CI now requires the forge
on the same host, and the controller's forgeTokenFile defaults to null
where the forge is not.

Closes #4705
Refs #3782
2026-09-24 23:56:07 +02:00
iris
04e27c4fb6 docs: suppress reviewed write-good.Passive false positives
133 hits across 38 files, all previously classified during #4548's sweep
and deliberately left un-rewritten (predicate-adjective state/necessity
description, design-intent idiom, structural/type-description idiom,
no-single-actor topology claim, parallel-triple exception, vale
substring-match artifact — see hyperhive#4548's per-PR bodies for the
per-hit reasoning).

Wraps each one in a scoped <!-- vale write-good.Passive = NO/YES -->
pair (the supported mechanism — TokenIgnores has a known offset-drift
bug) rather than a blanket per-file or per-rule silence, so a *new*
passive-voice hit anywhere in these files still fails once the rule
gates CI (next commit). Table/list false positives (docs/swarm/credentials.md's
renewal-table cells) wrap the whole block, not each cell.

Part of #4546.
2026-09-20 16:24:11 +02:00
iris
c9f7de294d docs: clear write-good.Passive hits in docs/scheduler/ci.md 2026-09-20 14:24:12 +02:00
atlas
f45cecf08c ops: address argus review findings on PR #4433
Add attribution-trailer lint row to the ci.md checks table (modeled
on the vale-errors row: not yet a required check) so the doc doesn't
assert stale completeness once attribution-trailers merges. Delete
the dead CI_COMMIT_REF_NAME elif in check-attribution-trailers.sh —
byte-identical to the else arm, never exercised, and its comment
overclaimed GitLab/Forgejo support nothing here can test.

Refs #4432
2026-09-16 00:07:02 +02:00
atlas
55f01942a2 docs, prompts, hive-forge: stop handing readers the renamed verbs
docs/tools/forge.md already listed the nine renamed verbs as removed, then
used them ~30 more times in pasteable blocks. Sweeps every occurrence a
reader would type, including three runtime messages that told the user to
run a verb the same binary rejects.

The renamed-verb list itself keeps the old names; it is what documents them.

Refs #4155
2026-09-10 17:22:57 +02:00
damocles
a5b07c55c8 docs/scheduler/ci.md: drop bare issue tag #4146 missed in ci.yml's own cleanup 2026-09-09 23:00:38 +02:00
iris
c13499c839 ci: split an error-only vale check out of the full prose-lint job
mara, on #4128: add a CI step (separate from the existing one) that
only flags error-level vale hits, so it can be made a required check
without also gating merges on the pre-existing warning/suggestion
backlog. The full job stays as-is, advisory, for that backlog.

Also brought docs/scheduler/ci.md's CI-checks table back in sync with
reality (it was missing the doc-pointer lint job already; now lists
both vale jobs and their required-check status).
2026-09-09 22:55:28 +02:00
iris
15890f9d5b docs: fix genuine Microsoft.Contractions/Negative errors
16 of the 23 error-level hits from a full-repo vale run were real:
'is/are/does/do NOT' and bold 'not' expanded per Microsoft.Contractions,
one hyphen-as-negative-number fixed to an en dash per Microsoft.Negative
(docs/web-ui/dashboard.md's -45 deg column-header tilt).

Where the caps/bold was there for emphasis (contrasting X does this,
Y does not), kept the emphasis by bolding the contraction rather than
dropping it silently -- 'is not' -> 'isn't', 'does NOT' -> '**doesn't**',
etc.

docs/tools/swarmctl-cli.md's one genuine hit is generated -- fixed the
source doc comment in swarmctl/src/main.rs and regenerated via
'cargo run --bin swarmctl -- markdown-docs', diffed against the old
copy first to confirm only the intended line changed.

Left 7 hits unfixed, false positives from the rule matching a
substring rather than the actual pattern it names:
- 4x 'that's instead of that is': every one is the explanatory 'that
  is' idiom (~= i.e.), not a contractible subject+verb -- 'that's'
  would misparse as a demonstrative-pronoun contraction and change the
  sentence's meaning. docs/integrations/forge.md:282,
  docs/tools/forge.md:260, docs/tools/hivectl.md:243,
  docs/web-ui/dashboard.md:457 (and the swarmctl-cli.md generated
  twin of the same category, source left alone for the same reason).
- docs/agent-lifecycle/persistence.md:482 -- 'is not' matched inside
  'is nothing' (the same has-not/has-nothing substring trap noted
  before in this doc's own git history).
- docs/swarm/ca.md:182 -- 'it is' matched inside the already-correct
  'it isn't'.

Per #4128. Remaining errors on main after this: Microsoft.Avoid's 26
hits, already tracked + awaiting a house-style ruling on #4041.
2026-09-09 01:48:46 +02:00
iris
09e4e2f5e9 docs: fix genuine passive-voice hits in docs/scheduler
Seventh batch of the ongoing write-good.Passive pass (hyperhive#4042):
read all 65 hits across jobq.md/ci.md/observability.md/coordinator.md
in context and rewrote 41 with a clearly nameable actor -- mostly
hive-c0re, nix/the nix module, the harness, or a specific fn/type
named right there or nearby (coordinator.md's node-inventory table
and DAG-shape descriptions name concrete Rust items constantly, so
the actor is almost always sitting in the same sentence).

Left 24 alone: predicate-adjective-copula state descriptions ("is
stuck", "is gone", "is unaffected", "is done", etc. -- the largest
recurring bucket this batch, especially in observability.md's
scope/status descriptions), negative-capability idioms ("no X is
needed/left", "X can't be written down"), the established "is
tracked as a follow-up" idiom, a firewall-shorthand notation
("bridge->127.0.0.0/8 is dropped") where rewriting would break the
compact rule-like format, a CLI-flag "(repeatable)" annotation ("May
be repeated"), a Rust type-signature fact ("`moves` is typed ..."),
a hypothetical/counterfactual maintenance-burden clause, a
readiness-condition list ("a node is ready when ... every dep is
satisfied"), and one deliberately-parallel idiom pair
("When OTEL is enabled" used identically twice as a section-opening
convention -- fixing one would break the parallelism, not the
opposite).

One self-caught regression: an early attempt to fix "used by every
`Reconcile` node's start action" (a reduced participial clause, not
flagged) into "is used by every `Reconcile` node's start action"
introduced a brand-new flagged passive. Caught by the post-edit vale
count (expected 65->24, got 65->25) not matching, same discipline as
the docs/turn-loop batch's tail-truncation catch -- re-ran with
active voice instead ("Every `Reconcile` node's start action uses
this fallback").

Verified via vale before/after: 65 -> 24 write-good.Passive hits,
exactly the 24 left alone above; error count and other warning
categories unchanged. Re-read every changed line in full surrounding
context after editing before running the final vale check.
2026-09-08 20:23:54 +02:00
iris
a8fb08a7e8 docs: fix Microsoft.UIVerbs findings (click -> select)
Part of #4041's forgotten remainder (UIVerbs was scoped as pure
execution work, no decision needed -- see comment 71586).

29 genuine input-device-neutral rewrites ("click"/"clicking"/"clicked"
-> "select"/"selecting"/"selected", a few reworded where a direct verb
swap didn't read naturally: "one click from the hub" -> "one step from
the hub", "click straight from X into Y" -> "go straight from X into
Y", "the operator never clicked" -> "the operator never triggered").

Left 5 hits unfixed, each read in context and genuinely not a
device-assumption problem:
- docs/process/gotchas.md:439 -- "click-to-unlock screen" names a
  specific OS lock-screen pattern, not an instruction to the reader.
- docs/web-ui/agent.md:377 -- "clicks" describes literal RFB pointer
  events forwarded by hive-screen-mcp's sendPointer, genuinely
  mouse-specific.
- docs/web-ui/agent.md:78 -- "ctrl/middle-click" names a specific
  keyboard-modifier + mouse-button combination with no "select"
  equivalent.
- docs/web-ui/dashboard.md:741 -- explicitly contrasts "click (or
  Enter/Space)" as two named input methods; replacing "click" with
  "select" would conflate the two the sentence is distinguishing.
- docs/web-ui/shape.md:253 -- "swipes in from the right" describes the
  panel's own slide animation, not a user touch gesture.

Verified: fresh `vale --filter '.Name == "Microsoft.UIVerbs"' docs`
after the fix shows exactly those 5, `nix fmt` reports 0 changes.
2026-09-07 18:46:16 +02:00
atlas
6d4e0e5fa1 docs/ci: say to measure the GC window before relying on the stagger
The guidance says to stagger two hosts' collections, and never says how
long one takes — so an operator picking `dates` has no way to know
whether their stagger is wide enough.

The number that matters is theirs, not mine: a collection's wall clock
is dominated by the sweep over unused `.links` entries, which scales
with the size of the store rather than with what the run deletes. So a
store's size, not its churn, decides the window, and `randomizedDelaySec`
spreads only the start.

Measured here for scale, and deliberately kept out of the doc since it
does not transfer: 11 runs over two weeks ranged 5min 16s to 51min 25s,
inversely — the 51-minute run deleted 732 paths, a 12-minute run deleted
21,901.

Refs #4019.
2026-09-07 17:05:19 +02:00
iris
05cf8e8276 docs: remove hyphens from auto-X compounds per Microsoft.Auto style
Fixed 72 hyphenated 'auto-X' compounds across the docs by deleting
the hyphen to match Microsoft style guide (autogenerated, autoregistration,
autodiscovery, etc). Preserved original capitalization throughout.

Covered 26 documentation files in docs/, including README.md, agent-lifecycle,
integrations, scheduler, networking, process, tools, trust-boundary,
turn-loop, and web-ui sections.
2026-09-07 16:28:06 +02:00
iris
4f2d1d281a docs: fix Microsoft.Foreign hits (e.g./i.e. -> for example/that is)
Substitutes 'for example' for 'e.g.' and 'that is' for 'i.e.' per
Microsoft style, with no comma after the replacement -- this repo
never puts a comma after e.g./i.e. either, so the substituted phrase
matches that house style instead of vale's literal 'for example,'
suggestion.

Covers all 77 real hits (72 from the initial vale pass + 5 more of the
same pattern found on a follow-up vale run). None of the flagged
instances were sentence-initial, so there's no capitalization concern
here.

Verified via a fresh vale run: 0 remaining Microsoft.Foreign hits.
Full accounting in /agents/iris/state/haiku-batches/foreign-report.md.
2026-09-07 16:28:06 +02:00
iris
78021ce982 docs: fix 329 Microsoft.Contractions hits with proper safety checks
Apply contraction fixes across ~40 doc files (setup, integrations, lifecycle,
networking, scheduler, swarm, tools, trust-boundary, UI, etc.). Skipped 14 hits:
- 10 where words appear in ALL CAPS for deliberate emphasis (is NOT, do NOT, etc.)
- 4 where text could not be safely located due to markdown formatting or column position

Applied via systematic scan with checks for fenced code blocks, inline code spans,
and intentional caps. Preserves sentence-initial capitalization throughout.
2026-09-07 16:28:06 +02:00
atlas
5c658e9bcf docs/ci: stagger the GC we recommend, and say that temp roots stop at a store boundary
The nightly GC this page tells operators to configure is what #4019 is
about: a collection that lands on the same wall clock as CI. Two gaps in
the guidance rather than one.

`dates = "daily"` with no randomization puts the collection at the same
time every night, so whatever else runs nightly meets it every night.
`randomizedDelaySec` spreads it; the value is nixpkgs' own example for
that option, and the option feeds `RandomizedDelaySec` on the timer.

The overlap itself does not fail a build on a single host — the runner
builds through the host nix-daemon (`hive-ci.nix` disables its own and
bind-mounts the socket), so an in-flight build's temp roots are held by
the daemon a host GC talks to. What it does cost is wall time: the first
build after a collection rebuilds what the collection deleted. That is
the every-run version of the same cause and it is what the comment now
says.

The Remote builders paragraph covered disk space only. Temp-root
protection is per-daemon, so it does not span two stores: a collection
on the builder is not aware of a coordinator build waiting on a path
there. Stated as the reason to stagger the two hosts' windows rather
than give them the same `dates`.

Deliberately not claiming this fixes the failure in #4019. That one
observed a missing build input with a remote builder in play, and
distinguishing "the collector deleted it" from "it was never in that
store" needs a correlated reading on both hosts during a live window,
which has not been taken. This is the half that is knowable from the
tree: our own recommendation is what schedules the collision.
2026-09-07 15:30:01 +02:00
atlas
1db2ac26a7 deploy: split the forge's host decisions out of swarm.forge
`swarm.*` is what a hive needs to be a *client* of the swarm. For the
forge that is what it IS from any hive's point of view: its package, the
names and ports it answers on, the URLs it advertises, and the client id
it is registered under. How it is served, what it mirrors and where its
host-local secrets sit are decisions of the machine running it, so
behindGateway, openFirewall, mirrors, sso.clientSecretFile and
hostSwarmControllerTokenFile move to `deploy.forgejo.*`.

Unlike the wireguard mesh this SPLITS a module rather than relocating a
whole namespace. `sso` splits with it: `clientId` stays because it must
match the id in authelia's register, while the secret beside it is a
path on one host. Moving the whole `sso` block for symmetry with `ci`
was considered and rejected on exactly that asymmetry.

Declared in hive-forge/default.nix under the `deploy.*` path, following
swarm-victorialogs.nix; deploy.nix carries only the renames. `mirrors`
renames in one entry rather than one per field — it is a single option
of a list-of-submodule type, so the rename carries its whole value,
where `ci` needed five because it is a plain attrset of options.

Readers outside the module: hive-ci.nix binds `deploy.forgejo` for its
behindGateway assertion; swarm-authelia.nix and swarm-controller.nix
read theirs off the `deployCfg` they already bind. hivectl's `open`
printed `services.hyperhive.forge.behindGateway` in an operator-facing
hint — a path that never existed, missing `swarm.` — and hive-c0re's
state_snapshot doc comment carried the same defect; both now name the
new path. The rendered docs put the two halves on separate pages, so
the five descriptions of staying options that explain themselves in
terms of `behindGateway` now qualify it in full.

module-eval gains a forge case configured entirely through the old
paths, asserting the rendered firewall ports and the mirror env var
c0re seeds from: the new paths evaluate fine without the shims, so
dropping them reads as a clean tree. All five old paths are defined in
the fixture, so removing any single shim entry fails the eval rather
than only the two the assertion reads.
2026-09-07 14:24:52 +02:00
atlas
36b67fcda3 docs/ci: the local-checks block named a command that does not exist
`docs/scheduler/ci.md` told the reader to run `nix develop -c treefmt`.
treefmt is not on the devshell PATH — `nix develop -c which treefmt` exits
1 while `which cargo` resolves, so the check discriminates and the
documented command has never worked from that shell.

The same line enumerated the formatter set as "rustfmt + nixfmt + taplo",
which was already wrong before this branch: keep-sorted has been enabled
all along, and the commit before this adds prettier. Replaced the list
with a pointer to nix/treefmt.nix so it can't drift out of sync again.

Also drops "+ rustfmt" from the nix-flake-check row: rustfmt is one of
treefmt's formatters, not a separate thing that runs alongside it.
2026-09-02 15:25:07 +02:00
atlas
39b95c2ede treefmt: apply prettier
Pure `nix fmt` output from the commit before this one — no hand edits.
203 files: 52 md, 42 tsx, 32 js, 32 css, 21 ts, 13 html, 8 json, 3 mjs.

Reproduce with `nix develop -c nix fmt` on the parent commit; the result
should be byte-identical to this tree.

None of the 13 `.prettierignore` entries appears here — verified by
intersecting the changed-file list against the ignore file, with a
control proving the intersection finds a match when one exists.
2026-09-02 15:25:07 +02:00
atlas
caf5896303 docs: repoint every reference the docs/ reorg left dangling
`docs/` was reorganised into topic subdirectories and the references to it
were not moved with it. Thirteen distinct paths and three relative links no
longer resolved, spread across nix, css, html, js, markdown and
.prettierignore — a stale pointer is not a markdown problem, it is wherever
someone wrote a path down.

Each mapping resolved to exactly one target. `docs/matrix.md` was the sole
ambiguous basename: .prettierignore lists `docs/tools/matrix.md` separately
and that entry still resolves, so the stale one is the integrations doc.

The three relative links were each one `../` too deep — from `<crate>/src/`
two levels reach the repo root. `hive-agent/src/login.rs` already had the
correct form, in the same crate, at the same depth.

.prettierignore is repointed rather than dropped, though nothing in the tree
runs prettier: no treefmt entry, no CI job, no package script. Whether that
config should exist at all is a separate question from whether it names
files that do.
2026-09-02 10:23:24 +02:00
iris
9a854a160b docs: fix ci.md's now-two-levels-deep relative link to .forgejo/workflows
argus caught this on review: ci.md's own content never changed (0 diff on the
move), but it went from one level under docs/ to two (docs/scheduler/ci.md),
so its `../.forgejo/workflows/ci.yml` link now needs `../../`.

Also fixes the verification script itself — it only checked link targets
ending in .md or / (a systematic blind spot for a link to any other file
type, which is exactly how this one slipped through both the grep sweep and
the link-resolution check). Re-ran the corrected version repo-wide (93
tracked .md files, matches argus's own count) — zero broken links.
2026-09-02 01:55:37 +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
Renamed from docs/ci.md (Browse further)