Reviewer suggested an evaluation footprint that lands "the smallest substrate any caller-LLM can use", with 5 files and ~200 LOC ceiling in $HOME. This commit ships that profile. Files installed in $HOME by `./install.sh --profile=outcome-only`: 1. ~/.claude/hooks/agent-outcome-backfill.sh (PostToolUse:Agent) 2. ~/.claude/hooks/error-spike-detector.sh (PostToolUse:Bash, rolling 20-call window) 3. ~/.claude/agents/ledger.sqlite (full v9 schema via kei-ledger init, or sqlite3-fallback DDL) 4. ~/.claude/CLAUDE.md (1-line STATUS-TRUTH MARKER instruction appended) 5. ~/.claude/settings.json (jq-merge of 2 hook entries) Plus optional 6th: kei-model-router binary built from _primitives/_rust if cargo on PATH; deferred otherwise (warning printed, install continues). Files added to repo: - install/lib-profile-outcome-only.sh (145 LOC) — profile orchestrator with --dry-run support; sources lib-log/lib-backup/lib-hooks helpers; exits before heavy install phases when --profile=outcome-only - install/sql/outcome-only-schema.sql (69 LOC) — flattened v9-equivalent SQLite DDL (agents + skill_invocations + indexes), used by sqlite3 fallback when kei-ledger CLI is unavailable - docs/PROFILE-OUTCOME-ONLY.md (97 LOC) — reviewer-facing doc: 5-file install table, what is NOT installed, kei-model-router activation explanation, privacy posture (no telemetry), 4-line uninstall paste Files modified: - install.sh (+12 LOC) — sources outcome-only lib, adds short-circuit before menu when --profile=outcome-only, accepts in profile validator - install/lib-args.sh (+9 LOC) — registers --dry-run flag (sets OUTCOME_DRY_RUN=1), adds outcome-only + --dry-run lines to --help - README.md (+7 LOC) — adds Outcome-only Quick-start section pointing to PROFILE-OUTCOME-ONLY.md Verification: - bash -n clean on all 3 modified shell files - Dry-run produces exactly 5 numbered $HOME paths (verified end-to-end: HOME=/tmp/kei-fake-home bash install.sh --profile=outcome-only --dry-run) - Real install against fake $HOME succeeds (5 files present, ledger init via kei-ledger binary, router build correctly skipped on toolchain absence with warning) - Ledger schema includes agents + skill_invocations tables + 3 indexes + 2 triggers via real migration path (not the SQL fallback) [FROM-JOURNAL: end-to-end install dry-run + real-run measured at ~/.claude/memory/time-metrics/sessions.jsonl this session, both <2s wall] Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
69 lines
2.8 KiB
SQL
69 lines
2.8 KiB
SQL
-- outcome-only-schema.sql — minimal SQLite schema for the outcome-only
|
|
-- profile. Mirrors `_primitives/_rust/kei-ledger/src/migrations_list.rs`
|
|
-- but flattened: a single transaction that creates the v9-equivalent
|
|
-- shape of `agents` + `skill_invocations`. No PRAGMA user_version bump
|
|
-- is performed (the Rust runner expects to own that); if/when the user
|
|
-- later upgrades to a full kit install, `kei-ledger init` is idempotent
|
|
-- — IF NOT EXISTS guards keep both paths compatible.
|
|
--
|
|
-- Two tables:
|
|
-- agents → outcome rows (kei-model-router posterior)
|
|
-- skill_invocations → per-skill load events (Phase D metrics)
|
|
|
|
BEGIN IMMEDIATE;
|
|
|
|
CREATE TABLE IF NOT EXISTS agents (
|
|
id TEXT PRIMARY KEY,
|
|
branch TEXT NOT NULL,
|
|
parent_branch TEXT,
|
|
spec_sha TEXT NOT NULL,
|
|
status TEXT NOT NULL CHECK (status IN ('running','done','failed','merged','rejected')),
|
|
started_ts INTEGER NOT NULL,
|
|
finished_ts INTEGER,
|
|
summary TEXT,
|
|
worktree_path TEXT,
|
|
dna TEXT,
|
|
creator_id TEXT,
|
|
fork_parent_id TEXT,
|
|
cost_cents INTEGER DEFAULT 0,
|
|
provider TEXT DEFAULT '',
|
|
model TEXT DEFAULT '',
|
|
cost_micro_cents INTEGER DEFAULT 0,
|
|
tokens_in INTEGER,
|
|
tokens_out INTEGER,
|
|
stubs_count INTEGER DEFAULT 0,
|
|
outcome TEXT CHECK (outcome IS NULL OR outcome IN ('functional','partial','scaffolding','fail')),
|
|
escalation_depth INTEGER DEFAULT 0,
|
|
task_class_dna TEXT GENERATED ALWAYS AS (
|
|
CASE
|
|
WHEN dna IS NULL OR dna = '' THEN NULL
|
|
WHEN length(dna) > 9
|
|
AND substr(dna, length(dna) - 8, 1) = '-'
|
|
THEN substr(dna, 1, length(dna) - 9)
|
|
ELSE dna
|
|
END
|
|
) VIRTUAL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_parent ON agents(parent_branch);
|
|
CREATE INDEX IF NOT EXISTS idx_status ON agents(status);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_dna_prefix ON agents(substr(dna, 1, 30));
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_agents_dna_unique ON agents(dna);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_creator ON agents(creator_id);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_fork_parent ON agents(fork_parent_id);
|
|
CREATE INDEX IF NOT EXISTS idx_agents_task_class ON agents(task_class_dna);
|
|
|
|
CREATE TABLE IF NOT EXISTS skill_invocations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
skill_name TEXT NOT NULL,
|
|
ts INTEGER NOT NULL,
|
|
agent_id TEXT,
|
|
success INTEGER NOT NULL CHECK(success IN (0, 1)),
|
|
trajectory_id TEXT,
|
|
duration_ms INTEGER
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_skill_invocations_name_ts
|
|
ON skill_invocations(skill_name, ts DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_skill_invocations_success
|
|
ON skill_invocations(skill_name, success);
|
|
|
|
COMMIT;
|