feat(doctor): silent-failure check batch — content-hash duplicates, undeclared DB-only pages, heartbeat staleness, db_only collector collision (#2250 #2784 #2787 #2788) (#3457)

Co-Authored-By: Time Attakc <89218912+time-attack@users.noreply.github.com>
This commit is contained in:
Garry Tan
2026-08-01 10:06:17 +08:00
committed by Sina Matian
co-authored by Time Attakc
parent aa5b9e6e2d
commit 7cbb99ffef
14 changed files with 1130 additions and 7 deletions
File diff suppressed because one or more lines are too long
+8 -1
View File
@@ -69,6 +69,12 @@ health_checks: # typed DSL to verify the integration is working
auth_user: "$TWILIO_ACCOUNT_SID"
auth_token: "$TWILIO_AUTH_TOKEN"
label: "Twilio account"
- type: heartbeat_max_age # staleness gate: FAILS `integrations doctor`
max_age: 48h # when the newest heartbeat event is older.
label: "Data freshness" # The other types are point-in-time and stay
# green even when a sense stops producing data.
output_paths: # repo-relative dirs the collector writes files to;
- daily/voice/ # lets doctor/sync warn if one lands in db_only
setup_time: 30 min # estimated time to complete setup
---
@@ -86,7 +92,8 @@ a source install, or the global install copy) are trusted. Recipes discovered at
runtime from `$GBRAIN_RECIPES_DIR` or a cwd-local `./recipes/` are marked untrusted:
they cannot run `command` health checks, cannot run `http` health checks (SSRF
defense), and cannot use the deprecated string health_check form. Untrusted recipes
can still use `env_exists` and `any_of` compositions. To ship a recipe that runs
can still use `env_exists`, `heartbeat_max_age` (reads only the local heartbeat
file — no exec, no network), and `any_of` compositions. To ship a recipe that runs
live checks, contribute it upstream so it becomes package-bundled.
## The Deterministic Collector Pattern
+12
View File
@@ -51,6 +51,18 @@ When storage configuration is present, `gbrain sync` automatically manages `.git
- Skipped when the repo is a git submodule (`.git` is a file, not a directory) — submodule .gitignore changes don't survive parent updates. A warning explains.
- Skipped entirely when `GBRAIN_NO_GITIGNORE=1` is set (escape hatch for shared-repo setups where a maintainer wants gbrain to leave .gitignore alone).
- Failures (write permission denied, etc.) are caught and logged, never crash sync.
- Warns when a configured collector's declared output dir (recipe `output_paths`
frontmatter) sits inside a `db_only` path: gitignored files never appear in the
git-walking sync diff, and `gbrain import` honors `.gitignore` too — the
collector would run green while nothing reaches the DB. The
`db_only_collector_collision` doctor check surfaces the same trap.
Related doctor coverage: `undeclared_db_only_pages` warns about DB pages with no
backing file that sit outside every declared `db_only` path. The engine's own
derive-phase output prefixes (`life/events/`, `atoms/`, `extracts/`,
`dream-cycle-summaries/`) count as implicitly declared for that check, so healthy
brains stay quiet without adding them to `gbrain.yml`. They are NOT auto-added to
`.gitignore` — only explicitly declared `db_only` dirs are.
Example `.gitignore` addition: