docs: name the actor instead of the vague 'we'/'our'

Per mara's ruling on hyperhive#4041 (Microsoft.We): keep the rule enabled,
same treatment as the 'backend' rewrites. Traced all 21 genuine hits (4
gateway.md 'Let's Encrypt' hits are a substring-match false positive, left
alone) to their actual referent: some name a specific component already
established nearby in the same doc (forge_notify, hive-github-notify's
poller, hive-forge, hive-agent/the harness, colors.css, the dashboard),
others were pure filler that adds nothing once dropped.
This commit is contained in:
iris 2026-09-09 18:10:52 +02:00 committed by mara
commit 9d02d81144
10 changed files with 44 additions and 43 deletions

View file

@ -277,7 +277,7 @@ The one gap the timestamp cut leaves: a genuine comment posted **within
`NEW_ITEM_TOLERANCE_SECS` of the merge** bumps `updated_at` close enough `NEW_ITEM_TOLERANCE_SECS` of the merge** bumps `updated_at` close enough
to `closed_at` that `state_change_is_current` returns `true` — so it takes to `closed_at` that `state_change_is_current` returns `true` — so it takes
the state-change path, dropping its body. Best of both worlds: the state-change path, dropping its body. Best of both worlds:
on the merge/close path we fetch the `latest_comment_url` comment and, when on the merge/close path `forge_notify` fetches the `latest_comment_url` comment and, when
its `created_at` is strictly **after** the subject's `closed_at` its `created_at` is strictly **after** the subject's `closed_at`
(`comment_is_after_close`) — that is it raced the merge rather than being the (`comment_is_after_close`) — that is it raced the merge rather than being the
pre-merge last comment the subject keeps — append it as a pre-merge last comment the subject keeps — append it as a
@ -286,7 +286,7 @@ pre-merge last comment the subject keeps — append it as a
and the racing comment. `forge_notify` leaves the kept pre-merge comment (created before and the racing comment. `forge_notify` leaves the kept pre-merge comment (created before
`closed_at`) off, drops a self-authored racing comment (don't `closed_at`) off, drops a self-authored racing comment (don't
echo the agent's own write), and appends nothing for a missing/unparseable `created_at`/ echo the agent's own write), and appends nothing for a missing/unparseable `created_at`/
`closed_at` (conservative — only surface a comment we can `closed_at` (conservative — only surface a comment it can
positively place after the close). Cost: one extra comment fetch on positively place after the close). Cost: one extra comment fetch on
merge/close notifications, acceptable given how rare they are. merge/close notifications, acceptable given how rare they are.
@ -300,7 +300,7 @@ original open notification and miss the review. The `open`
state only earns the `new <kind>` label when the notification's event state only earns the `new <kind>` label when the notification's event
time (`updated_at`) is within `NEW_ITEM_TOLERANCE_SECS` (120s) of the time (`updated_at`) is within `NEW_ITEM_TOLERANCE_SECS` (120s) of the
subject's `created_at`. `forge_notify` labels anything later `activity on <kind>` subject's `created_at`. `forge_notify` labels anything later `activity on <kind>`
— neutral and non-misleading, since we can't cheaply say _what_ the — neutral and non-misleading, since it can't cheaply say _what_ the
activity was without an extra reviews fetch. Missing/unparseable activity was without an extra reviews fetch. Missing/unparseable
timestamps default to `new` (preserve prior behavior rather than mask a timestamps default to `new` (preserve prior behavior rather than mask a
genuine new item). A small dependency-free genuine new item). A small dependency-free

View file

@ -128,10 +128,10 @@ application/vnd.github+json`, `X-GitHub-Api-Version` and a
header: `x-ratelimit-remaining` near 5000 is an authenticated user, header: `x-ratelimit-remaining` near 5000 is an authenticated user,
near 60 is anonymous. near 60 is anonymous.
- **GitHub sets the cadence.** It returns `X-Poll-Interval` (60s in - **GitHub sets the cadence.** It returns `X-Poll-Interval` (60s in
practice, slower than our own tick) and rate-limits callers who ignore practice, slower than the poller's own tick) and rate-limits callers who
it, so the loop re-arms to the server's interval whenever that's ignore it, so the loop re-arms to the server's interval whenever that's
_slower_ than ours. A hint faster than our own tick isn't a reason to _slower_ than the poller's. A hint faster than the poller's own tick
poll harder. isn't a reason to poll harder.
⚠️ **This needs the `notifications` scope on the PAT.** A token minted ⚠️ **This needs the `notifications` scope on the PAT.** A token minted
for `gh` + `git push` typically carries `repo` only, which is enough to for `gh` + `git push` typically carries `repo` only, which is enough to

View file

@ -279,7 +279,7 @@ straight to `new Date(s)` for display.
Every HTTP API in this repo answers failures with **RFC 9457 Every HTTP API in this repo answers failures with **RFC 9457
`application/problem+json`** (`{ type, title, status, detail }`), with the `application/problem+json`** (`{ type, title, status, detail }`), with the
human-readable cause in `detail`. An endpoint of ours returning a bare string human-readable cause in `detail`. An endpoint returning a bare string
or a bespoke error shape is a **bug to file against the daemon that or a bespoke error shape is a **bug to file against the daemon that
returned it**, not something for the caller to work around. returned it**, not something for the caller to work around.

View file

@ -1,6 +1,6 @@
# Gotchas # Gotchas
NixOS + nspawn quirks and lessons we hit the hard way. If something NixOS + nspawn quirks and hard-won lessons. If something
here looks unmotivated in the code, there's probably a story underneath. here looks unmotivated in the code, there's probably a story underneath.
Grouped by area — jump to the section that matches what you're Grouped by area — jump to the section that matches what you're
touching. touching.
@ -30,7 +30,7 @@ Not `boot.isContainer = true`. Renamed in nixos-25.11+.
…in the `.conf`. The start script's `if HOST_ADDRESS set → …in the `.conf`. The start script's `if HOST_ADDRESS set →
--network-veth` branch then forces a private netns — silently fatal --network-veth` branch then forces a private netns — silently fatal
for our web UIs (the bind is invisible from the host). Every agent for the web UIs (the bind is invisible from the host). Every agent
container runs isolated: `hive-priv`'s `write_nspawn_flags` writes container runs isolated: `hive-priv`'s `write_nspawn_flags` writes
`PRIVATE_NETWORK=1` plus a veth pair onto the host bridge, `HOST_ADDRESS` `PRIVATE_NETWORK=1` plus a veth pair onto the host bridge, `HOST_ADDRESS`
set to the bridge gateway IP (so `nixos-container`'s in-container init set to the bridge gateway IP (so `nixos-container`'s in-container init
@ -204,7 +204,7 @@ the `TIME_WAIT` case from a clean previous exit; retry covers the
genuine "previous process is still alive during a systemd restart genuine "previous process is still alive during a systemd restart
overlap" case. REUSEADDR does **not** allow two simultaneous overlap" case. REUSEADDR does **not** allow two simultaneous
`LISTEN` sockets on the same port (that would be `SO_REUSEPORT`, `LISTEN` sockets on the same port (that would be `SO_REUSEPORT`,
which we don't use) — it preserves exclusivity. not used here) — it preserves exclusivity.
## Approvals ## Approvals
@ -417,8 +417,8 @@ connects to the compositor at `127.0.0.1:<vnc_port>`.
bind-address flag (unlike the `rdp-backend`'s `--address`), so the bind-address flag (unlike the `rdp-backend`'s `--address`), so the
listener binds `0.0.0.0`. The harness relay only connects via listener binds `0.0.0.0`. The harness relay only connects via
`127.0.0.1`; the host firewall blocks the per-agent VNC port range `127.0.0.1`; the host firewall blocks the per-agent VNC port range
from external access. A future weston.ini `[vnc] address=` will from external access. A future weston.ini `[vnc] address=` would
let us restrict the bind directly once upstream supports it. restrict the bind directly, once upstream supports it.
- **PAM service name**: literal `weston-remote-access` — that's the - **PAM service name**: literal `weston-remote-access` — that's the
string libweston passes to `pam_start()` in `libweston/auth.c`. string libweston passes to `pam_start()` in `libweston/auth.c`.
Using `weston` falls back to the system default PAM stack and Using `weston` falls back to the system default PAM stack and

View file

@ -143,7 +143,7 @@ The store's **first reader** is the matrix registration token, and it's worth
saying why that one: it's an opaque 32-byte value with no second file and no saying why that one: it's an opaque 32-byte value with no second file and no
format. Authelia's OIDC secret needs a `.secret` _and_ a matching `.digest`, so format. Authelia's OIDC secret needs a `.secret` _and_ a matching `.digest`, so
starting there would have meant debugging "can a reader authenticate and get starting there would have meant debugging "can a reader authenticate and get
bytes back" and "did we write authelia's file format right" at once, with an bytes back" and "is authelia's file format right" at once, with an
SSO outage as the failure mode. SSO outage as the failure mode.
`glue-matrix-bao-token.nix` fetches it and writes the file `hive-matrix.nix` `glue-matrix-bao-token.nix` fetches it and writes the file `hive-matrix.nix`

View file

@ -265,8 +265,8 @@ to discover valid label names before triaging or to audit the label set.
- `comment --body "..."` with backticks in the body: always use - `comment --body "..."` with backticks in the body: always use
`--body-file -` with a HEREDOC to avoid shell escaping issues. `--body-file -` with a HEREDOC to avoid shell escaping issues.
- `pr-create --push` also runs `git push forge <head>` and suppresses - `pr-create --push` also runs `git push forge <head>` and suppresses
the post-push "Create a pull request" hint (we print the canonical the post-push "Create a pull request" hint (hive-forge prints the
URL ourselves). canonical URL itself).
- `attachment-get` saves to `/tmp/forge-attachment-{uuid}` by default - `attachment-get` saves to `/tmp/forge-attachment-{uuid}` by default
and prints the resolved path. Pass `-o -` to stream to stdout. and prints the resolved path. Pass `-o -` to stream to stdout.
- `artifact-get <name> --run <n>` downloads a CI Actions artifact. `<n>` - `artifact-get <name> --run <n>` downloads a CI Actions artifact. `<n>`

View file

@ -81,11 +81,11 @@ file. Because the
title is constant, `/compact` and its post-compact retry provably target title is constant, `/compact` and its post-compact retry provably target
the same session (killing the old "compact ran on a different/empty the same session (killing the old "compact ran on a different/empty
session" bug), and a `choom` invocation in the same cwd can't hijack the session" bug), and a `choom` invocation in the same cwd can't hijack the
context (it won't carry our title). claude stores sessions in context (it won't carry that title). claude stores sessions in
`~/.claude/projects/<cwd-slug>/<uuid>.jsonl` (bind-mounted persistently); `~/.claude/projects/<cwd-slug>/<uuid>.jsonl` (bind-mounted persistently);
`--name` writes the title into the file as a `custom-title` event, which `--name` writes the title into the file as a `custom-title` event, which
is what `--resume <title>` resolves against. We never pass bare is what `--resume <title>` resolves against. The harness never passes
`--continue` (it resumes the _latest_ session in the cwd — the hijack bare `--continue` (it resumes the _latest_ session in the cwd — the hijack
vector). The managed settings at `/etc/claude-code/managed-settings.json` vector). The managed settings at `/etc/claude-code/managed-settings.json`
disable automemory and dynamic workflows (the `/workflows` feature): disable automemory and dynamic workflows (the `/workflows` feature):
`disableWorkflows` keeps the `/workflows` machinery from spawning sub-runs `disableWorkflows` keeps the `/workflows` machinery from spawning sub-runs

View file

@ -123,13 +123,13 @@ color: var(--green); /* ok */
## Theme swapping — the base16 contract ## Theme swapping — the base16 contract
**The swap interface is `colors.css` — the 16 base16 slots, not our **The swap interface is `colors.css` — the 16 base16 slots, not the
semantic names.** A theme generator (for example one reading a stylix base16 semantic names.** A theme generator (for example one reading a stylix base16
scheme) overrides only `colors.css`; the semantic layer in `theme.css` scheme) overrides only `colors.css`; the semantic layer in `theme.css`
derives everything else, so the whole UI re-themes with nothing else to derives everything else, so the whole UI re-themes with nothing else to
template or regenerate. The base16 slot → semantic mapping is _internal_ template or regenerate. The base16 slot → semantic mapping is _internal_
to `theme.css` (the "Derives from" column above) — a generator never to `theme.css` (the "Derives from" column above) — a generator never
needs to know our var names, and `theme.css` + the page bundles stay needs to know the semantic var names, and `theme.css` + the page bundles stay
untouched. untouched.
**Two palettes, one contract.** `colors.css` ships both a dark default **Two palettes, one contract.** `colors.css` ships both a dark default
@ -142,24 +142,24 @@ wholesale (for example the stylix path, which writes a single unconditional
`colors.css` base16 slot defaults (Catppuccin Mocha, dark default): `colors.css` base16 slot defaults (Catppuccin Mocha, dark default):
| Slot | Default | Standard base16 role | Mapped to | | Slot | Default | Standard base16 role | Mapped to |
| -------- | --------- | -------------------- | --------------------------------------------------- | | -------- | --------- | -------------------- | ---------------------------------------------------------- |
| `base00` | `#1e1e2e` | default bg | `--bg`, (darkened) `--crust` | | `base00` | `#1e1e2e` | default bg | `--bg`, (darkened) `--crust` |
| `base01` | `#181825` | lighter bg | `--bg-elev` | | `base01` | `#181825` | lighter bg | `--bg-elev` |
| `base02` | `#313244` | selection/surface | `--border` | | `base02` | `#313244` | selection/surface | `--border` |
| `base03` | `#45475a` | comments/dim surface | `--purple-dim` | | `base03` | `#45475a` | comments/dim surface | `--purple-dim` |
| `base04` | `#585b70` | dark foreground | _(unused; kept for completeness)_ | | `base04` | `#585b70` | dark foreground | _(unused; kept for completeness)_ |
| `base05` | `#cdd6f4` | default foreground | `--fg`, (blended) `--muted`/`--subtext0` | | `base05` | `#cdd6f4` | default foreground | `--fg`, (blended) `--muted`/`--subtext0` |
| `base06` | `#f5e0dc` | light foreground | _(unused)_ | | `base06` | `#f5e0dc` | light foreground | _(unused)_ |
| `base07` | `#b4befe` | lightest | _(unused)_ | | `base07` | `#b4befe` | lightest | _(unused)_ |
| `base08` | `#f38ba8` | red | `--red` | | `base08` | `#f38ba8` | red | `--red` |
| `base09` | `#fab387` | orange | `--amber` | | `base09` | `#fab387` | orange | `--amber` |
| `base0A` | `#f9e2af` | yellow | `--yellow` | | `base0A` | `#f9e2af` | yellow | `--yellow` |
| `base0B` | `#a6e3a1` | green | `--green` | | `base0B` | `#a6e3a1` | green | `--green` |
| `base0C` | `#89dceb` | cyan | `--cyan` (our _sky_; Catppuccin's `base0C` is teal) | | `base0C` | `#89dceb` | cyan | `--cyan` (named _sky_ here; Catppuccin's `base0C` is teal) |
| `base0D` | `#89b4fa` | blue | `--blue` | | `base0D` | `#89b4fa` | blue | `--blue` |
| `base0E` | `#cba6f7` | magenta | `--purple` | | `base0E` | `#cba6f7` | magenta | `--purple` |
| `base0F` | `#f5c2e7` | extra accent | `--pink` | | `base0F` | `#f5c2e7` | extra accent | `--pink` |
Notes for theme authors: Notes for theme authors:
@ -167,8 +167,9 @@ Notes for theme authors:
derived via `color-mix()` over base16 (`--crust` = a darkened `base00`; derived via `color-mix()` over base16 (`--crust` = a darkened `base00`;
`--muted`/`--subtext0` = `base05``base00` blends). They still track a `--muted`/`--subtext0` = `base05``base00` blends). They still track a
swap automatically; no generator action needed. swap automatically; no generator action needed.
- A standard Catppuccin base16 scheme uses **teal** for `base0C`; we - A standard Catppuccin base16 scheme uses **teal** for `base0C`;
default it to **sky** (`#89dceb`) to preserve the historical accent. A `colors.css` defaults it to **sky** (`#89dceb`) to preserve the historical
accent. A
stylix Catppuccin scheme will shift `--cyan` to teal — that's the stylix Catppuccin scheme will shift `--cyan` to teal — that's the
operator's chosen scheme, working as intended. operator's chosen scheme, working as intended.
- `base04`/`base06`/`base07` aren't consumed by a semantic var today; - `base04`/`base06`/`base07` aren't consumed by a semantic var today;

View file

@ -1107,7 +1107,7 @@ the toggle and silences dispatch without revoking the OS
permission. Requires a secure context (HTTPS or localhost); on permission. Requires a secure context (HTTPS or localhost); on
other origins the controls hide themselves. Browsers typically other origins the controls hide themselves. Browsers typically
suppress notifications while the originating tab is focused — suppress notifications while the originating tab is focused —
that's a browser-level decision, not ours. that's a browser-level decision, not the dashboard's.
## Dashboard endpoints ## Dashboard endpoints

View file

@ -199,7 +199,7 @@ carry raw HTML. Rendered `<a>`s get the same target rewrite.
The JS app handles all `form[data-async]` submissions via a delegated The JS app handles all `form[data-async]` submissions via a delegated
listener: read `data-confirm`, swap the button to a spinner, POST listener: read `data-confirm`, swap the button to a spinner, POST
`application/x-www-form-urlencoded`, re-enable the button on success `application/x-www-form-urlencoded`, re-enable the button on success
(refreshState may keep the form mounted, so we don't rely on a (refreshState may keep the form mounted, so the handler doesn't rely on a
re-render), call `refreshState()`. State shapes live in re-render), call `refreshState()`. State shapes live in
`hive-c0re/src/dashboard/state_snapshot.rs::StateSnapshot` and `hive-c0re/src/dashboard/state_snapshot.rs::StateSnapshot` and
`web_ui/state.rs::StateSnapshot` — when `web_ui/state.rs::StateSnapshot` — when