Remove or fix broken documentation links that accumulate silently:
- container_view.rs: HiveEnv reference
- forge/mod.rs: READY_TIMEOUT and webhook handler links
- workers/knowledge.rs: webhook handler link
- job_queue/model.rs: Claim::deps and WireNode::data references
- stats/hive_stats.rs: read_skill_breakdown reference
- stores/audit_log.rs: global() reference
- workers/agent_sockets.rs: ambiguous agent_sockets::write reference
- coordinator.rs: systemd.services.<harness> formatting
- resource_limits.rs: ambiguous write/read references
Some broken links were to deleted functions/types; these are replaced
with prose descriptions. Others referenced items outside this crate or
were private; these are replaced with plain text references or qualified
paths as appropriate.
Fixes: #3245
Closes the #3110 split — lib.rs is now just the crate doc comment and
the pub mod list.
journal.rs's new doc comment fixes a pre-existing bug: the old
JournalPriority doc text in lib.rs was actually half Capability's doc
(a leftover from an earlier reorder that moved the code but not the
comment above it).
`QueueInner` was `{ sched, node_rt }`, where `node_rt` held exactly one
datum per node: the `build_logs` row id. It existed because a `hive_jobq`
node payload is immutable after insert while the log row is created when
the build starts — so the link could not ride the node.
Invert it: the log row names its node (`build_logs.node_id`, one migration
in the existing `schema_versions` framework). Same single-home property,
in the direction the type system allows.
`QueueInner` is now just the scheduler. That is the point: the queue holds
no per-node side map, so nothing has to be locked alongside the graph.
Deleted as a consequence, each surfaced by dead-code analysis after the
edit above rather than predicted:
- `NodeRuntime`, `node_rt`, `set_build_log_id`, and `build_log_id_of`
(which linear-scanned the map to match a wire `u64` against opaque
`NodeId`s). The lookup is an indexed query now.
- `struct Ctx`, entirely. It carried `coord` + `dag_id` + `node_id` into
the executors so the build-log callback could reach the queue; without
the callback, `coord`/`dag_id` were never read and `node_id` was already
on the `Claim` both executors receive.
- `QueueInner::node_running`, which existed only for `set_build_log_id`'s
"only while running" guard.
- The `Fn(i64)` callbacks on `prebuild_toplevel` / `swap_update` /
`priv_run_inner`, replaced by a `node_id: Option<u64>` passed down. The
id travels one way now instead of being registered back.
`meta.rs`'s `nix_logged` passes `None` deliberately: its callers reach it
from outside the queue as well as inside, and nothing reads the link for
them yet.
`id_for_node` takes `MAX(id)` rather than assuming uniqueness — a retried
node opens a second row and the panel wants the current attempt. The test
moved to where the behaviour lives and covers that, plus survival across
completion and non-collision with node-less rows.
Both webhook registrations (knowledge push + config-PR pull_request) now
use the public hive domain instead of loopback:
https://<HYPERHIVE_HIVE_DOMAIN>/webhook/{knowledge,config-pr}
This routes deliveries through the gateway, bypassing the Forgejo SSRF
guard that blocked loopback delivery and silently broke the config-PR
merge flow since launch.
Changes:
- webhook_secret: new module — auto-generate + persist a 32-byte HMAC
secret to STATE_ROOT/webhook-secret on first startup; verify
X-Hub-Signature-256 on every incoming webhook POST (HMAC-SHA256).
- forge/mod.rs: ensure_config_pr_webhook now takes hive_domain +
webhook_secret; sets secret in Forgejo hook config.
- workers/knowledge.rs: ensure_webhook same update.
- dashboard/webhook.rs: both handlers read raw Bytes first, verify HMAC,
then parse JSON. Returns 401 on signature mismatch.
- dashboard/mod.rs: AppState carries webhook_secret; serve() takes it.
- main.rs: load/generate secret at startup; pass to registration tasks
+ dashboard; add 5-minute config-PR polling fallback task.
- forge/config_pr_poll.rs: new — scan agent-configs/* for open PRs with
no pending MergeConfigPr approval; queue them. Idempotent.
- stores/approvals.rs: has_pending_merge_config_pr() for poll dedup.
- nix/modules/hive-gateway.nix: remove dashboardAuth from /webhook/
location (HMAC replaces basic auth for webhook endpoints; Forgejo
cannot send HTTP Basic credentials with webhook deliveries).
Two hardening items from argus's review of #2374:
1. PR state check at submission:
- Add `pr_is_open(repo, pr)` to forge/pr_merge.rs using
`repo_get_pull_request` + `StateType` — early error if the PR is
already closed or merged instead of queuing a card that fails later
- Call it in `submit_merge_config_pr` before fetching the head sha
2. Atomic fetched_sha INSERT:
- Add `fetched_sha: Option<&str>` to `Approvals::submit_kind` so
the sha can be included in the INSERT rather than a follow-up UPDATE
- MergeConfigPr already knows the sha before inserting the row
(pr_head_sha runs first) → pass `Some(&sha)`, drop the separate
`set_fetched_sha` call → truly atomic
- ApplyCommit still needs two writes (sha resolved by git_fetch_to_tag
after the row exists) → pass `None`, `set_fetched_sha` unchanged
- All other callers (InitConfig, Spawn, UpdateMetaInputs,
SchedulePrompt) pass `None` — no behavioural change
- Add `fetched_sha_in_insert_is_readable_via_get` test covering the
MergeConfigPr path
Replace the try-and-ignore-duplicate-column approach in apply_migrations
with proper schema versioning using a shared schema_versions table.
## mechanism
New function: db::apply_versioned_migrations(conn, subsystem,
legacy_column, migrations). Tracks the applied-migration count in a
schema_versions table (one row per subsystem key). Only migrations past
the stored version run.
Legacy detection: pre-versioning databases have no schema_versions row.
The legacy_column tuple (table, column) identifies a column that exists
only in a fully-migrated legacy database. If present, all known
migrations are skipped. If absent, migrations start from 0.
## stores migrated
- broker: removes bespoke ensure_message_columns / ensure_reminder_columns.
Unified into BROKER_MIGRATIONS (v1-v5). Legacy detector: messages.priority
(added in the last pre-versioning migration).
- approvals: 4 historical migrations (v1-v4). Legacy detector:
approvals.submitter.
- operator_questions: 3 historical migrations (v1-v3). Legacy detector:
operator_questions.target.
- scheduled_prompts: 1 historical migration (v1). Legacy detector:
scheduled_prompts.paused_at_unix.
apply_migrations removed (no callers).
## tests (db.rs)
- fresh_install_runs_all_migrations
- legacy_install_skips_all_migrations
- partial_migration_resumes_from_version
- already_at_latest_is_noop
- multiple_stores_in_same_db