KeiSeiKit-1.0/docs/PROFILE-OUTCOME-ONLY.md
Parfii-bot fb8a004b03 fix(release+slices): v0.14.4 publish auth fallback + 4 fix-implementer slices
After v0.14.3 npm-publish failed again with 401 Unauthorized despite
path-scoped _authToken. Direct curl probe to keigit confirmed BOTH Bearer
and Basic auth schemes work — so the issue is npm 10 not sending the
auth header in CI. Likely cause: deprecated `always-auth=true` interfered
with token resolution.

== Publish auth fix ==
- Drop `always-auth=true` (deprecated in npm 10+; warns in logs)
- Keep path-scoped `_authToken` (npm 10 canonical)
- Add legacy Basic-auth fallback rows (username/_password/email) — Forgejo
  accepts both schemes per direct probe; if one resolution path fails,
  npm tries the other
- chmod 600 on $HOME/.npmrc and project .npmrc (defense-in-depth)
- Bump 0.14.3 → 0.14.4

== Slice A — TS server hardening (Sonnet code-implementer-typescript) ==
File: _ts_packages/packages/mcp-server/src/server.ts (+3/-1)
File: _ts_packages/packages/mcp-server/src/index.ts (+14/-4)
- safeEqual constant-time path on length mismatch (timing oracle close)
- HTTP server defaults to 127.0.0.1 bind; --bind <addr> opt-in for 0.0.0.0
- Body cap 1 MiB with 413 response (DoS prevention)
- VERIFIED: tsc -b --noEmit exit 0

== Slice B — Outcome-only profile hardening (Sonnet code-implementer) ==
Files: install.sh, install/lib-args.sh, install/lib-profile-outcome-only.sh
- Confirm-screen gate before destructive install (skips on --dry-run / --yes)
- _outcome_install_ledger return value tracked → summary reflects reality
  (was: false-success "ledger: ..." when init failed)
- --dry-run silent-ignored on non-outcome profiles → now warns
- VERIFIED: end-to-end smoke against fake $HOME with `<<< "y"` — all 5
  files installed, schema v9 + 2 triggers, summary correct

== Slice D — jq-merge dedup tuple (Sonnet code-implementer) ==
File: install/lib-hooks.sh
- Replaced `unique_by(.command)` with reduce-into-object keyed on
  norm-ed command (tilde-vs-absolute path collision fix)
- Snippet-wins precedence on collision
- 3 manual scenario traces pass: tilde+tilde, absolute+tilde, idempotency

