Commit Graph
2 Commits
Author SHA1 Message Date
root de32f54337 feat(daily-digest): deliver via Zulip DM as an HTML attachment; drop mail entirely
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 6s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 13s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 11s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
Captain's decision 2026-09-26, clarified the same day: the digest is delivered to
his Zulip DM (user id 9) from abiba-bot as an HTML FILE - an attachment, not HTML
rendered in the message body and not a Markdown translation of it. Closes
daily-digest-mail-transport-20260921; the Google dependency is gone (no SMTP, no
EMAIL_PASSWORD, no app password, nothing to rotate).

WHAT CHANGES
* scripts/daily-infra-report.py: send_email() is replaced by send_zulip(), which
  writes the styled dashboard to /var/log/daily-infra-report/infra-report-<ts>.html,
  uploads it via POST /api/v1/user_uploads, then posts a SHORT Markdown pointer to
  user 9. The message body carries subject, top-line status and the attachment
  link; it does not reproduce the report.
* the 10,000-character cap is irrelevant here - it bounds message TEXT only, and
  the report travels as a file, so nothing is shrunk to fit.
* the key is abiba-bot's, already on the execution host at
  /root/.pi/agent/extensions/zulip/.env (mode 600). No vault entry was added:
  under the auth-keys charter that is a captain decision.
* daily-health-digest.prose.md -> v2.0.0 and contract-registry.yaml updated:
  transport, healthy/degraded definitions, and exit codes now match observed
  behaviour. There is NO degraded delivery leg any more - delivery is the only
  output path, so a missing or rejected key is a real failure (exit 1).
* queued defect folded in: a failed delivery used to print only the transport
  error while the report body never surfaced. Now the HTML is printed to stdout
  AND persisted on every failure, and the message names which step failed.

EVIDENCE (all against the live stack)
* real send: message id 86221 to user 9, attachment 16208 bytes at
  /user_uploads/2/45/m1cQesBFV78BGeNY2lN8xkN5/infra-report-20260926-153406.html
* the message is type=private, sender abiba-bot@chat.sysloggh.net, recipients
  [9, 21], body carries the top-line status and the attachment link, and does NOT
  contain a <table> - i.e. it does not reproduce the report
* the attachment fetches HTTP 200, 16208 bytes, content-type text/html, starts
  with <!DOCTYPE html>, and contains <style>, <table> and 16 class="card" blocks -
  it opens as a standalone styled document
* failure path: a bad key gives 'Delivery FAILED at upload: Malformed API key',
  EXIT=1, the HTML is printed to stdout and persisted to disk
* scheduled path: the run's own output is pasted in the PR

prose-lint: PASSED (19 warnings); secret scan clean.
2026-09-26 15:35:36 +00:00
root cd00cd0475 feat: add the missing daily-health-digest contract and register it
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 6s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 13s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
Backlog row daily-health-digest-contract-missing-20260925. The digest has been
dispatched on a schedule with NO contract file at all - no *daily*.prose.md,
absent from contract-registry.yaml, the only reference anywhere being the CT100
cron line. That absence is why the choice of execution copy was silently the
operator's, and how a stale clone could run the check unnoticed.

New daily-health-digest.prose.md states:
* the PINNED execution path /root/abiba-workspace/projects/prose-contracts/
  scripts/daily-infra-report.py and the pinned clone - the cron's FM_HOME clone,
  the only stable non-ephemeral copy; the treehouse clone is a per-agent working
  copy and must NOT be pinned;
* the output shape (all 18 top-level --json keys) and what a healthy run is;
* the exit-code semantics AS THEY ACTUALLY BEHAVE, verified case by case:
  missing PVE_TOKEN or an unreachable probe exits 1 and raises an alert, while
  a missing EMAIL credential is a deliberate DEGRADED leg that still exits 0 and
  still produces the report. PROBE_FAILURES and DEGRADED_LEGS are separate lists
  on purpose and must not be merged;
* the email-delivery dependency, that EMAIL_PASSWORD must be a Google app
  password, that it is failing with 534 5.7.9 as of 2026-09-25, and that a
  delivery failure is a credential dependency rather than a code defect;
* what counts as a failure versus degraded.

Registered in contract-registry.yaml (contracts entry plus index.by_category
.monitoring and index.by_domain.infrastructure). Verified: YAML parses, 31
contracts, exactly one daily-health-digest entry.
2026-09-25 11:08:28 +00:00