99c7bac99b
The Stop-hook was writing empty-shell episodes (task_id "unknown-<ts>",
node_chosen "unknown", events []). Root cause: buildEpisodeFromContext
read fields from the Stop-event stdin that Claude Code never sends
(primary_rationale, node_chosen, ...) and the session field name was
wrong (ctx.sessionId camelCase vs Claude Code's session_id). The hook
never read transcript_path — the only real source of session data.
New tools/observer-transcript-parser.mjs — pure parseTranscript(text,
fallbackSessionId):
- Scopes to the last turn (from the last real user prompt to EOF) —
one episode == one prompt→response cycle. A tool_result-carrier user
message is not treated as a turn boundary.
- Extracts task_id (real sessionId), timestamps (real duration),
skill_invoked events, a tool_summary event with per-tool counts,
error events (tool_result is_error), node_chosen (first skill, else
"direct"), hard_floor (invoked when a superpowers:* skill is used),
path_type (regulated/improvised), task_classification (keyword
heuristic on the prompt).
- Reasoning fields triggers_matched/candidates_considered/
boundaries_applied stay [] — not recoverable from a transcript;
their capture is a separate ADR-011 follow-up.
observer-stop-hook.mjs: reads ctx.transcript_path + ctx.session_id
(camelCase fallback kept), readFileSync best-effort, delegates to
parseTranscript. No transcript → graceful fallback to ctx defaults.
Episode schema (5 mandatory + 7-field primary_rationale) unchanged —
no normative change. Stop-event is never blocked (exit 0 on any error).
TDD: 17 parseTranscript tests + 1 buildEpisodeFromContext transcript
test. Full tools Vitest 70/70 GREEN. CLI smoke against a real 575-entry
transcript: episode populated — real task_id, ~6.5 min duration,
tool_summary {Bash:5,Read:5,Grep:1,Edit:9,Write:1}, error event.
Refs: ADR-011 brain governance §6.2 (observer evidence loop).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
2.2 KiB
Markdown
37 lines
2.2 KiB
Markdown
# Observer infrastructure
|
|
|
|
Passive evidence-loop for the Лидерра «brain» per ADR-011.
|
|
|
|
## Files
|
|
|
|
- `episodes-YYYY-MM.jsonl` — append-only JSONL, one line per Stop-event (one prompt→response turn). Written by `tools/observer-stop-hook.mjs`, which parses the session transcript (`transcript_path`) via `tools/observer-transcript-parser.mjs`.
|
|
- `notes/YYYY-MM-DD-<slug>.md` — optional MD notes for sessions with qualitative history.
|
|
- `STATUS.md` — auto-generated dashboard. Regenerated per-commit by `tools/status-md-generator.mjs`.
|
|
- `.read-counter.json` — C3 observer-of-observer counter. Updated on Read of observer files.
|
|
|
|
## Lifecycle
|
|
|
|
1. **Write**: every Stop-event appends one JSONL line, parsed from the session transcript (Stop-hook).
|
|
2. **Aggregate**: `/brain-retro` skill reads JSONL each sprint, proposes regulatory candidates.
|
|
3. **Surface**: `STATUS.md` shows controllers + monthly stats.
|
|
4. **Self-prune**: C3 warns if 54 weeks pass without any read of observer files.
|
|
|
|
## Privacy
|
|
|
|
PII filter (phone numbers, emails, tokens) is applied **before** every write — see `tools/observer-pii-filter.mjs`. gitleaks pre-push also scans observer files as part of full-history sweep.
|
|
|
|
## Don't
|
|
|
|
- Don't edit `episodes-*.jsonl` manually — it's append-only.
|
|
- Don't write outside `docs/observer/notes/` for hand-curated notes.
|
|
- Don't change `.read-counter.json` manually — it's maintained by hooks.
|
|
|
|
## HK1 pre-check (Pravila ADR-010) — verified 2026-05-19
|
|
|
|
Before registering `tools/observer-stop-hook.mjs` on Stop event (Task B5), verified collision against 6-component economy/skill-discipline architecture:
|
|
|
|
- **User-level** `~/.claude/settings.json` already has Stop hook: **agent-type** Sonnet-4.6 economy compliance verifier (analyzes transcript for claim-without-evidence violations).
|
|
- **Project-level** `.claude/settings.json` — Stop slot empty.
|
|
|
|
**Result**: no overwrite. observer-stop-hook will be added as **command-type entry in project-level Stop array**. Project + user scopes are independent slots in Claude Code 2.x — both run on the same Stop event without conflict. The agent verifier (user scope) and the JSONL appender (project scope) have non-overlapping responsibilities.
|