Implement AGENTIC-WP-0011 kaizen correlation follow-up

Add bidirectional doc links (PRD §9.1, README, DESIGN §11), session-close
HELIX_* env convention, stable digest JSON contract, and digest_lookup CLI
for read-only correlate lookups. All tasks done; 163 tests green.
This commit is contained in:
2026-06-19 20:27:00 +02:00
parent 292b656952
commit 01d2affc3b
6 changed files with 279 additions and 6 deletions

View File

@@ -45,6 +45,7 @@ session_memory/
retro/build.py # windowed top-3-per-repo suggestions
retro/publish.py # hub coding_retro read model + local report
retro/__main__.py # python -m session_memory.retro
digest_lookup.py # python -m session_memory.digest_lookup (read one digest, no ingest)
config.toml # store paths, retention caps, sources, repo->domain map, curate gate
```
@@ -184,6 +185,39 @@ Writes `retro/last_retro.{json,md}` and (with `--publish`) posts an
which emits one improvement task per relevant repo. Hub publish degrades
gracefully when the hub is unreachable.
## Correlation with kaizen-agentic
Helix Forge owns **fleet-level** session digests; **kaizen-agentic** owns
**project-scoped** execution metrics (ADR-004). The two layers correlate by
optional `helix_session_uid` on project records — **link-by-reference only**;
kaizen-agentic does not ingest JSONL into this store.
| Layer | Storage |
|-------|---------|
| Fleet (here) | `session_memory/.store/mem.db``digests` table |
| Project (kaizen) | `.kaizen/metrics/<agent>/executions.jsonl` |
- **Spec:** [DESIGN-session-memory.md §11](../docs/DESIGN-session-memory.md#11-project-metrics-correlation-kaizen-agentic)
- **Contract (kaizen-agentic):** [Helix Forge Correlation Contract](https://gitea.coulomb.social/coulomb/kaizen-agentic/src/branch/main/docs/integrations/helix-forge-correlation.md)
### Session-close env export
After ingest has written the digest, agents using both layers export `HELIX_*`
vars for `kaizen-agentic metrics record` to merge (names match ADR-004):
`HELIX_SESSION_UID`, `HELIX_REPO`, `HELIX_FLAVOR`, `HELIX_TOKENS`,
`HELIX_INFRA_OVERHEAD_SHARE`, and optionally `HELIX_STORE_DB` (absolute path to
`mem.db`). See DESIGN §11.1 for field sources.
### Read one digest (for `metrics correlate`)
```bash
python -m session_memory.digest_lookup claude:abc-123 --json
HELIX_STORE_DB=/abs/path/to/mem.db python -m session_memory.digest_lookup <uid>
```
Defaults to `[store].db_path` in `config.toml`. Read-only — does not run ingest.
## Retention knobs (`[retention]` in config.toml)
| Key | Meaning |
@@ -220,3 +254,7 @@ python -m pytest # schema, adapters, store, digest, retention, ingest,
- **Phase 4** (AGENTIC-WP-0009): Measure — fleet baseline/trend + before/after
per-pattern effectiveness. The Capture → Detect → Curate → Distribute → Measure
loop is closed.
- **Weekly retro** (AGENTIC-WP-0010): windowed top-3-per-repo + hub `coding_retro`
publish.
- **Kaizen correlation** (AGENTIC-WP-0011): bidirectional doc links, session-close
`HELIX_*` env convention, `digest_lookup` read path.

View File

@@ -0,0 +1,76 @@
"""Read a single session digest from the local store (AGENTIC-WP-0011 T03).
Thin read path for ``kaizen-agentic metrics correlate`` and other consumers.
Does not run ingest.
Usage:
python -m session_memory.digest_lookup <session_uid> [--json]
HELIX_STORE_DB=/abs/path/to/mem.db python -m session_memory.digest_lookup <uid>
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from .core.store import Store
from .ingest import _expand, load_config
def resolve_store_paths(*, config_path: str | None = None) -> tuple[str, str]:
"""Resolve db + blob paths from HELIX_STORE_DB or config.toml [store]."""
env_db = os.environ.get("HELIX_STORE_DB")
if env_db:
db_path = _expand(env_db)
blob_dir = os.path.join(os.path.dirname(db_path), "blobs")
return db_path, blob_dir
here = os.path.dirname(os.path.abspath(__file__))
cfg_path = config_path or os.path.join(here, "config.toml")
store_cfg = load_config(cfg_path).get("store", {})
return _expand(store_cfg.get("db_path", "session_memory/.store/mem.db")), _expand(
store_cfg.get("blob_dir", "session_memory/.store/blobs")
)
def lookup_digest(session_uid: str, *, config_path: str | None = None) -> dict | None:
db_path, blob_dir = resolve_store_paths(config_path=config_path)
store = Store(db_path, blob_dir)
try:
return store.get_digest(session_uid)
finally:
store.close()
def main(argv: list[str] | None = None) -> int:
here = os.path.dirname(os.path.abspath(__file__))
ap = argparse.ArgumentParser(
description="Read one session digest from the Helix Forge store (no ingest)."
)
ap.add_argument("session_uid", help="Normalized session uid, e.g. claude:abc-123")
ap.add_argument("--config", default=os.path.join(here, "config.toml"),
help="config.toml when HELIX_STORE_DB is unset")
ap.add_argument("--json", action="store_true", help="print digest JSON to stdout")
args = ap.parse_args(argv)
digest = lookup_digest(args.session_uid, config_path=args.config)
if digest is None:
print(f"digest not found: {args.session_uid}", file=sys.stderr)
return 1
if args.json:
print(json.dumps(digest, indent=2, sort_keys=True))
else:
cost = digest.get("cost") or {}
tokens = cost.get("input_tokens", 0) + cost.get("output_tokens", 0)
print(f"session_uid: {digest.get('session_uid')}")
print(f"repo: {digest.get('repo')} flavor: {digest.get('flavor')}")
print(f"outcome: {digest.get('outcome')} tokens: {tokens}")
print(f"started_at: {digest.get('started_at')} ended_at: {digest.get('ended_at')}")
return 0
if __name__ == "__main__":
raise SystemExit(main())