feat: vault metabolism Phase 2 (structural health metrics + dashboard) - #2
Conversation
…, k-core)
Phase 2a of METABOLISM.md: the timestamp-free structural layer over the
Phase-0 resolved link graph (undirected projection, dangling links excluded,
self-loops dropped, edges deduplicated).
- core/graph.go: union-find connected components (count + giant-component
ratio), Batagelj-Zaversnik k-core coreness peel (the durable-vs-transitory
axis, exposed as data not per-note noise), and orphan/leaf/island detectors.
- orphans/leaves are flagged only in connective folders (2-Areas, 3-Resources)
and only once stale; fresh capture and archives are never flagged. Islands
are small components (size 2..island_max_size) that are not the mainland
(largest component excluded) and not wholly archived, so they never
duplicate orphan findings or flag the giant component or fresh single notes.
- GraphHealth exposes component/coreness stats as the substrate the dashboard
and vault_stats will read. hebb health prints a one-line graph summary; the
--json envelope is now {findings, stats}.
- [health] config gains connective_folders, expected_orphan_folders,
orphan_stale_days, island_max_size with defaults.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 2b of METABOLISM.md: extend the web app from search-only into a
health view. New GET /api/health runs RunHealthFull and returns the
{findings, stats} envelope, refreshing the index like /api/search and
sitting behind the same loopback bind and Host guard (covered by a test).
The embedded page gains a Health tab, worklist-first: findings grouped by
type with counts, each row deep-linking to the note via obsidian://, ordered
by an honest per-type proxy (oversized by tokens, orphans/leaves by age,
islands by size; no invented access-frequency ranking, that signal is
Phase 3). Structural metric tiles (notes, links, components, giant ratio,
max k-core) sit below the worklist. No single composite health score, per
the Goodhart rule. Search view is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0603e97876
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR implements Phase 2 of the vault-metabolism plan by extending vault health from Phase-1 content detectors into Phase-2 structural graph metrics (components + k-core + orphan/leaf/island findings) and wiring a new health dashboard into hebb serve via a new /api/health endpoint.
Changes:
- Add Phase 2a structural graph model + metrics and new detectors (orphans/leaves/islands) surfaced via
core.RunHealthFulland CLI output. - Add
/api/healthendpoint and UI “Health” tab to display grouped findings and structural metric tiles. - Extend
[health]config with thresholds/folder lists and update tests accordingly.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
web/server.go |
Adds /api/health endpoint returning findings + graph stats envelope. |
web/server_test.go |
Adds endpoint shape/host-guard tests and a fixture vault for health. |
web/index.html |
Adds Health tab UI, rendering logic, and dashboard styling. |
METABOLISM.md |
Marks Phase 2 checklist item complete. |
core/vaultconfig.go |
Adds Phase 2a [health] config fields + defaulting accessors. |
core/health.go |
Introduces HealthResult + RunHealthFull, runs Phase 2a detectors, computes graph stats. |
core/health_test.go |
Adjusts “clean notes not flagged” test to only assert Phase 1 types. |
core/graph.go |
New graph implementation: build graph, components, coreness, orphan/leaf/island detection, and GraphStats. |
core/graph_test.go |
New tests covering graph construction, metrics, detectors, and config defaults. |
cli/health.go |
Extends hebb health JSON output envelope and prints structural summary line in text mode. |
cli/health_test.go |
Updates JSON/text tests for new envelope and structural summary line. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Addresses PR #2 review: - Show the Search/Health tabs on initial load instead of only after a search or the #view=health hash, so the dashboard is reachable from the landing page (Search stays the default active tab). - Remove the total note-count tile (the hoarding-incentive vanity metric METABOLISM Phase 2 forbids); keep components, giant ratio, max k-core. - Merge the duplicate class attribute on the refresh-health link (invalid HTML that left the click handler unreachable). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… archives Addresses PR #2 review: - hebb health --json again emits a top-level []Finding array (its Phase 1 contract now on main); the {findings, stats} envelope changed shape silently and broke array consumers. Graph stats remain on the text summary and the web /api/health endpoint, which is unchanged. - Island suppression now uses a new [health] archive_folders config (default 4-Archives) instead of the full expected_orphan_folders list, matching METABOLISM ("islands outside Archives") and the config comment; islands in Journal/Notes are reported again. Orphan/leaf detection still uses the full expected-orphan list. - Correct the GraphHealth doc comment to describe the real call paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks both. All six addressed in
Also flagged a separate, pre-existing bug found in passing (not in this PR's scope): Full suite green; web changes verified with a live serve smoke. Resolving these threads. |
Phase 2 of the vault-metabolism plan in METABOLISM.md, stacked on the merged Phase 0-1 work. All structural, timestamp-free, and read-only: no scoring, no access signal, no decay (those stay gated behind the Phase 3 experiment).
2a — structural graph metrics (
core/graph.go)Over the Phase-0 resolved link graph (undirected projection, dangling links excluded, self-loops dropped, edges deduplicated):
hebb healthOrphans/leaves are flagged only in connective folders (
2-Areas,3-Resources) once stale; fresh capture and archives are never flagged. Islands are small components (size 2 toisland_max_size) that are not the mainland (the largest component is excluded) and not wholly archived, so they never duplicate orphan findings, flag the giant component, or flag fresh single notes. New[health]config block for the folder lists, stale-days, and island size.2b — the dashboard (
hebb serve)New
GET /api/healthreturns{findings, stats}(refreshing the index like/api/search, behind the same loopback bind and DNS-rebinding Host guard, with a test covering it). The embedded page gains a worklist-first Health tab: findings grouped by type with counts, each row deep-linking to the note viaobsidian://, ordered by an honest per-type proxy (no invented access-frequency ranking, that signal is Phase 3). Structural metric tiles sit below. No composite "health score", per the Goodhart rule. Search view unchanged.Refinement caught by smoke-testing
The first cut of the island detector flagged the giant hub-and-spoke component and double-reported orphans as size-1 islands. Tightened so islands are size 2 to N and never the largest component, then re-verified against the real binary. (Folded into the 2a commit.)
Verification
gofmt,vet,build,test ./...all clean (uncached) after each step, plus a livehebb servesmoke confirming the endpoint, the dashboard markup, and a 403 on a foreign Host.Next
Phase 3: the access-log observer plus the two-week falsification experiment that decides whether the scoring/decay half of the plan is real.
🤖 Generated with Claude Code