== Slice E — Doc honesty pass (Sonnet code-implementer, selective-merged) ==
Files: README.md, docs/{INSTALL,ARCHITECTURE,PROFILE-OUTCOME-ONLY}.md
Note: Slice E worktree was based on an older main commit; merged
selectively to preserve current-main values (565 DNAs, not worktree's 518)
- README:62 plugin marketplace URL: KeiSei84/KeiSeiKit → KeiSei84/KeiSeiKit-1.0
  (consistent with line 66 git clone URL + Cargo.toml repository field)
- README:9-15: per-claim [REAL: <command>] markers on all 8 numerics
- README:124-132 + PROFILE-OUTCOME-ONLY.md:43-55 + ARCHITECTURE.md:288-302:
  rephrase 100-row router claim — now describes Wilson lower-bound
  (δ=0.10, q*=0.70) continuous metric with file:line pointer to select.rs
- INSTALL.md: ESTIMATE-HTC marker covering all install-time / disk-size
  numerics in profile table (RULE 0.18 compliance)
- PROFILE-OUTCOME-ONLY.md privacy section: discloses agent-toolstats.jsonl
  sidecar (was undocumented per W3 finding)
- PROFILE-OUTCOME-ONLY.md uninstall: added 6th rm -f for .bak-* cleanup
  (closes orphan-accumulation per W3+W4 audits)

[FROM-JOURNAL: tasks.jsonl this session — 12 audit agents waves 5+6 +
4 parallel fix-implementer worktrees ran ~25 min wall-time]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 00:16:48 +08:00

5.5 KiB

outcome-only install profile

Five-file pitch: install the outcome-tracking primitive without committing to anything else. No daemon, no Forgejo, no launchd, no hundred Rust crates, no no-github-push hook, no agent generation. If you do not like what ~/.claude/agents/ledger.sqlite collects, the uninstall is a four-line shell paste at the bottom.

What gets installed

# Path Source LOC
1 ~/.claude/hooks/agent-outcome-backfill.sh hooks/agent-outcome-backfill.sh 140
2 ~/.claude/hooks/error-spike-detector.sh hooks/error-spike-detector.sh 89
3 ~/.claude/agents/ledger.sqlite install/sql/outcome-only-schema.sql (or kei-ledger init) n/a
4 one appended line in ~/.claude/CLAUDE.md the STATUS-TRUTH MARKER instruction 1
5 _primitives/_rust/kei-model-router/target/release/kei-model-router (deferred) _primitives/_rust/kei-model-router/ n/a

Plus a jq-merge of two hooks into ~/.claude/settings.json:

  • PostToolUse:Agentagent-outcome-backfill.sh
  • PostToolUse:*error-spike-detector.sh

./install.sh --profile=outcome-only --dry-run prints exactly this list and exits 0 without writing.

What does NOT get installed

  • 105 Rust workspace crates (cortex, frustration-loop, sleep-layer, …)
  • 68 skills, 38 agent manifests, 85 substrate blocks
  • kei-cortex HTTP / WS daemon
  • Forgejo, dev hub, Datasette, restic, mdbook, gdrive-import
  • launchd plists (disk-reclaim, sleep-layer cron)
  • no-github-push.sh hook (or any other Bash gate)
  • substrate PATH wiring (no edits to your shell rc files)

If you later want any of those, the kit is incremental: re-run ./install.sh --profile=core (or heavier) and the outcome-only state is preserved verbatim — both paths share ~/.claude/hooks/ and ~/.claude/agents/ledger.sqlite.

How kei-model-router activates

The router is a posterior decision rule keyed on per-task-class DNA plus a Beta posterior over (success, total) in agents.outcome. The router uses a Wilson-style lower confidence bound (δ=0.10, q*=0.70) — it falls back to "behaviour unchanged" (manifest-declared model) UNTIL the per-(task-class, model) lower-bound clears the quality bar. Typically that's tens of successful observations per pair, not a discrete 100-row threshold (see _primitives/_rust/kei-model-router/src/select.rs:74-124).

Once the posterior dominates the uniform Beta(1,1) prior the router starts producing concrete recommendations. You opt in by adding kei-model-router to a PreToolUse:Agent hook later — that step is not done by this profile. You stay in observe-only mode by default.

If cargo is on PATH at install time the binary is built into _primitives/_rust/kei-model-router/target/release/. If cargo is missing the build is skipped silently and the install is still considered complete; rebuild later with:

cd _primitives/_rust/kei-model-router && cargo build --release

Privacy posture

All outcome rows live in ~/.claude/agents/ledger.sqlite. They never leave the machine — no sync hook, no remote-push, no telemetry. Inspect with:

sqlite3 ~/.claude/agents/ledger.sqlite \
  "SELECT id, branch, status, outcome, stubs_count, started_ts FROM agents
   ORDER BY started_ts DESC LIMIT 20;"

A sidecar JSONL at ~/.claude/memory/time-metrics/agent-toolstats.jsonl accumulates per-agent token counts, tool-use stats, and durations — local-only, append-only, no network egress. Same privacy guarantees as the ledger; the uninstall recipe below removes it.

Uncomfortable with the file? rm it; the next install or agent run recreates an empty schema, no other side effects.

Uninstall

rm -f ~/.claude/hooks/agent-outcome-backfill.sh
rm -f ~/.claude/hooks/error-spike-detector.sh
rm -f ~/.claude/agents/ledger.sqlite
rm -f ~/.claude/memory/time-metrics/agent-toolstats.jsonl
# CLAUDE.md cleanup — portable across BSD (macOS) and GNU sed via awk.
# The original line `sed -i.bak '/.../,+1 d'` used the GNU `,+N` address
# extension which BSD sed does NOT support; on macOS it silently no-ops,
# leaving an orphan instruction. The awk recipe below works on both.
awk 'BEGIN{skip=0} /<!-- outcome-only profile \(KeiSeiKit\) -->/ {skip=2; next} skip>0 {skip--; next} {print}' \
    ~/.claude/CLAUDE.md > ~/.claude/CLAUDE.md.tmp \
    && mv ~/.claude/CLAUDE.md.tmp ~/.claude/CLAUDE.md
# Clean .bak-<epoch> files left by backup_file during install
rm -f ~/.claude/hooks/*.bak-* \
      ~/.claude/CLAUDE.md.bak-* \
      ~/.claude/settings.json.bak-*

Both hooks exit 0 immediately when their target script is missing, so the ~/.claude/settings.json jq-merge entries are harmless after rm. To scrub those too, drop agent-outcome-backfill.sh / error-spike-detector.sh lines from settings.json by hand.

The 5th rm removes the sidecar telemetry JSONL the backfill hook writes (per-agent token counts + tool stats; local-only, no network egress, but worth deleting if you uninstalled for privacy reasons).

Why this profile exists

A kit with 100 crates / Forgejo / launchd plists is too heavy to evaluate. A pitch you can read in four minutes and trial in five is not. This profile is the answer to "what is the smallest version of KeiSeiKit that still demonstrates the outcome loop?" — and nothing more.