12-agent audit (waves 3+4 Opus+Sonnet) on commit3759fb0found that 2 of my prior fixes had regressions, plus the prev batch missed 8 stale-text sites and 2 latent bugs. This batch closes them all. == Regressions in audit-batch (3759fb0) — now fixed == 1. PRAGMA user_version=9 placement — could silently downgrade schema on cross-version install (existing v10 DB → re-run reset to 9 → migrations replay → ALTER TABLE duplicate-column errors) - install/sql/outcome-only-schema.sql: PRAGMA moved OUTSIDE the transaction (after COMMIT) for portability across SQLite versions - install/lib-profile-outcome-only.sh::_outcome_install_ledger: added downgrade guard — reads existing user_version BEFORE running ANY init path; if >9, skips entirely (preserves newer schema) - VERIFIED: simulated v10 DB → re-run prints "skipping init to preserve newer schema"; user_version stays at 10 (was downgraded to 9 in the prior batch) [REAL: ran in this session] 2. backup_file mv→cp workaround left orphan backups + bypassed rollback contract (BACKUP_PAIRS not registered) - install/lib-profile-outcome-only.sh: now manually appends to BACKUP_PAIRS so rollback trap restores on later failure; removes the .bak on success path - Comment updated to explain the workaround vs backup_file mv 3. CLAUDE.md skip-guard "STATUS-TRUTH MARKER" was too broad — false-positive on existing kit users (RULE 0.16 doc text matches) - lib-profile-outcome-only.sh: changed grep to literal HTML comment marker `<!-- outcome-only profile (KeiSeiKit) -->` (specific marker written by the installer itself) == Tier 1 missed in prev batch — now fixed == 4. _ts_packages/package-lock.json referenced packages/cortex-ui which does NOT exist on disk → npm ci would fail with ELSPROBLEMS in CI - Regenerated via fresh `rm package-lock.json && npm install` - npm ci now exits 0 cleanly [REAL: ran in this session] - Lockfile shrunk 2403→0 lines on the cortex-ui section (full regen) 5. v3 triggers (branch length cap ≤256) were MISSING from outcome-only-schema.sql — sqlite3 fallback path skipped a schema feature that the Rust kei-ledger flow enforces, creating cross-flow drift - Added trg_agents_branch_len_ins + trg_agents_branch_len_upd mirroring migrations_list.rs:30-44 - Header comment in outcome-only-schema.sql rewritten to match current behavior (was stale) - VERIFIED: end-to-end install creates 2 triggers [REAL: sqlite3 .schema | grep trg_agents_branch_len returns 2] 6. README.md:232 said "102 crates" while README.md:9 said "105 crates" — internal contradiction in same doc - README:232 → "105 workspace crates" 7. ARCHITECTURE.md:165 "53 Rust crates + 13 shell primitives" stale - Updated to "105 Rust workspace crates (47 declared in MANIFEST.toml `full` profile) + 14 shell primitives" 8. ARCHITECTURE.md:157 "45 /commands" stale - Updated to 68 9. plugin.json + marketplace.json description strings still had pre-fix counts (23 primitives / 39 skills / 9 hooks / 12 agents) - Both rewritten to match README:9 SSoT (38 agents / 68 skills / 38 hooks / 105 workspace crates / 47 installable + 14 shell) 10. PROFILE-OUTCOME-ONLY.md:28-29 "What does NOT get installed" still cited 102/67/37/82 - Updated to 105/68/38/85 11. encyclopedia/substrate-overview.md §6/§11/§12 still said "80-char DNA"; §13 said "495 DNA indices"; §6 said "11 install profiles (.../Cursor/Continue/etc)" - All 4 sites fixed to current language (≥33-char variable, 565 DNAs, 12 install profiles) 12. docs/DNA-INDEX.md:1352 said wire format is "(80 chars)" - Updated to "(≥33 chars; role + caps slugs are variable — see docs/DNA-FORMAT.md)" == Tier 2 honesty fixes == 13. Wagner et al. 2004 citation in SLEEP-LAYER.md:26 lacked [VERIFIED] marker (W3 doc consistency caught it) - Added [VERIFIED: doi:10.1038/nature02223] + clarification that the original study did not isolate a specific sleep stage; SWS attribution comes from secondary literature (Diekelmann/Born) 14. PHILOSOPHY.md:125 attributed "overnight consolidation of un-finished intentions" to Wagner 2004 — that paper is about insight gain on the Number Reduction Task, not Zeigarnik-effect cued memory - Rewritten to accurately describe Wagner 2004's actual finding + [VERIFIED: doi:10.1038/nature02223] Verification: - `npm ci` in _ts_packages/ exits 0 [REAL: ran in this session] - `cargo check --workspace` exits 0 in _primitives/_rust [REAL: ran in this session] - Outcome-only end-to-end fresh install produces user_version=9 + 2 triggers (correct schema shape) - Outcome-only re-run against v10 DB preserves user_version=10 (downgrade guard works) - CLAUDE.md skip-guard now triggers ONLY on literal marker, not on RULE 0.16 phrase NOT addressed in this batch (deferred to a future round): - github KeiSei84/{KeiSeiKit, KeiSeiKit-1.0} 404 (user-side action: publish repo or update refs) - keigit user `keisei` does not exist (user-side: create org or rename scope) - KEIGIT_TOKEN secret not configured (user-side action) - Forgejo registration disabled (admin-side) - safeEqual timing leak in TS server (LOW per W3 reassessment) - HTTP bind 0.0.0.0 default (MEDIUM) - Unbounded request body (MEDIUM) - Outcome-only confirm-screen bypass (RULE 0.1 spirit) - Ledger fallthrough false summary - Node 20 deprecation (deadline 2026-06-02, 30 days) - Hook count triple-discrepancy (38 README / 53 DNA-INDEX / 35 maturity-row) - 100-row router claim still in README:117 + PROFILE-OUTCOME-ONLY.md - INSTALL.md numerics without [REAL:] markers - Stale .bak files accumulation policy (cosmetic) - README per-claim [REAL: ] markers for 6 of 7 numerics Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
177 lines
7.5 KiB
Bash
177 lines
7.5 KiB
Bash
# shellcheck shell=bash
|
|
# lib-profile-outcome-only.sh — the "outcome-only" minimal install profile.
|
|
#
|
|
# Installs 5 files: 2 hooks + ledger.sqlite + 1 CLAUDE.md line + (deferred)
|
|
# kei-model-router binary. Skips cortex daemon, Forgejo, launchd plists,
|
|
# no-github-push hook, 100+ Rust crates, skills, agents.
|
|
#
|
|
# Usage:
|
|
# ./install.sh --profile=outcome-only # install
|
|
# ./install.sh --profile=outcome-only --dry-run # print plan, exit 0
|
|
#
|
|
# Requires say/warn/err (lib-log), backup_file (lib-backup),
|
|
# _jq_merge_hooks (lib-hooks). Reads $KIT_DIR / $HOME_DIR /
|
|
# $HOOKS_DIR / $AGENTS_DIR. Sets $OUTCOME_DRY_RUN_FILES.
|
|
# See docs/PROFILE-OUTCOME-ONLY.md for the user-facing pitch.
|
|
|
|
OUTCOME_DRY_RUN_FILES=""
|
|
|
|
# Append a path to the dry-run list, one per line.
|
|
_outcome_dr_add() { OUTCOME_DRY_RUN_FILES="${OUTCOME_DRY_RUN_FILES}${1}"$'\n'; }
|
|
|
|
# Single-line CLAUDE.md instruction. No behavioural rewrite — one rule.
|
|
_outcome_marker_line() {
|
|
printf 'At the end of every subagent invocation, emit a STATUS-TRUTH MARKER block (RULE 0.16) so the outcome-only ledger can backfill the agents row.\n'
|
|
}
|
|
|
|
# Minimal settings-snippet — only this profile's two hooks.
|
|
_outcome_write_snippet() {
|
|
local out="$1"
|
|
cat > "$out" <<'JSON'
|
|
{
|
|
"_comment": "outcome-only profile — registers only agent-outcome-backfill + error-spike-detector",
|
|
"hooks": {
|
|
"PostToolUse": [
|
|
{ "matcher": "Agent",
|
|
"hooks": [{ "type": "command",
|
|
"command": "~/.claude/hooks/agent-outcome-backfill.sh",
|
|
"statusMessage": "outcome-backfill (RULE 0.16)..." }] },
|
|
{ "matcher": "*",
|
|
"hooks": [{ "type": "command",
|
|
"command": "~/.claude/hooks/error-spike-detector.sh",
|
|
"statusMessage": "error-spike rolling window (RULE 0.14)..." }] }
|
|
]
|
|
}
|
|
}
|
|
JSON
|
|
}
|
|
|
|
# Initialise ledger.sqlite. Tries (a) kei-ledger CLI on PATH, (b) prebuilt
|
|
# kei-ledger binary, (c) sqlite3 with embedded DDL. Warns if all three miss
|
|
# (hooks exit cleanly on missing DB so the profile is still usable).
|
|
_outcome_install_ledger() {
|
|
local db="$AGENTS_DIR/ledger.sqlite"
|
|
mkdir -p "$AGENTS_DIR"
|
|
local kl="$KIT_DIR/_primitives/_rust/kei-ledger/target/release/kei-ledger"
|
|
# Cross-version downgrade guard (audit fix 2026-05-03 W3): if an
|
|
# existing DB is at a NEWER schema (user_version > 9, e.g. user
|
|
# later upgrades to a full kit that adds a v10 migration), do NOT
|
|
# re-run any init path — the SQL fallback would otherwise reset
|
|
# user_version and the binary path may replay incompatible v9 ALTERs.
|
|
if [ -f "$db" ] && command -v sqlite3 >/dev/null 2>&1; then
|
|
local current_v
|
|
current_v=$(sqlite3 "$db" "PRAGMA user_version;" 2>/dev/null || echo 0)
|
|
if [ "${current_v:-0}" -gt 9 ] 2>/dev/null; then
|
|
say "ledger already at schema v$current_v (>9); skipping init to preserve newer schema"
|
|
return 0
|
|
fi
|
|
fi
|
|
if command -v kei-ledger >/dev/null 2>&1; then
|
|
kei-ledger --db "$db" init >/dev/null 2>&1 \
|
|
&& say "ledger initialised via kei-ledger CLI" && return 0
|
|
fi
|
|
if [ -x "$kl" ]; then
|
|
"$kl" --db "$db" init >/dev/null 2>&1 \
|
|
&& say "ledger initialised via prebuilt kei-ledger binary" && return 0
|
|
fi
|
|
if command -v sqlite3 >/dev/null 2>&1; then
|
|
sqlite3 "$db" < "$KIT_DIR/install/sql/outcome-only-schema.sql" \
|
|
&& say "ledger initialised via sqlite3 ($db)" && return 0
|
|
fi
|
|
warn "no kei-ledger or sqlite3 found; ledger NOT initialised."
|
|
warn " install one of: brew install sqlite, or rerun after a full kit install."
|
|
return 1
|
|
}
|
|
|
|
# Append STATUS-TRUTH MARKER instruction to CLAUDE.md (idempotent: skip
|
|
# if our specific marker comment is already present).
|
|
_outcome_install_claude_md() {
|
|
local cm="$HOME_DIR/.claude/CLAUDE.md"
|
|
mkdir -p "$HOME_DIR/.claude"
|
|
# Audit fix 2026-05-03 (W3): match the literal HTML comment marker we
|
|
# wrote, NOT the broad phrase "STATUS-TRUTH MARKER" — the broad phrase
|
|
# is also used in RULE 0.16 documentation that many users already have
|
|
# in their CLAUDE.md, which would cause a false-positive skip and the
|
|
# outcome-only instruction would never land.
|
|
if [ -f "$cm" ] && grep -qF '<!-- outcome-only profile (KeiSeiKit) -->' "$cm"; then
|
|
say "CLAUDE.md already contains outcome-only marker; skipping"
|
|
return 0
|
|
fi
|
|
backup_file "$cm" 2>/dev/null || true
|
|
{
|
|
[ -f "$cm" ] && printf '\n'
|
|
printf '<!-- outcome-only profile (KeiSeiKit) -->\n'
|
|
_outcome_marker_line
|
|
} >> "$cm"
|
|
say "appended STATUS-TRUTH MARKER instruction to $cm"
|
|
}
|
|
|
|
# Build kei-model-router if cargo on PATH; otherwise deferred.
|
|
_outcome_install_router_if_cargo() {
|
|
command -v cargo >/dev/null 2>&1 || {
|
|
warn "cargo not found; skipping kei-model-router build (deferred)"
|
|
return 0
|
|
}
|
|
local crate_dir="$KIT_DIR/_primitives/_rust/kei-model-router"
|
|
[ -d "$crate_dir" ] || { warn "kei-model-router crate dir missing; skipped"; return 0; }
|
|
say "building kei-model-router (release)..."
|
|
( cd "$crate_dir" && cargo build --release --quiet 2>&1 ) \
|
|
|| warn "cargo build failed; router not installed (rerun manually if desired)"
|
|
}
|
|
|
|
# Public entry — called from install.sh when --profile=outcome-only.
|
|
install_profile_outcome_only() {
|
|
local hook_src hook_dst snippet
|
|
if [ "${OUTCOME_DRY_RUN:-0}" = "1" ]; then
|
|
_outcome_dr_add "$HOOKS_DIR/agent-outcome-backfill.sh"
|
|
_outcome_dr_add "$HOOKS_DIR/error-spike-detector.sh"
|
|
_outcome_dr_add "$AGENTS_DIR/ledger.sqlite"
|
|
_outcome_dr_add "$HOME_DIR/.claude/CLAUDE.md (append 1 line)"
|
|
_outcome_dr_add "$HOME_DIR/.claude/settings.json (jq-merge 2 hooks)"
|
|
say "DRY RUN — files that WOULD be touched in \$HOME:"
|
|
printf '%s' "$OUTCOME_DRY_RUN_FILES" | sed '/^$/d' | nl -ba
|
|
return 0
|
|
fi
|
|
mkdir -p "$HOOKS_DIR" "$AGENTS_DIR"
|
|
for hook_src in \
|
|
"$KIT_DIR/hooks/agent-outcome-backfill.sh" \
|
|
"$KIT_DIR/hooks/error-spike-detector.sh" ; do
|
|
[ -f "$hook_src" ] || { err "missing source hook: $hook_src"; return 2; }
|
|
hook_dst="$HOOKS_DIR/$(basename "$hook_src")"
|
|
backup_file "$hook_dst" 2>/dev/null || true
|
|
cp -f "$hook_src" "$hook_dst" && chmod +x "$hook_dst"
|
|
say "installed hook -> $hook_dst"
|
|
done
|
|
_outcome_install_ledger
|
|
_outcome_install_claude_md
|
|
_outcome_install_router_if_cargo
|
|
snippet="$(mktemp -t outcome-snippet.XXXXXX)"
|
|
_outcome_write_snippet "$snippet"
|
|
if [ ! -f "$HOME_DIR/.claude/settings.json" ]; then
|
|
cp -f "$snippet" "$HOME_DIR/.claude/settings.json" \
|
|
&& say "created settings.json from outcome-only snippet"
|
|
else
|
|
# Audit fix 2026-05-03 (W3): backup_file MOVES the target which would
|
|
# leave _jq_merge_hooks with no file to read. Use cp -p to copy aside
|
|
# AND register the pair in BACKUP_PAIRS so the rollback trap restores
|
|
# it on later failure (was orphan-bak-not-in-rollback-contract).
|
|
local _ts
|
|
_ts=$(date +%s)
|
|
local _bak="$HOME_DIR/.claude/settings.json.bak-$_ts"
|
|
cp -p "$HOME_DIR/.claude/settings.json" "$_bak"
|
|
BACKUP_PAIRS+=("$HOME_DIR/.claude/settings.json|$_bak")
|
|
if ! _jq_merge_hooks "$snippet" "$HOME_DIR/.claude/settings.json"; then
|
|
err "settings.json merge failed; rollback trap will restore from $_bak"
|
|
rm -f "$snippet"
|
|
return 1
|
|
fi
|
|
# Success: remove our backup (rollback contract released)
|
|
rm -f "$_bak"
|
|
fi
|
|
rm -f "$snippet"
|
|
say "outcome-only profile installed."
|
|
say " hooks: agent-outcome-backfill.sh, error-spike-detector.sh"
|
|
say " ledger: $AGENTS_DIR/ledger.sqlite"
|
|
say " CLAUDE.md updated (1 line appended)"
|
|
say " router: built (if cargo present), else deferred — see docs/PROFILE-OUTCOME-ONLY.md"
|
|
}
|