feat: semantic-health baseline watermark (v1.38.0)#148
Conversation
Add an optional acknowledge-before watermark so an operator can declare
"state up to this date is seen and accepted", clearing the permanent
`watch` verdict a bulk-seeded vault gets from time-less `concept-gap` and
`confirmed_at`-anchored `batch-concept-inflation` findings, without
deleting or editing real memory.
- Config: new `health.silence_before` key in `_brain.yaml` (date-only
`YYYY-MM-DD` or full ISO-8601 timestamp), parsed/validated alongside
the existing health thresholds. Invalid value throws a BrainConfigError
(no silent fallback); absent means the feature is off and behavior is
byte-identical to before.
- CLI: `o2b brain health-baseline set <date>|now | get | clear` records
the watermark by upserting only the `silence_before` line in
`_brain.yaml`. Usage errors exit 2 via usageError; --json operational
failures use the {ok:false,message} envelope, matching state.ts.
- Surfacing filter only in reconcileSemanticHealth: a batch burst is
hidden when its windowEnd predates the watermark; a concept gap is
hidden only when every corpus entry mentioning the term is older than
it (an undated/unparseable entry counts as newer, so the filter can
only ever hide what is provably old). The verdict folds the surfaced
findings. Detection and stored files are untouched.
- Transparency: SemanticHealthReport gains an additive
`suppressed: {conceptGaps, batchInflation, baseline}` present only when
a watermark hid something; `o2b brain health` prints a
"suppressed: N finding(s) older than baseline <iso>" line, and the
brain_health MCP tool passes the field through additively (no new
tool). When unset, text and JSON output stay byte-identical.
- Extract the duplicated parseIsoUtc/ISO_DATE_ONLY_RE from stale-claim.ts
and batch-inflation.ts into shared health/iso-time.ts (one source), now
also used by the config validator and the reconcile filter.
Deviations from the brief:
- Verb named `health-baseline` (sibling to the existing `health` verb)
with the date as a POSITIONAL argument (`set 2026-01-01`) rather than a
`--value` flag as in `brain state`; a single required value reads
cleaner positionally. Subcommands are set|get|clear (no separate
list, since there is exactly one value).
- SemanticHealthInput threads dates as an optional parallel
`corpusPrincipleDates` array aligned with `corpusPrinciples` (rather
than restructuring entries to {text,timestamp}), keeping all existing
callers and tests byte-identical when the watermark is unset.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add missing watermark boundary tests (windowEnd == watermark, burst straddling the watermark, concept-gap newest mention == watermark); dedupe the fourth parseIsoUtc copy in health/thesis.ts onto the shared health/iso-time.ts source; and write _brain.yaml atomically (atomicWriteText, temp-file + rename) in writeHealthBaseline instead of a plain writeFileSync, matching schema-mutate.ts so a crash mid-write cannot truncate the vault config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
writeHealthBaseline now takes the same withFileLock + atomicWriteText lock schema-mutate.ts uses for _brain.yaml, so a concurrent health-baseline set and another _brain.yaml writer can no longer lose an update. The CLI verb's set/clear subcommands await the now-async writer. Also adds explicit MCP coverage for the brain_health suppressed mirror: present (snake_case) when silence_before hid a finding, absent entirely otherwise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CHANGELOG 1.38.0 entry with compare link, README what-is-new rotation, cli-reference section for o2b brain health-baseline and the health.silence_before watermark, mcp.md note for the additive brain_health suppressed mirror, package.json bumped to 1.38.0 with sync-version propagation to all seven manifests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 25 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds semantic-health baselining through ChangesSemantic health baseline
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Operator
participant HealthBaselineCLI
participant BrainYaml
participant BrainHealth
Operator->>HealthBaselineCLI: set baseline
HealthBaselineCLI->>BrainYaml: locked atomic update
BrainHealth->>BrainYaml: resolve health.silence_before
BrainHealth-->>Operator: surface findings and suppressed counts
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/core/brain/health-baseline.ts`:
- Around line 78-109: The applyHealthSilenceBeforeToYaml function must support
CRLF content and preserve the existing health block’s indentation. Normalize or
account for trailing carriage returns when locating health: and its child keys,
and derive the inserted or replaced silence_before indentation from the existing
block’s sibling indentation rather than always using two spaces.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 52306efa-f1c4-4239-b680-0f55e2bafefc
📒 Files selected for processing (34)
.claude-plugin/plugin.json.codex-plugin/plugin.jsonCHANGELOG.mdREADME.mddocs/cli-reference.mddocs/mcp.mdopenclaw.plugin.jsonpackage.jsonplugin.yamlplugins/codex/.codex-plugin/plugin.jsonplugins/hermes/plugin.yamlpyproject.tomlsrc/cli/brain.tssrc/cli/brain/help-text.tssrc/cli/brain/verbs/health-baseline.tssrc/cli/brain/verbs/health.tssrc/cli/brain/verbs/index.tssrc/core/brain/doctor.tssrc/core/brain/health-baseline.tssrc/core/brain/health/batch-inflation.tssrc/core/brain/health/concept-gap.tssrc/core/brain/health/iso-time.tssrc/core/brain/health/reconcile.tssrc/core/brain/health/stale-claim.tssrc/core/brain/health/thesis.tssrc/core/brain/policy.tssrc/core/brain/types.tssrc/mcp/brain/health-tools.tstests/cli/brain-health-baseline.test.tstests/core/brain/health-baseline.test.tstests/core/brain/health/concept-gap.test.tstests/core/brain/health/reconcile.test.tstests/core/brain/policy-health.test.tstests/mcp/brain-health.test.ts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/core/brain/health-baseline.ts (1)
92-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPrevent a leading blank line when writing to an empty file.
If the original file is completely empty (
!hadContent),basecurrently evaluates to"\n"(since"".replace(...) + "\n"yields"\n"). This results in the newly generated YAML unnecessarily starting with a blank line (\nhealth:\n...).Only append the newline to
baseif the file originally had content.✨ Proposed fix
if (headerIdx < 0) { - const base = normalized.replace(/[\r\n]+$/, "") + eol; + const base = hadContent ? normalized.replace(/[\r\n]+$/, "") + eol : ""; const separator = hadContent ? eol : ""; return `${base}${separator}health:${eol} silence_before: ${quoted}${eol}`; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/core/brain/health-baseline.ts` around lines 92 - 95, Update the headerIdx < 0 branch in the health baseline writer so base appends eol only when hadContent is true; preserve the separator and generated health YAML structure while ensuring an originally empty file starts directly with health:.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/core/brain/health-baseline.ts`:
- Around line 140-142: Update the sibling-indentation detection loop around
lines and the `line` variable to ignore comment-only lines before evaluating
indentation or ending the scan. Continue past trimmed lines beginning with the
YAML comment marker, then determine indentation only from the first actual child
key so inserted `silence_before` uses the correct spacing.
---
Nitpick comments:
In `@src/core/brain/health-baseline.ts`:
- Around line 92-95: Update the headerIdx < 0 branch in the health baseline
writer so base appends eol only when hadContent is true; preserve the separator
and generated health YAML structure while ensuring an originally empty file
starts directly with health:.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e16b70d6-a478-401d-8b25-4bf1052a3c67
📒 Files selected for processing (2)
src/core/brain/health-baseline.tstests/core/brain/health-baseline.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/core/brain/health-baseline.test.ts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Operators can now acknowledge vault history up to a chosen date so that one-time bulk seeds stop pinning the semantic-health verdict at
watchforever. A newhealth.silence_beforewatermark in_brain.yaml(managed byo2b brain health-baseline set/get/clear) filters advisory findings whose underlying entries are entirely older than the watermark out of the surfaced report, while detection, storage, and every finding tied to newer entries stay exactly as they are.Closes #147.
Why this matters
flowchart LR A[Bulk seed of preferences] --> B[concept-gap and batch-inflation fire] B --> C{Watermark set?} C -- no --> D[Verdict pinned at watch forever] C -- yes --> E[Findings entirely before baseline suppressed] E --> F[Verdict reflects current state] E --> G[Report prints suppressed count and baseline date] B -.entries after baseline.-> FBefore this change the only way to clear a permanently firing advisory was deleting or editing real memory. Now acknowledgement is a first-class, explicit, reversible operation that never touches stored data.
Concrete benefits
o2b brain healthatwatch; the verdict is computed from the surfaced findings only.suppressed: N finding(s) older than baseline <date>and carries an additivesuppressedobject (mirrored snake_case on MCPbrain_health).{ok:false}envelopes on--jsonoperational failures._brain.yamlupsert follows the repository convention (file lock plus atomic temp-file rename) and preserves unrelated config content byte-for-byte.iso-timemodule.What ships
src/core/brain/health/iso-time.ts- shared ISO parsing helpers (single source, previously four copies).src/core/brain/health-baseline.ts- watermark read/write with a pure YAML upsert transform.src/cli/brain/verbs/health-baseline.ts-o2b brain health-baseline set <date>|now / get / clear.src/core/brain/health/reconcile.ts- surfacing-only baseline filter, additivesuppressedreport field, verdict over surfaced findings.src/core/brain/policy.ts,types.ts-health.silence_beforeconfig parsing and validation.src/cli/brain/verbs/health.ts,src/mcp/brain/health-tools.ts- explicit suppression line in text output and additive MCP mirror.suppressed.Test plan
bun run fmt- no changesbun run lint- exactly 134 warnings, 0 errors (baseline held)bun run typecheck- cleanbun test- 6803 pass, 0 failbun run scripts/sync-version.ts --check- manifests in syncset 2026-01-01suppresses a pre-baseline burst and prints the suppressed line;clearrestores the full report; unset vault output byte-identical to v1.37.0Summary by CodeRabbit
New Features
o2b brain health-baseline set|get|clear(watermark stored in_brain.yaml).brain_healthMCP tool output now includes suppression details when baselining hides findings.Documentation
health-baselinecommand.Release