hippo-memory 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,6 +85,11 @@ hippo recall "data pipeline issues" --budget 2000
85
85
 
86
86
  ---
87
87
 
88
+ ### What's new in v0.40.0
89
+
90
+ - **Company Brain measurement gates.** Two new diagnostic commands close the last blocked rows of the Company Brain scorecard. `hippo provenance [--json] [--strict]` audits every `kind='raw'` row for `owner` + `artifact_ref`; `--strict` exits non-zero so CI can block on coverage regressions. `hippo correction-latency [--json]` reports p50 / p95 / max wall-clock lag from receipt to supersession across `superseded_by` chains. Both helpers (`buildProvenanceCoverage`, `buildCorrectionLatency`) are importable from `src/`.
91
+ - **No behavioral change to remember / recall.** Additive only: schema unchanged, retrieval untouched.
92
+
88
93
  ### What's new in v0.39.0
89
94
 
90
95
  - Security hardening release: 5 CRITICAL cross-tenant fixes (CVE candidates), GDPR Path A on archive (true RTBF), MCP per-client isolation, Slack ingestion race + idempotency hardening, auth timing leak reduction.
package/dist/cli.js CHANGED
@@ -53,6 +53,8 @@ import { importChatGPT, importClaude, importCursor, importGenericFile, importMar
53
53
  import { cmdCapture } from './capture.js';
54
54
  import { auditMemories, appendAuditEvent, } from './audit.js';
55
55
  import { listApiKeys, revokeApiKey } from './auth.js';
56
+ import { buildProvenanceCoverage } from './provenance-coverage.js';
57
+ import { buildCorrectionLatency } from './correction-latency.js';
56
58
  import * as api from './api.js';
57
59
  import * as client from './client.js';
58
60
  import { detectServer, removePidfile } from './server-detect.js';
@@ -4621,6 +4623,11 @@ Commands:
4621
4623
  --threshold <n> Overlap threshold 0-1 (default: 0.7)
4622
4624
  status Show memory health stats
4623
4625
  audit [--fix] Check memory quality (--fix removes junk)
4626
+ provenance Provenance coverage gate for kind='raw' rows
4627
+ --json Output as JSON
4628
+ --strict Exit non-zero when coverage < 100%
4629
+ correction-latency Wall-clock lag from receipt to supersession (p50/p95/max)
4630
+ --json Output as JSON
4624
4631
  outcome Apply feedback to last recall
4625
4632
  --good Memories were helpful
4626
4633
  --bad Memories were irrelevant
@@ -5008,6 +5015,62 @@ async function main() {
5008
5015
  }
5009
5016
  break;
5010
5017
  }
5018
+ case 'correction-latency': {
5019
+ requireInit(hippoRoot);
5020
+ const entries = loadAllEntries(hippoRoot);
5021
+ const report = buildCorrectionLatency(entries);
5022
+ if (flags['json']) {
5023
+ console.log(JSON.stringify(report, null, 2));
5024
+ }
5025
+ else if (report.count === 0) {
5026
+ console.log('No supersessions found. Correction latency is undefined.');
5027
+ }
5028
+ else {
5029
+ const fmt = (ms) => {
5030
+ if (ms === null)
5031
+ return 'n/a';
5032
+ if (ms < 1000)
5033
+ return `${ms}ms`;
5034
+ if (ms < 60_000)
5035
+ return `${(ms / 1000).toFixed(1)}s`;
5036
+ if (ms < 3_600_000)
5037
+ return `${(ms / 60_000).toFixed(1)}m`;
5038
+ return `${(ms / 3_600_000).toFixed(1)}h`;
5039
+ };
5040
+ console.log(`Corrections: ${report.count} total (${report.extractionCount} extraction-driven, ${report.manualCount} manual)`);
5041
+ console.log(`Latency p50: ${fmt(report.p50Ms)}, p95: ${fmt(report.p95Ms)}, max: ${fmt(report.maxMs)}`);
5042
+ if (report.extractionCount === 0 && report.manualCount > 0) {
5043
+ console.log(`\nAll ${report.manualCount} corrections were manual supersedes: no measurable observation lag.`);
5044
+ console.log(`To measure latency, route corrections through extraction (set new.extracted_from to the raw receipt).`);
5045
+ }
5046
+ }
5047
+ break;
5048
+ }
5049
+ case 'provenance': {
5050
+ requireInit(hippoRoot);
5051
+ const entries = loadAllEntries(hippoRoot);
5052
+ const coverage = buildProvenanceCoverage(entries);
5053
+ if (flags['json']) {
5054
+ console.log(JSON.stringify(coverage, null, 2));
5055
+ }
5056
+ else if (coverage.rawTotal === 0) {
5057
+ console.log('No kind=raw memories present. Coverage gate trivially satisfied.');
5058
+ }
5059
+ else {
5060
+ const pct = (coverage.coverage * 100).toFixed(1);
5061
+ console.log(`Provenance coverage: ${coverage.rawWithEnvelope}/${coverage.rawTotal} raw rows envelope-complete (${pct}%)`);
5062
+ if (coverage.gaps.length > 0) {
5063
+ console.log(`\nGaps:`);
5064
+ for (const g of coverage.gaps) {
5065
+ console.log(` ${g.id}: missing ${g.missing.join(', ')}`);
5066
+ }
5067
+ }
5068
+ }
5069
+ if (flags['strict'] && coverage.coverage < 1) {
5070
+ process.exit(1);
5071
+ }
5072
+ break;
5073
+ }
5011
5074
  case 'status':
5012
5075
  cmdStatus(hippoRoot);
5013
5076
  break;