First doc-directory of hyperhive#4042's Passive pass (705+ hits across
docs/, genuinely mixed unlike TooWordy -- needs a real per-hit read,
not a dictionary shortcut, so this is going doc-directory by
doc-directory in small PRs, per the plan posted on the issue).
Read all 13 flagged hits in this file in context, not just the flagged
word. 3 were genuine catches with a real active-voice improvement and
a nameable actor:
- "the human operator's own forge/matrix account is created via swarm
SSO" -> "swarm SSO creates the human operator's own forge/matrix
account" (x2, identical sentence shape for both accounts) -- swarm
SSO is a nameable, specific actor already named later in the same
sentence, so naming it as the subject too is strictly clearer, not
just different.
- "Do this before anything is pointed at it" -> "Do this before you
point anything at it" -- matches the doc's own established
second-person imperative voice used throughout ("Do this", "Put the
token's value", "Delete the file"); the passive here was the odd one
out, not the house style.
The other 10 are legitimate passives, left alone:
- Generic/unspecified-actor statements ("is needed", "is bound", "is
issued", "been run") where forcing a subject would either invent an
actor the doc never established or read worse than the original.
- Security/architecture invariants ("No forge admin token is stored in
any agent state dir", "Telemetry ingest is authenticated per hive")
-- "No X is Y" / "X is Y" is the standard idiom for a guarantee
statement in security docs, not a clarity problem to fix.
- "operator-only surfaces ... are gated on that group" -- borderline
(could name the group as subject), judged idiomatic access-control
phrasing rather than genuinely clearer active, but flagged as the
closest call in this batch.
Verified: vale docs/getting-started/setup.md before/after -- 13 -> 10
write-good.Passive hits (exactly the 3 rewritten), the pre-existing
unrelated alex.Suicide hit on "hang" (line 51, untouched) still
present and correctly out of scope for this pass.
`Microsoft.Contractions` fires on "is not" and "it is", and both were in
the sentence I added about the role having no consumer yet. Reworded so
neither appears, and the passive construction goes with them.
The vale job is red on every PR by design -- ci.yml says so, the docs
tree has a standing backlog against these rules -- which is exactly why
"vale is red" was not a safe thing to wave through. Checking per line
rather than per job is what found these.
Verified with the invocation ci.yml uses:
`XDG_DATA_HOME=$PWD/.vale-data vale sync && vale docs/getting-started/setup.md`
-> synced 3 packages, 0 errors, 14 warnings. The 2 errors CI reported at
103:39 and 104:7 are the presence control: same rule, same file, prior
commit.
The policy the granting unit already writes grants paths under
`auth/cert/certs/*`, and nothing in the tree creates that mount. Every
certificate login therefore fails against a path that is not there --
the controller's own, and the per-hive ones it is meant to issue
against the same mount.
Same unit, same bootstrap token: check whether cert auth is mounted,
enable it if not, then write a role binding CN `swarm-controller` to
the `swarm-controller` policy.
Idempotency is a read rather than a tolerated error. `auth enable`
fails on an existing mount, and recognising that would tie a rebuild to
an error string no run of this store has ever produced, so the unit
asks `bao auth list` and mounts only on absence. That read is why the
token policy in setup.md gains `sys/auth`.
Each grant came from `bao <cmd> -output-policy`, which prints what a
command requires without running it -- the same way controllerPolicyText
was derived. Enabling an auth method needs `sudo` on `sys/auth/cert`,
which the documented token did not have.
Gated on `clientCaFile`, not on the token alone: `swarm-bao-certs`
installs `client-ca.pem` only under that condition, and a role's
`certificate=` has to name a real CA. The policy write, which needs no
CA, is unchanged in that case.
Nothing can present a certificate for this role yet -- the only client
leaf the tree mints carries CN = the hive's name -- and none of this has
been run against a live store. Both are stated in setup.md.
Cert auth answers a role, so nothing in the swarm can authenticate to
the store until some role exists. Creating the first one therefore
cannot itself use a certificate — the credential has to come from
outside that cycle, and an operator places it.
`deploy.bao.bootstrapTokenFile` names that token. A one-shot unit inside
the store's container reads it and writes the `swarm-controller` policy;
`local-defaults.nix` supplies the path (never the file) on an all-local
deploy, since co-location makes only the location derivable. `bao
operator init` stays an operator action in every shape.
The unit runs in the container rather than on the host because writing
the first grant is a store-side operation: it reaches the store locally
and needs no client certificate. Gating it on the store being here is
therefore not the co-location assumption glue-matrix-bao-token.nix
warns about — a reader has to work from anywhere, the first write never
does.
Policy only, deliberately: a cert-auth role binds a certificate and the
controller has no bao identity yet — it holds no leaf and contains no
bao code at all. The two certificates that do exist are both wrong to
bind. `clientCertFile` is the store host's own reader leaf rather than
the controller's, and the CA that signed it also signs every other
reader's, so binding that would let any reader authenticate as the
controller. Whoever gives the controller an identity writes the role.
The grants are scoped to `hive-*`. Without the prefix the controller
could rewrite the policy that constrains it.
Two things the module-eval arms pin: the unit renders inside the
container with the token path in both its script and its
ConditionPathExists, and a host that names a token while running no
store gets neither the unit nor the host-side directory.
The capabilities were derived with `bao write -output-policy` rather
than written from memory, and the setup.md commands were run against a
real binary for shape before being written down.
Refs #3726.
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.
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.
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.