KeiSeiKit-1.0/install/sql/outcome-only-schema.sql
Parfii-bot 6b66914f97 feat(install): outcome-only minimum profile
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>
2026-05-03 16:59:53 +08:00

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;