REUSE + STATUS: map the new scripts, correct a second stale "not wired" claim (R-229)
gates / gates (push) Successful in 8s
gates / gates (push) Successful in 8s
REUSE.md line 62 claimed hub_confirm_gate.py is "not wired to run (R-29)" -- it is gate 3 of repo_gates.py, which both the pre-push hook and CI run. Second instance of the same stale-claim class found today, in a third file. Added rows for repo_gates.py (the runner), instructions_gate.py, install_workspace.py and rules_report.py, plus the extension point: a new .claude/rules/*.md is NOT live in the session that created it -- verify from a fresh session, never from the frontmatter. STATUS.md: one operator-facing entry -- the assistant's notes had no backup; they do now, with the same-disk and no-off-site caveats stated rather than implied.
This commit is contained in:
@@ -59,7 +59,7 @@
|
||||
| Symbol | File | Short signature | Use for | Gotchas |
|
||||
|---|---|---|---|---|
|
||||
| funcMap in `web.New` | hub/internal/web/server.go (~L67) | `template.FuncMap{...}` | ALL template helpers (`timeAgo`, `statusColor`, `json`, `hubVersion`…) | Add new template funcs HERE, nowhere else. Tested by hub/internal/web/funcmap_test.go + render_test.go. |
|
||||
| `inline_confirm_js` partial (v0.52.0) | hub/internal/web/templates/inline_confirm.html | `{{template "inline_confirm_js"}}` in the page `<head>` | Inline "question + Igen/Mégse" confirm for consequential buttons — `data-confirm="…"` on the button, or `felhomConfirm(el, q, onYes)` from JS | NEVER native `confirm()`/`prompt()` — OS-modals freeze browser automation (F-16). `scripts/hub_confirm_gate.py` asserts zero, but is **not wired to run** (R-29) — so the rule holds only as long as you keep it. Uses `requestSubmit` so `formaction` sub-buttons riding a parent form work. NOT for the danger-zone typed-confirm cascade. |
|
||||
| `inline_confirm_js` partial (v0.52.0) | hub/internal/web/templates/inline_confirm.html | `{{template "inline_confirm_js"}}` in the page `<head>` | Inline "question + Igen/Mégse" confirm for consequential buttons — `data-confirm="…"` on the button, or `felhomConfirm(el, q, onYes)` from JS | NEVER native `confirm()`/`prompt()` — OS-modals freeze browser automation (F-16). `scripts/hub_confirm_gate.py` asserts zero and IS wired — it is gate 3 of `scripts/repo_gates.py`, which the pre-push hook and CI both run (R-29 closed the wiring; corrected here 2026-08-06). Uses `requestSubmit` so `formaction` sub-buttons riding a parent form work. NOT for the danger-zone typed-confirm cascade. |
|
||||
| `timeAgo` | hub/internal/web/server.go (~L603) | `(t time.Time) string` | Human-relative timestamps in UI | — |
|
||||
| `statusColor` | hub/internal/web/server.go (~L630) | `(status string) string` | Status → design-system-v2 token (nominal/warn/crit/neutral) | Class SUFFIX only, never inline color (D4). Exception-color principle: healthy = blue/neutral. |
|
||||
| `(*Server).hostStatus` + `hostStatusClass`/`hostStatusLabel` | hub/internal/web/hosts.go (~L16/34/48) | `(lastReport *time.Time) string` | Host liveness badge | Uses the SAME threshold as HostStalenessChecker (down = 2× stale) — never invent a second definition. |
|
||||
@@ -151,6 +151,10 @@
|
||||
| Seam-injected sender for tests | hub/internal/notify/dispatcher.go `sendEmailFn` (~L33) | Function-field defaulting to the real impl in the constructor; tests overwrite it. Same idea: `mailRateLimiter.now`, `mailrelay.Sender` fake. |
|
||||
| Immediate-sync notify (per plane) | agent plane: `poke.Notifier` (`web.Server.poke` / `api.Handler.poker` via `SetPoke`/`SetPoker`) — controller plane: `intent.Hub.Bump` (`web.Server.bumpIntent`, `api.Handler.intentHub`) | EVERY desired-state mutation fires the RIGHT plane's notifier AFTER the successful store write, never on an error path (fire-after-commit). Agent-plane pokes a HOST when its generation moved (`SetHostDesired`/`Bump*HostDesired`); controller-plane bumps a CUSTOMER on a controller-visible change. Both receivers COALESCE bursts — add NO hub-side dedup. Deliberate non-sites need a documented reason (undeliverable pre-tunnel, transport removed, or no generation bump → the 60 s ticker is the pickup path). Both seams nil-safe: unset = the ≤15-min cycle still reconciles. Full site inventory: REPORT.md audit table (v0.63.0). |
|
||||
| Website page | website/index.html | UTF-8 **with BOM**; shared `<nav>`/`<footer>` byte-identical across pages (only `class="active"` differs); two-tone H1 = `<h1>…<span>accent</span></h1>`; all styling in website/assets/site.css tokens (`:root`) — zero embedded `<style>`; `?v=N` cache-bust on site.css/icons.svg; umami snippet; no CDN fonts; no emoji (sprite icons.svg instead). |
|
||||
| Gate RUNNER (the entry point) | scripts/repo_gates.py | THE one entry point — runs all six gates, streams each gate's own output, non-zero if any fails. `--fast` = no network, no container runtime. A missing gate script is a FAILURE, never a skip. `.githooks/pre-push` runs it with `--fast`; CI re-runs it on every push and mails on failure (R-168). Register a new gate as a row in `GATES`; do NOT model new work on `site_gates.py`, which is a gate, not a runner (R-161). |
|
||||
| Instruction-file gate (shared) | scripts/instructions_gate.py | Registered in all four repos' runners and **never copied** into a sibling — a copy recreates the drift it detects. Checks CLAUDE.md effective length / version literals / expired TEMPORARY, `.claude/rules/*.md` scoping, workspace-copy identity, and (check 6) the auto-memory index. Effective text = HTML comments stripped, because they are stripped before injection. **Three outcomes are deliberately different**: over-limit FAILS, an orphan WARNS, an absent store PASSES *printing its reason* — and the test asserts on that reason text, since a pass with no reason is indistinguishable from a gate that stopped running. |
|
||||
| Workspace installer | scripts/install_workspace.py | Lays down the workspace-root `CLAUDE.md` (canonical source: `documentation/runbooks/workspace-CLAUDE.md`) and the `InstructionsLoaded` hook from `workspace/hooks/`. **Unlike `install_skills.py` the targets are LIVE CONFIG, not disposable**: timestamped backup before every write, `settings.json` MERGED (owns exactly one key, `hooks.InstructionsLoaded`), a diverged CLAUDE.md reported not silently resolved, an unparseable settings.json REFUSED. Idempotent — a second run writes nothing. |
|
||||
| Rule-firing report | scripts/rules_report.py | Reads the `InstructionsLoaded` hook log and cross-references every `.claude/rules/*.md` in the workspace. **The column that matters is the empty one** — a rule that has never fired is mis-globbed or dead (built-but-never-wired, applied to instructions). Prints each silent rule's `paths:` so "wrong glob" is distinguishable from "quiet month". Caveat: the log only covers since the hook was armed. |
|
||||
| Gate script | scripts/site_gates.py | Byte-level mechanical gates (BOM, emoji codepoint ranges, nav/footer diff, analytics, banned tokens, cache-bust); run `python scripts/site_gates.py` after ANY website change; non-zero exit on failure. |
|
||||
| Fetch-validate-install (shell) | scripts/felhom-host-install.sh `step_agent_install` (~L1108) | `fetch_raw` to mktemp → syntax-check (`bash -n`) → `install -m0755 -o root -g root` → only then activate; guarded-mkfs wrapper installed BEFORE the sudoers that references it (ordering is the safety property). All mutations through `run()` (dry-run aware). |
|
||||
| Install-profile gate (shell) | scripts/felhom-host-install.sh `--mode appliance\|byo` (GL-2, v1.10.0) | Mandatory-flag profile (no default), refusals at argv time BEFORE any prompt/step, risky step gated at its CALL SITE (one auditable place — never a branch inside the step), mode persisted to state.json + resume-mismatch refusal, `FELHOM_INSTALL_STATE_DIR` override for harness isolation. Harness: scripts/hostinstall-mode-harness.sh (static refusal matrix + grep-invariants + PVE dry-transcript tier; red-proofs run against a mutated scratch copy). |
|
||||
@@ -204,6 +208,7 @@
|
||||
- **New template func**: funcMap in web.New only; add a case to hub/internal/web/funcmap_test.go.
|
||||
- **New daily job**: `scheduleDaily` in hub/cmd/hub/main.go + add pruning to `pruneAll` if data grows.
|
||||
- **New site gate**: append to scripts/site_gates.py; new website pages go into its `PAGES` list.
|
||||
- **New gate of any kind**: add a row to `GATES` in scripts/repo_gates.py — a gate reachable only by being named in a CLAUDE.md is the R-29 finding. **A new `.claude/rules/*.md` needs a `paths:` list, and is NOT live in the session that created it** — verify from a fresh session (`claude -p`) and confirm with scripts/rules_report.py, never from the frontmatter.
|
||||
- **New artifact kind (Day-0)**: consts `pkg*`/`file*` (hub/internal/web/server.go ~L27), `ArtifactManifest` fields + settings keys (hub/internal/store/store.go ~L905), `handleSetArtifacts`, `artifactManifestResponse` (handler.go), and the install script's verify step.
|
||||
- **New host-install step**: `step_*` function in scripts/felhom-host-install.sh using `run()`/`fetch_raw`/`die` helpers; keep dry-run coverage.
|
||||
- **New DR-recipe section**: `hostHalfShape`/`appHalfShape` **and** `AssembledRecipe` (hub/internal/store/dr_recipe.go) — those shape structs are **ALLOW-LISTS, not forward-compat**: a section only the emitter knows about is stored intact and **silently dropped** before the operator downloads it. No error, no log, no red test. That is R-122: the controller emitted `offsite_restic` from fork-4, all three real customers had it stored, and no delivered recipe ever contained it. Then extend `TestAssembleDRRecipe_CarriesEveryEmittedSection` (same commit) and, for a host-half section, the agent's `DRRecipeHostHalf` + BOTH copies of `testdata/host-report.golden.json` (byte-identical, cross-repo).
|
||||
|
||||
@@ -76,6 +76,16 @@ failed until someone walks it end to end with no help from us.
|
||||
|
||||
## What shipped recently
|
||||
|
||||
- **2026-08-06** — **The assistant's own working notes were on one machine with no copy anywhere.**
|
||||
Everything the assistant has learned about this system over months — where things live, which traps
|
||||
cost us an incident — sat in a folder on the build machine that no backup touched and no repository
|
||||
held. It is now included in that machine's nightly backup. **Two things you should know before
|
||||
treating that as solved:** the copy lands on the **same physical disk** as the original, so it
|
||||
survives a mistake but not a dead drive, and the build machine's backups have **no off-site copy at
|
||||
all**. Also tidied the same day: a quarter of those notes had become unreachable — filed but listed
|
||||
nowhere, so nothing would ever read them — and the instructions the assistant reads at the start of
|
||||
every session were cut roughly in half, with a check added so they cannot quietly grow back. Nothing
|
||||
was deleted. *(R-229, R-230, R-231)*
|
||||
- **2026-08-05 (late)** — **New machines now get current software again — and the disc image had been
|
||||
quietly un-updatable for days.** Approving the newer in-house service turned out to be impossible on
|
||||
its own: the system correctly refuses to publish a set where the pre-built machine image is older
|
||||
|
||||
Reference in New Issue
Block a user