From ff377b0deeecca8d34a0ce2092946c19bb9dbe78 Mon Sep 17 00:00:00 2001 From: iris Date: Mon, 7 Sep 2026 14:56:04 +0200 Subject: [PATCH] docs: fix capitalization losses + one text corruption from the contractions pass Review pass on top of the previous commit (85a94671) turned up three real issues its own vale-only verification didn't catch: - 'has not' -> 'hasn't' fired inside 'has nothing', corrupting docs/swarm/README.md into 'hasn'thing to say upward'. Restored 'has nothing'. - ~44 hits where the original text was genuinely sentence-initial ('It is', 'That is', 'They are', 'What is', 'Do not', ...) got contracted in lowercase, silently de-capitalizing the start of a sentence. Checked each one's real surrounding text and capitalized the ones that needed it. - Confirmed (by reading the actual text, not just trusting vale) that the 3 remaining 'is not'/'has not'/'it is' hits after those fixes are vale's own false positives: it matches these as a bare substring with no trailing word boundary, so it also fires on 'is nothing', 'has nothing', and the already-correct 'it isn't'. Left those alone -- there's no real issue in the text. Re-verified with a fresh vale run: the remaining 17 hits are exactly the union of the 14 legitimate ALL-CAPS/bold-emphasis skips from the first commit and these 3 false positives. Full accounting in /agents/iris/state/haiku-batches/contractions-report.md. --- docs/README.md | 2 +- docs/agent-lifecycle/persistence.md | 4 ++-- docs/networking/gateway.md | 6 +++--- docs/networking/network.md | 4 ++-- docs/networking/snapshot-store.md | 16 ++++++++-------- docs/scheduler/coordinator.md | 8 ++++---- docs/scheduler/observability.md | 4 ++-- docs/swarm/README.md | 10 +++++----- docs/swarm/ca.md | 12 ++++++------ docs/swarm/secrets.md | 12 ++++++------ docs/swarm/services.md | 2 +- docs/swarm/ui.md | 2 +- docs/trust-boundary/boundary.md | 2 +- docs/trust-boundary/security.md | 8 ++++---- docs/web-ui/dashboard.md | 2 +- 15 files changed, 47 insertions(+), 47 deletions(-) diff --git a/docs/README.md b/docs/README.md index bf10d1e8..4bb56aaf 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,7 +58,7 @@ declarations. the PAT injected?** → [`integrations/github.md`](integrations/github.md) (operator content up top; the `gh`/git-push + notification-poller mechanics are in a collapsed "Implementation" section at the bottom). -- **What is `/knowledge`? How does the hive-wide knowledge repo sync, +- **What's `/knowledge`? How does the hive-wide knowledge repo sync, and how do I contribute a document?** → [`integrations/knowledge.md`](integrations/knowledge.md). - **What does `hivectl` do? Provisioning, gateway users, container shells?** → [`tools/hivectl.md`](tools/hivectl.md) (the curated guide); diff --git a/docs/agent-lifecycle/persistence.md b/docs/agent-lifecycle/persistence.md index 8c6d6f4f..046982bd 100644 --- a/docs/agent-lifecycle/persistence.md +++ b/docs/agent-lifecycle/persistence.md @@ -476,9 +476,9 @@ Only present on the one host running so it survives restarts and redeploys. - `webhook-secret` — the HMAC key the swarm's forge webhooks are signed - with. **Keep it.** it's handed to Forgejo when a hook is registered, + with. **Keep it.** It's handed to Forgejo when a hook is registered, so replacing the file means every subsequent delivery fails - verification until the hook is re-registered with the new value. it's + verification until the hook is re-registered with the new value. It's generated automatically on first start; there is nothing to configure. If the file is unreadable at startup the daemon still starts and logs diff --git a/docs/networking/gateway.md b/docs/networking/gateway.md index 4761c481..cd9a5a88 100644 --- a/docs/networking/gateway.md +++ b/docs/networking/gateway.md @@ -206,7 +206,7 @@ On by default, and listens on `httpsPort` (default 443) on every vhost beside th The issuer is a **host-held hive CA**, not a bare self-signed leaf. A host service (`hive-tls-ca.service`, from the `hive-tls` module) generates a long-lived CA (`services.hyperhive.deploy.hive-controller.tls.caValidityDays`, default ~20y) under `services.hyperhive.deploy.hive-controller.tls.stateDir` (default `/var/lib/hive-tls`), then signs a gateway **leaf** (`leafValidityDays`, default 30d) with it. `hive-gateway-self-signed-cert` then imports the leaf into nginx's state dir (`/var/lib/hive-gateway/tls/{cert,key}.pem`). -⚠️ **don't collapse that import unit into pointing nginx at the CA dir.** +⚠️ **Don't collapse that import unit into pointing nginx at the CA dir.** It does two jobs, and skipping it has taken the gateway down in production before. It re-modes the leaf (`hive-tls-ca` writes the key `0600 root:root`; nginx's pre-start `nginx -t` runs as the *nginx user*, so a @@ -455,7 +455,7 @@ legacy single-proxy block and all traffic is forwarded to the agent daemon as before. **`extraFiles`**: per-agent `hyperhive.frontend.extraFiles` are in -`mergedDist`, not in the base `cfg.frontend` dist. they're not under +`mergedDist`, not in the base `cfg.frontend` dist. They're not under the nix-store `alias` path, so requests for them fall through `try_files` to `@_dynamic` and are served by the agent daemon as before. @@ -542,7 +542,7 @@ The daemon hashes passwords with BCrypt (cost 12) and writes `$2y$`-prefixed hashes that nginx accepts natively. No external `htpasswd` binary is required. -**what's not gated:** per-agent UI routes emitted into `agents.conf` +**What's not gated:** per-agent UI routes emitted into `agents.conf` (served under `/agent//`) inherit no auth from `/` — nginx applies `auth_basic` per-location. Full per-agent coverage is a follow-up. diff --git a/docs/networking/network.md b/docs/networking/network.md index 0ce22524..d850a3f6 100644 --- a/docs/networking/network.md +++ b/docs/networking/network.md @@ -236,7 +236,7 @@ to all containers — agents and service containers alike. `HOST_ADDRESS` is the bridge gateway IP (the address part of `HIVE_NETWORK_SUBNET`, via `lifecycle::bridge_gateway_ip` — taken verbatim so a non-`.1` operator override still resolves to wherever the bridge -actually lives). it's **load-bearing**: nixos-container's container-side +actually lives). It's **load-bearing**: nixos-container's container-side network setup only installs a default route (`ip route add default via $HOST_ADDRESS`) when `HOST_ADDRESS` is non-empty. In bridge mode the host-side address/route setup is skipped, so writing it only affects the @@ -257,7 +257,7 @@ wiring is runtime: gateway IP) into each container's `/etc`. - the `hyperhive-isolated-dns` oneshot (`nix/agent-modules/network.nix`), gated on that marker, rewrites `/etc/resolv.conf` to `nameserver ` at boot. - it's ordered `before` the harness (`hive-ag3nt`), the matrix daemon, and + It's ordered `before` the harness (`hive-ag3nt`), the matrix daemon, and `tea-login` so the resolver is correct before the first DNS lookup. **Why isolation is safe**: hive-c0re's control-plane sockets are unix diff --git a/docs/networking/snapshot-store.md b/docs/networking/snapshot-store.md index 84bea093..e1a17681 100644 --- a/docs/networking/snapshot-store.md +++ b/docs/networking/snapshot-store.md @@ -7,11 +7,11 @@ complete a migration. Two things it's not, both worth stating because both are common assumptions: -- **it's not the swarm controller**, and doesn't depend on one. it's +- **It's not the swarm controller**, and doesn't depend on one. It's a NixOS host role: a btrfs subvolume tree, a socket-activated receiver, and the `wg-hive` interface the swarm module already brings - up. that's why it can be deployed before any controller exists. -- **it's not a backup product.** It happens to hold the data a backup + up. That's why it can be deployed before any controller exists. +- **It's not a backup product.** It happens to hold the data a backup would hold, and it should be operated accordingly (see [Operating it](#operating-it)) --- but nothing in it does scheduling, verification, or restore orchestration. @@ -56,7 +56,7 @@ services.hyperhive.swarm.snapshotStore = { Two deliberate asymmetries in that pair, both liable to be misread as inconsistency: -- **`address` has no default.** it's a deployment fact a pushing hive +- **`address` has no default.** It's a deployment fact a pushing hive can't derive, and a wrong guess means streaming an agent's state at whatever happens to answer. Unset, a push fails naming this option. - **`port` does default** (`51821`), because it's a convention both @@ -64,7 +64,7 @@ inconsistency: coordination, not a guess. Note the option lives under `swarm.*` while the receiving host's lives -under `services.hyperhive.snapshotStore`. that's the distinction the +under `services.hyperhive.snapshotStore`. That's the distinction the two namespaces carry throughout: `swarm.*` describes _the swarm_ as seen from this host, and a bare `services.hyperhive.` describes _a role this host performs_. A store host sets both --- one to run the @@ -78,7 +78,7 @@ and no credential argument, because the mesh is the authentication. ## The mesh is the authentication -There are no certificates here, and no key material of its own. that's +There are no certificates here, and no key material of its own. That's deliberate rather than an omission. WireGuard's cryptokey routing already binds a peer's source address to @@ -116,7 +116,7 @@ The rule that matters: Validation is an allowlist --- `[A-Za-z0-9_-]+` and nothing else. No slash and no dot means neither directory traversal nor an absolute path -can survive it. it's deliberately an allowlist and not a list of +can survive it. It's deliberately an allowlist and not a list of forbidden characters: a blocklist only ever excludes the attacks somebody already thought of. @@ -165,7 +165,7 @@ nobody runs it day to day, so it rots and is discovered broken in production. ⚠️ **The assumption to keep true over time:** the store host runs -nothing else. that's true on day one and quietly false the day someone +nothing else. That's true on day one and quietly false the day someone notices the box has spare disk. Nothing in the config objects when it stops being true. diff --git a/docs/scheduler/coordinator.md b/docs/scheduler/coordinator.md index 145f22e0..6ef4d863 100644 --- a/docs/scheduler/coordinator.md +++ b/docs/scheduler/coordinator.md @@ -100,7 +100,7 @@ container build: `DeployWindow` — the deploy subtree's root, which holds it across every phase below it (it declares `Resource::MetaWindow`). Two meta mutations can therefore never interleave, so no commit lands inside another - node's staged window. it's a queue resource rather than a runtime mutex + node's staged window. It's a queue resource rather than a runtime mutex because a resource is held by a subtree root across its whole subtree, which a `MutexGuard` (bounded by one executor fn) can't — that's what lets a multi-node deploy own one window. For the same reason the window must stay @@ -237,7 +237,7 @@ than to one DAG shape it happens to appear in. A **brace** is the one sanctioned exception: a pure-resource-holder root that declares on behalf of a subtree coordinated with itself, whose members then declare nothing. -it's forced rather than stylistic. Declaring a resource means _"I need this +It's forced rather than stylistic. Declaring a resource means _"I need this exclusively"_, and the agent lease is single-unit — so **two siblings that both declared it could never run concurrently.** For a subtree whose whole point is concurrency (`Prebuild` beside the `Signal` → `Drain` quiesce window), declaring @@ -349,7 +349,7 @@ the event's whole job. ## Container view `container_view.rs` maintains an in-memory snapshot of every nixos-container's -systemd service state. it's polled on coordinator startup and re-scanned after +systemd service state. It's polled on coordinator startup and re-scanned after every lifecycle operation (spawn, rebuild, kill) so the dashboard always reflects the actual container status without a live `nixos-container list` call on each render. @@ -527,7 +527,7 @@ wants it. Two things to know about the weights: -- they're **hive-wide** — unlike the caps there is no per-agent +- They're **hive-wide** — unlike the caps there is no per-agent override in `meta/resource-limits.json`, so every agent carries the same value and the weight does _not_ rank agents against each other. What `80` buys is that agents yield to everything **not** on this diff --git a/docs/scheduler/observability.md b/docs/scheduler/observability.md index a0b1f5a3..0f5125c0 100644 --- a/docs/scheduler/observability.md +++ b/docs/scheduler/observability.md @@ -54,7 +54,7 @@ credential.** Neither tier can tell a container's genuine Claude Code stats from anything else shaped like OTLP arriving on that port — including data smuggled out in resource attributes on an otherwise-legitimate export. -that's a **different risk from the one the collector fixes**, and strictly +That's a **different risk from the one the collector fixes**, and strictly smaller than what preceded it: before, every agent held the upstream credential itself, so it could do all of the above _and_ use the token anywhere else. The collector removes the token and keeps the pipe. Agents are inside the trust @@ -122,7 +122,7 @@ read. `0600` protects it from other containers, not from the agent itself. As long as the direct path stays _selectable_, that hole stays selectable; an option that can reintroduce it's a hole with extra steps. -**Why the tiers stay separate on one box.** they're not collapsed when +**Why the tiers stay separate on one box.** They're not collapsed when co-located: an all-local hive is a statement about _where_ processes run, not about the shape of the deployment. A boundary that disappears locally is one the local deployment stops testing. diff --git a/docs/swarm/README.md b/docs/swarm/README.md index 71964669..57b3fb8d 100644 --- a/docs/swarm/README.md +++ b/docs/swarm/README.md @@ -120,7 +120,7 @@ services.hyperhive.swarm.hives = { ``` One attrset describing **every** hive in the swarm, **including this -one**, keyed by that hive's `hiveName`. it's meant to be _identical on +one**, keyed by that hive's `hiveName`. It's meant to be _identical on every host_ — write it once, share it, and each host reads it correctly because `services.hyperhive.hiveName` says which entry is itself. @@ -138,7 +138,7 @@ evaluates cleanly points at a real machine that isn't the one you meant. > inside a swarm comes from the swarm root ([`ca.md`](ca.md)): every > hive chains to it, so one anchor replaces per-hive pinning entirely. > What that genuinely drops is trusting a hive whose root this swarm -> does _not_ own — another swarm's, or one keeping its own CA. that's +> does _not_ own — another swarm's, or one keeping its own CA. That's > a cross-swarm problem and wants a mechanism designed for it. (An > earlier `certFingerprint` field existed for exactly that gap, pinning > a peer's TLS leaf for hive-c0re's own peer HTTPS checks — removed @@ -183,7 +183,7 @@ hiveName = "pr1ma"; hiveName = "edge"; swarm.hives = { … }; swarm.hives = { … }; # byte-identical ``` -that's the point of the shape, and it removes a class of bug rather +That's the point of the shape, and it removes a class of bug rather than saving typing: a per-host peer list let two hosts hold _different_ facts about the same third hive — a stale endpoint, a rotated fingerprint — with nothing to detect the disagreement. One entry per @@ -276,7 +276,7 @@ service it points at: `services.hyperhive.swarm.snapshotStore.{address, port}` tells this hive where the swarm's `btrfs receive` endpoint is, so `hivectl agent subvol snapshot push` has somewhere to stream to. -it's genuinely swarm-scoped rather than per-peer — a swarm has exactly +It's genuinely swarm-scoped rather than per-peer — a swarm has exactly one store, because the receiver keys destinations by _agent_ so a migrating agent keeps one unbroken incremental chain. See [snapshot-store.md](../networking/snapshot-store.md). @@ -303,7 +303,7 @@ still knows its own state — you just can't see it from here. A hive publishes only once it has been given the three `swarm.statusPublish` coordinates below. A hive that has not reads -`never_reported` — it's not broken, it just hasn'thing to say upward. +`never_reported` — it's not broken, it just has nothing to say upward. | freshness | what to do about it | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/docs/swarm/ca.md b/docs/swarm/ca.md index f2ae1a76..e174a8d3 100644 --- a/docs/swarm/ca.md +++ b/docs/swarm/ca.md @@ -5,7 +5,7 @@ hive's own CA, and that hive CA signs the gateway leaf. A peer that trusts the root once validates every hive in the swarm, present and future, instead of being pinned to each one by hand. -that's the whole point of the hierarchy — it turns per-peer trust from +That's the whole point of the hierarchy — it turns per-peer trust from O(n²) hand-pinning into one anchor per swarm. ## Two provisioning modes, one structure @@ -49,7 +49,7 @@ swarm-services leaf can, and this host signs that one only under and every client sees a name mismatch. So `hive-tls` emits an eval-time **warning** naming the uncovered names. -it's deliberately not an assertion: this module can see what _it_ is +It's deliberately not an assertion: this module can see what _it_ is able to issue, but not an operator-installed sub-CA in `swarm.ca.stateDir`, an external ACME setup, or a certificate delivered by any other means. If you have arranged one, the warning is expected @@ -89,7 +89,7 @@ host: scp /var/lib/swarm-ca/root.pem :/var/lib/swarm-ca/root.pem ``` -that's the point of the hierarchy: the root is installed **once per +That's the point of the hierarchy: the root is installed **once per swarm host**, not once per peer, so a hive joining later needs no edit on the hives already running. A hive whose cert already chains to a public CA has nothing to install — `peer-config` says so instead. @@ -98,7 +98,7 @@ Handing a peer this hive's own `ca.pem` would not work even as a one-off: once a hive CA is an intermediate under the swarm root, it's no longer something a verifier can build a chain _to_ — OpenSSL won't terminate a chain at a trusted non-self-signed certificate without -`-partial_chain`. that's why the tool distributes the root, not a +`-partial_chain`. That's why the tool distributes the root, not a per-hive file. ## Adopting the hierarchy on an existing hive @@ -117,7 +117,7 @@ Adoption happens by itself, once. `hive-tls-ca.service` notices that `ca-previous.pem`, and re-issues under the root; the next leaf is signed by the new CA. -it's safe to automate here precisely because this is the +It's safe to automate here precisely because this is the all-on-one-host shape: every consumer is on this box, so "when will they have refreshed" is knowable rather than guessed. @@ -147,7 +147,7 @@ build log isn't something anyone reads twice. To keep the current CA on purpose — a hive that deliberately stays outside the hierarchy, or one mid-migration — `touch` the marker file -named in the message. that's a decision, and it's recorded as one. +named in the message. That's a decision, and it's recorded as one. A hive with **no** root configured at all isn't affected by any of this: it self-signs exactly as it always has. diff --git a/docs/swarm/secrets.md b/docs/swarm/secrets.md index 1538ba30..1ac8cb51 100644 --- a/docs/swarm/secrets.md +++ b/docs/swarm/secrets.md @@ -19,7 +19,7 @@ so the store is a perfectly good place for it. **The generator and the reader are usually in different containers.** They share the host's network namespace, which makes them feel co-located, but their -filesystem roots are separate. that's why delivery is a **host-side copy rather +filesystem roots are separate. That's why delivery is a **host-side copy rather than a bind mount**: `nixos-container` refuses to start when a bind source is missing, and a secret minted on another container's first boot doesn't exist yet. Binding it would make one container wait on a file that waits on a @@ -59,7 +59,7 @@ neither is a renaming of the other. | the secret store's unseal material | the HSM/TPM under `deploy.bao.seal = "pkcs11"`; openbao itself under `"shamir"` | in the token; or held by whoever ran `bao operator init`, which is what `"shamir"` means and why it's stated rather than inferred | n/a — only the host running the store seals anything | The three keys authelia mints for itself are generated in-container precisely -because nothing outside that container ever reads them. **that's the test worth +because nothing outside that container ever reads them. **That's the test worth applying to any secret added here** — and the client secret's plaintext half is the one row that fails it, which is the entire reason a delivery step exists. @@ -80,7 +80,7 @@ secret isn't the container that reads it. The copy is only made when authelia is enabled **on this host** and something published is being scraped; otherwise no secret is needed and none is placed. -⚠️ **don't read that delivery unit as the only way this collector is fed.** +⚠️ **Don't read that delivery unit as the only way this collector is fed.** Whether it authenticates follows the _credential_, never another service's placement: a swarm collector may run on a host that holds neither store and no authelia, and then the secret is an ordinary operator-provided file named in @@ -108,12 +108,12 @@ admit anyone to the queue, so it belongs wherever the responder runs and nowhere else. A hive that sets neither the public keys nor `autoGenerateCallout` fails at -eval, naming the option it wants. that's deliberate: a queue that started +eval, naming the option it wants. That's deliberate: a queue that started without them would accept `CONNECT {"user":"auth"}` from anyone sharing the host's network namespace, and nothing would look wrong until somebody connected. **All four or none** — the seed paths are required too, not just the public -keys. they're two halves of the same pair: the server verifies with the public +keys. They're two halves of the same pair: the server verifies with the public half, the responder signs with the private one. Supplying only the public keys used to pass eval and leave the queue with an auth-callout nobody answers, which refuses every client rather than degrading — and a refusal reaches the client as @@ -163,7 +163,7 @@ internal CA deletes that file and names its own paths in `deploy.bao.serverCertFile` / `clientCaFile`; the store itself has no opinion. A hive that reads from a store on **another** machine names the reader's half — `clientCertFile`, `clientKeyFile`, `serverCaFile` — and places that leaf by hand. -it's the one credential that can't come out of the store, being what opens it; +It's the one credential that can't come out of the store, being what opens it; everything else a hive needs does. ## The constraint that decides where the root lives diff --git a/docs/swarm/services.md b/docs/swarm/services.md index 7854b573..21a28cd5 100644 --- a/docs/swarm/services.md +++ b/docs/swarm/services.md @@ -11,7 +11,7 @@ services.hyperhive.deploy.allSwarmServices = true; **`deploy.allSwarmServices` is what "the swarm's shared services run here" means: every once-per-swarm service that's _optional_ takes its -`enable` from it.** that's the whole rule, stated once — the per-service +`enable` from it.** That's the whole rule, stated once — the per-service sections below don't repeat it, so a service that stops deriving is a visible difference rather than one more paragraph saying the same thing. diff --git a/docs/swarm/ui.md b/docs/swarm/ui.md index 5da75f2a..9cff8e28 100644 --- a/docs/swarm/ui.md +++ b/docs/swarm/ui.md @@ -57,7 +57,7 @@ between "an operator's page" and "anyone with a session". ## What it costs to be reachable The apex is published to the hive's resolver like every other swarm -service, so agent containers can resolve it. that's deliberate and it's +service, so agent containers can resolve it. That's deliberate and it's not a hole: **reachability isn't the access control here.** An agent that resolves the name and connects still has no operator session, and the subrequest denies it. diff --git a/docs/trust-boundary/boundary.md b/docs/trust-boundary/boundary.md index 84a18894..d059962d 100644 --- a/docs/trust-boundary/boundary.md +++ b/docs/trust-boundary/boundary.md @@ -110,7 +110,7 @@ agent's container uid/gid** — `o=--x` is traverse without listing, and both sockets are `0666`, which is all a dialer needs. **Ownership is declared, not repaired.** The tmpfiles.d entry written by -`SyncAgentTmpfiles` names the uid/gid directly. don't add a chown +`SyncAgentTmpfiles` names the uid/gid directly. Don't add a chown alongside it: `d` re-applies on every boot _and_ every agent spawn/destroy, so ownership set afterwards is reverted the next time any agent changes — which is exactly how this dir spent a long time at diff --git a/docs/trust-boundary/security.md b/docs/trust-boundary/security.md index e045f91b..27492f6f 100644 --- a/docs/trust-boundary/security.md +++ b/docs/trust-boundary/security.md @@ -5,7 +5,7 @@ The sections below document specific mechanisms (the state-file endpoint, nixbld isolation, privilege separation). This section frames the model they serve: **what hyperhive defends, what it deliberately doesn't, and where the -operator is accepting risk.** it's the reference for "is it safe to give an +operator is accepting risk.** It's the reference for "is it safe to give an agent capability X?". ### The trust boundary is the container, not credential storage @@ -66,7 +66,7 @@ checkpoints**, not about sandboxing the agent from its own tools: merges restricted to the operators team + a required operators-team approval (`apply_operator_branch_protection` / the config-repo equivalent) — and an agent (a write collaborator, not a repo admin) can neither change those - settings nor merge its own PR. it's **not** set up for external VCS (GitHub + settings nor merge its own PR. It's **not** set up for external VCS (GitHub etc.), though — there, operator-merge is process + accepted risk, not a technical control. - **Approvals** — config changes, schedule additions, and other @@ -161,7 +161,7 @@ services — including the core dashboard at `127.0.0.1:`, which has no application-layer auth of its own (see [`docs/scheduler/ci.md`](../scheduler/ci.md)). The `0600` token policy bounds file reads; network isolation bounds network reach. -**what's NOT exposed**: +**What's NOT exposed**: - `/home//.claude/` — mode `0700`, owned by the per-agent user ``. nixbld users can't read it. @@ -171,7 +171,7 @@ token policy bounds file reads; network isolation bounds network reach. can't read it. **Policy**: all credential files written to agent state directories MUST be mode -`0600` or stricter. don't create world-readable secret files in agent state dirs. +`0600` or stricter. Don't create world-readable secret files in agent state dirs. ### Long-term fix diff --git a/docs/web-ui/dashboard.md b/docs/web-ui/dashboard.md index aeca9803..435e0a80 100644 --- a/docs/web-ui/dashboard.md +++ b/docs/web-ui/dashboard.md @@ -852,7 +852,7 @@ life). Two consequences for anything rendering it: string; don't switch on specific values. `restarting` in particular no longer exists, because no node kind is unique to a restart. -- it's **not** exclusively operator-initiated, and **not** limited +- It's **not** exclusively operator-initiated, and **not** limited to rebuild-shaped work — `running_transients()` on the backend is a status-only test (any `Running` node whose payload names a non-empty agent lights a pill), so work the operator never