initial: pi-setup workspace with skill + extension plan

This commit is contained in:
张宗平
2026-06-10 17:30:43 +08:00
commit 49e581247b
158 changed files with 28777 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# duplicate-work-guard.sh — before the evolve-cron-rpi discovery loop creates a
# tracking bead, check whether an existing OPEN or CLOSED bead already covers the
# same work. Exits 1 (with the matching bead) when a duplicate is found, 0 when
# the candidate is genuinely new.
#
# Why this exists (ag-6jt/ag-2je): a stale phase-1 handoff kept re-seeding beads
# for work already merged or already tracked. The prior guard only matched EXACT
# OPEN-bead titles, so same-surface, different-wording dups slipped through
# (ag-b8m≈ag-jov, ag-6kw≈ag-c2i — 4th recurrence). This guard matches on:
# 1. exact normalized title (lowercased, punctuation-stripped), OR
# 2. significant-token overlap (Jaccard-style: shared / candidate tokens),
# across both open and closed beads.
#
# Usage: duplicate-work-guard.sh "<candidate bead title>"
# Exit: 0 no match · 1 duplicate found · 2 usage error
# Env: DUP_GUARD_THRESHOLD (default 0.6) overlap ratio to call it a dup
# DUP_GUARD_MIN_SHARED (default 3) min shared significant tokens
# BD_BIN (default "bd") bd binary (override for tests)
set -euo pipefail
THRESHOLD="${DUP_GUARD_THRESHOLD:-0.6}"
MIN_SHARED="${DUP_GUARD_MIN_SHARED:-3}"
BD_BIN="${BD_BIN:-bd}"
usage() {
echo "usage: duplicate-work-guard.sh \"<candidate bead title>\"" >&2
exit 2
}
[ "$#" -ge 1 ] || usage
candidate="$1"
# Reject empty / whitespace-only titles.
[ -n "${candidate//[[:space:]]/}" ] || usage
# All issues including closed (the dup-seeding failure spans merged/closed work).
beads_json="$("$BD_BIN" list --all --limit 0 --json 2>/dev/null || true)"
[ -n "$beads_json" ] || beads_json='[]'
match="$(
printf '%s' "$beads_json" | jq -r \
--arg cand "$candidate" \
--argjson threshold "$THRESHOLD" \
--argjson min "$MIN_SHARED" '
# Normalize a title to a set of significant (>=3 char) tokens.
def norm: (. // "")
| ascii_downcase
| gsub("[^a-z0-9]+"; " ")
| split(" ")
| map(select(length >= 3))
| unique;
($cand | norm) as $c
| ($c | length) as $cn
| [ .[]
| . as $b
| ($b.title | norm) as $t
| ([ $t[] | select(. as $x | $c | index($x) != null) ] | length) as $shared
| { id: $b.id, status: $b.status, title: $b.title,
exact: ($cn > 0 and $t == $c),
shared: $shared,
ratio: (if $cn > 0 then ($shared / $cn) else 0 end) } ]
| map(select(.exact or (.shared >= $min and .ratio >= $threshold)))
| if length == 0 then empty
else (max_by(.ratio)) | "DUPLICATE: \(.id) [\(.status)] \(.title)"
end
'
)"
if [ -n "$match" ]; then
echo "$match"
exit 1
fi
echo "OK: no existing work matches \"$candidate\""
exit 0
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# sync-main-to-origin.sh — before the evolve-cron-rpi discovery phase selects a
# slice, fetch origin and fast-forward the local `main` to `origin/main` so that
# discovery diffs candidate slices against the TRUE merge base, not a stale local
# main.
#
# Why this exists (ag-6jt): the rpi worktree's local `main` lags `origin/main`
# (e.g. local main=04b5d7cc vs origin/main=9e9caccb). Phase-1 discovery diffed
# the candidate slice against the stale local `main`, so work already merged to
# origin/main read as "open" — repeatedly re-seeding duplicate work/beads
# (ag-b8m≈ag-jov, ag-6kw≈ag-c2i, 4th recurrence). The work-selection-ladder
# reference claimed "the cron syncs local main to origin/main before discovery",
# but no code actually did it. This script makes that claim real and testable,
# and pairs with duplicate-work-guard.sh (the grep-existing-beads half).
#
# Behavior:
# 1. `git fetch <remote>` (so refs/remotes/<remote>/main is current).
# 2. Resolve the diff base to <remote>/main — ALWAYS, never local main.
# 3. Fast-forward the LOCAL `main` ref to <remote>/main without forcing:
# - if `main` is checked out: `git merge --ff-only`,
# - otherwise: `git fetch <remote> main:main` (refuses a non-fast-forward).
# 4. Print the resolved diff base SHA so callers/tests can assert discovery
# diffs against <remote>/main, not the previously-stale local main.
#
# Usage: sync-main-to-origin.sh [<remote>] (remote defaults to "origin")
# Exit: 0 synced (or already up to date) · non-zero on fetch/ff failure
# Output: final line is "DIFF_BASE: <remote>/main <sha>"
# Env: SYNC_MAIN_REMOTE (default "origin") overrides the remote name.
set -euo pipefail
REMOTE="${1:-${SYNC_MAIN_REMOTE:-origin}}"
# 1. Refresh remote-tracking refs.
if ! git fetch "$REMOTE" >/dev/null 2>&1; then
echo "FAIL: git fetch $REMOTE failed (offline or remote unreachable)" >&2
exit 1
fi
# The authoritative diff base after sync is ALWAYS <remote>/main, never local main.
if ! ORIGIN_MAIN_SHA="$(git rev-parse --verify --quiet "refs/remotes/$REMOTE/main")"; then
echo "FAIL: $REMOTE/main does not exist after fetch" >&2
exit 1
fi
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
if [ "$CURRENT_BRANCH" = "main" ]; then
# main is checked out — fast-forward only (never a merge commit, never force).
if ! git merge --ff-only "$REMOTE/main" >/dev/null 2>&1; then
echo "FAIL: local main is not a fast-forward of $REMOTE/main (diverged); resolve manually" >&2
exit 1
fi
else
# main is not checked out — move the ref directly, fast-forward only.
# `git fetch <remote> main:main` refuses a non-fast-forward update (no force).
if ! git fetch "$REMOTE" main:main >/dev/null 2>&1; then
echo "FAIL: cannot fast-forward local main to $REMOTE/main (diverged); resolve manually" >&2
exit 1
fi
fi
# Emit the resolved diff base so discovery (and tests) can confirm it is
# <remote>/main, not the previously-stale local main.
echo "DIFF_BASE: $REMOTE/main $ORIGIN_MAIN_SHA"
exit 0
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"
PASS=0; FAIL=0
check() { if bash -c "$2"; then echo "PASS: $1"; PASS=$((PASS + 1)); else echo "FAIL: $1"; FAIL=$((FAIL + 1)); fi; }
check "SKILL.md exists" "[ -f '$SKILL_DIR/SKILL.md' ]"
check "SKILL.md has YAML frontmatter" "head -1 '$SKILL_DIR/SKILL.md' | grep -q '^---$'"
check "SKILL.md has name: evolve" "grep -q '^name: evolve' '$SKILL_DIR/SKILL.md'"
check "references/ directory exists" "[ -d '$SKILL_DIR/references' ]"
check "references/ has at least 1 file" "[ \$(ls '$SKILL_DIR/references/' | wc -l) -ge 1 ]"
check "SKILL.md mentions kill switch" "grep -qi 'kill switch' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions fitness" "grep -qi 'fitness' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions GOALS.yaml" "grep -q 'GOALS.yaml' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions cycle" "grep -qi 'cycle' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions /rpi" "grep -q '/rpi' '$SKILL_DIR/SKILL.md'"
# Behavioral contracts from retro learnings (2026-02-12)
check "SKILL.md has KILL file path" "grep -q 'KILL' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents regression detection" "grep -qi 'regression' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents snapshot enforcement" "grep -qi 'snapshot' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents session_start_sha" "grep -qi 'session.start.sha\|cycle_start_sha' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents continuous values" "grep -qi 'continuous\|value.*threshold' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents regression gate" "grep -qi 'regression gate' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents post-cycle snapshot" "grep -q 'fitness-.*-post' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents oscillation detection" "grep -qi 'oscillat' '$SKILL_DIR/SKILL.md'"
# Design-level checks (2026-03-01)
check "Step 0 has oscillation sweep (always-on)" "grep -q 'Pre-populate quarantine list' '$SKILL_DIR/SKILL.md'"
check "Step 5 has wiring script pre-flight check" "grep -q 'if.*check-wiring-closure.sh' '$SKILL_DIR/SKILL.md'"
check "No ambiguous YAML fallback in Step 2" "! grep -q 'run each goal.*check command manually' '$SKILL_DIR/SKILL.md'"
check "CLI required for fitness measurement" "grep -q 'CLI is required for fitness measurement' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents harvested-first selection order" "grep -Fq 'Harvested \`.agents/rpi/next-work.jsonl\` work' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents generator ladder" "grep -q 'Testing improvements' '$SKILL_DIR/SKILL.md' && grep -q 'Validation tightening and bug-hunt passes' '$SKILL_DIR/SKILL.md' && grep -q 'Concrete feature suggestions' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents dormancy as last resort" "grep -q 'Dormancy is last resort' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents queue claim before consume" "grep -q 'claim it first' '$SKILL_DIR/SKILL.md' && grep -Fq 'keep \`consumed: false\`' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents session-state persistence" "grep -q 'session-state.json' '$SKILL_DIR/SKILL.md'"
check "SKILL.md documents immediate queue reread after /rpi" "grep -Fq 'immediately re-read \`.agents/rpi/next-work.jsonl\`' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions repo execution profile" "grep -qi 'repo execution profile' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions startup_reads" "grep -q 'startup_reads' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions validation_commands" "grep -q 'validation_commands' '$SKILL_DIR/SKILL.md'"
check "SKILL.md mentions definition_of_done" "grep -q 'definition_of_done' '$SKILL_DIR/SKILL.md'"
echo ""; echo "Results: $PASS passed, $FAIL failed"
[ $FAIL -eq 0 ] && exit 0 || exit 1