R-389: key the operator cooldown per app for app_start_failed; gate 11 makes an unfiled observation refuse the push
gates / gates (push) Successful in 16s
gates / gates (push) Successful in 16s
The cooldown key was customerID:eventType plus the tier and run suffixes, and none of them names an app, so every app going down inside the same hour collapsed onto one key and only the first was mailed. Measured on demo-hp: bookstack sent 09:27:51, privatebin suppressed 09:31:51 under key=demo-hp:app_start_failed. cooldownStackSuffix is the third sibling of cooldownTierSuffix and cooldownRunSuffix, and separate for the reason the second one's docstring already gives: the existing two keep byte-identical semantics for every type that uses them. It is ALLOW-LISTED to app_start_failed and takes the event type as well as the details, unlike its siblings, and that asymmetry is the safety property. The backup family's cooldown is coarse ON PURPOSE (R-97a, R-182) so one full disk sends one digest rather than one mail per app - and crossdrive_failed is severity error, reaches the operator leg, and carries stack_name through a DIFFERENT struct, so a payload-shape rule would have split it silently. The hour itself does not change. Gate 11 refuses a push whose REPORT.md carries an observation with neither `FILED: R-NNN` nor `NOT-A-FINDING: <reason>`. It deliberately does NOT accept a passing mention of some other R-number: the lost item cited R-182 as an analogy, so "cites a register row" would have passed the very item the gate exists to catch. That discrepancy with the spec is recorded in the gate's docstring. Registered here and in the controller and agent runners. NOT in the catalog runner - it has no shared-gate mechanism and appends --all to every gate; filed as R-391 rather than left as a sentence, which is this session's lesson. PROMPT-TEMPLATE.md §15.9 corrected: "documented, NOT acted on" was the wording that invited the gap, and it now names the markers and points at the gate. R-390 filed for the golden-bake runbook's missing `pveam update`. Hub tests 709 -> 716.
This commit is contained in:
@@ -256,7 +256,8 @@ Then: [exact refusal — HTTP status, error, and the proven non-effect, e.g. "m
|
||||
`go build ./... && go vet ./... && go test ./...` — all green before proceeding. The build IS the
|
||||
typecheck; do not accumulate compile errors.
|
||||
2. **Minimal changes:** build only what's listed. No "while I'm here" refactors. Note anything worth
|
||||
fixing under "Observations" (§15) — don't act on it.
|
||||
fixing under "Observations" (§15) — don't act on it, but **do file it**: §15.9's marker rule means
|
||||
"not acted on" never means "not recorded".
|
||||
3. **No silent failures:** never swallow a parse/exec error — log it. Check a subprocess's **own** exit
|
||||
code; never pipe in a way that hides a 127. (The silent `.felhom.yml` quoting bug + the spike's
|
||||
exit-swallow lesson.)
|
||||
@@ -553,7 +554,22 @@ Report MUST include:
|
||||
`pvesm status` before/after with the space returned, and the **hub-side record's disposition named**
|
||||
(deleted / retained-with-reason / gate-blocked-with-the-command). A run that provisioned nothing says
|
||||
so. "Teardown clean" without layer 3 is not a report — it is the `sess-c` failure.
|
||||
9. **Observations:** out-of-scope items noticed — documented, NOT acted on.
|
||||
9. **Observations:** out-of-scope items noticed. **Every item carries `FILED: R-NNN` naming the
|
||||
register row opened for it in THIS session, or `NOT-A-FINDING: <reason>` declaring plainly that it
|
||||
does not warrant one.** Opening the row is the default; declaring is the exception and its reason
|
||||
is the whole of the marker.
|
||||
|
||||
**This wording replaces "documented, NOT acted on" (2026-08-24, R-389), and the old wording was
|
||||
the defect.** "Documented" was satisfied by a paragraph — and `REPORT.md` is overwritten every
|
||||
session, so a paragraph has a lifetime of one session. On 2026-08-23 a live, reproducible finding
|
||||
(only the first broken app per hour reaches the operator) was written under Observations and
|
||||
nowhere else; it had no register row and had to be re-derived the next day. That is the same shape
|
||||
as R-341, and this project's own standard says **a rule without a mechanism is a wish**.
|
||||
|
||||
**The mechanism is gate 11** (`scripts/observations_gate.py`, registered in the repo runners),
|
||||
which refuses a push whose `REPORT.md` carries an observation with neither marker. Note what it
|
||||
deliberately does NOT accept: a passing mention of some other `R-NNN`. The lost item cited `R-182`
|
||||
as an analogy, so "cites a register row" would have passed the very item the gate exists to catch.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user