#!/bin/bash # The 33 gate criteria from brief.md "Success Criteria -> For the plan". # Written in session 2 of the planning work, moved into the repo 2026-09-04 so # the only machine check on the plan is not a scratchpad file. Runnable from # anywhere: the repo root is resolved from this script's own location. # # The plan it checks lives under .claude/projects/, which is gitignored on this # public remote (.gitignore:19). A fresh clone therefore has no plan to gate -- # that is a missing measurement, not a pass, and exits 2. # # Usage: tests/plan-gates/brief_criteria.sh [path-to-plan.md] SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) ROOT=$(cd "$SCRIPT_DIR/../.." && pwd) PLAN="${1:-$ROOT/.claude/projects/2026-09-03-jobbsok-plugin-build/plan.md}" if [ ! -f "$PLAN" ]; then echo "SKIP plan not found: $PLAN" echo " (local-only artefact; nothing was measured -- this is not a pass)" exit 2 fi pass=0; fail=0 chk() { # chk "" "" "" if [ "$2" = "$3" ]; then echo "PASS $1"; pass=$((pass+1)); else echo "FAIL $1 (got '$2', want '$3')"; fail=$((fail+1)); fi } ge() { # ge "" "" "" if [ "$2" -ge "$3" ] 2>/dev/null; then echo "PASS $1 ($2 >= $3)"; pass=$((pass+1)); else echo "FAIL $1 (got '$2', want >= $3)"; fail=$((fail+1)); fi } chk "milestone order" "$(grep -oE '^## .*\bM[1-6]\b' "$PLAN" | grep -oE 'M[1-6]' | tr -d '\n')" "M1M2M3M4M5M6" if grep -oE '^### Step [0-9]+: M[1-6]' "$PLAN" | grep -oE 'M[1-6]$' | sort -c 2>/dev/null; then echo "PASS step milestone tokens non-decreasing"; pass=$((pass+1)) else echo "FAIL step milestone tokens not sorted"; fail=$((fail+1)); fi chk "all steps carry M token" "$(grep -c '^### Step [0-9]*: M[1-6]' "$PLAN")" "$(grep -c '^### Step ' "$PLAN")" ge "guard tag v1.3.0" "$(grep -c 'v1.3.0' "$PLAN")" 1 chk "no vendoring" "$(grep -n 'vendor' "$PLAN" | grep -viE 'not vendored|never vendor|ikke vendor|do not vendor' | wc -l | tr -d ' ')" "0" chk "no gemini" "$(grep -n -i 'gemini' "$PLAN" | grep -viE 'no gemini|never|forbidden|excluded|ikke' | wc -l | tr -d ' ')" "0" chk "no commands dir" "$(grep -n 'commands/' "$PLAN" | grep -viE 'no commands|never|not create|ikke' | wc -l | tr -d ' ')" "0" chk "no imap" "$(grep -n -i 'imap' "$PLAN" | grep -viE 'no imap|deferred|not built|ikke|excluded|without imap|manual' | wc -l | tr -d ' ')" "0" for s in vurderer soker sendt dialog intervju tilbud avsluttet avslag trukket; do ge "transition names $s" "$(grep -cE "(test|transisjon|transition).*\b$s\b" "$PLAN")" 1 done ge "14 days" "$(grep -cE '14 (days|dager)' "$PLAN")" 1 ge "7 days" "$(grep -cE '\b7 (days|dager)' "$PLAN")" 1 ge "10 days" "$(grep -cE '10 (days|dager)' "$PLAN")" 1 ge "instruction override" "$(grep -ciE 'instruction override|instruksjonsoverstyring' "$PLAN")" 1 ge "zero-click/exfil" "$(grep -ciE 'zero-click|exfil' "$PLAN")" 1 ge "hidden unicode" "$(grep -ciE 'hidden unicode|skjult unicode' "$PLAN")" 1 ge "FAIL_SECURE x3" "$(grep -c 'FAIL_SECURE' "$PLAN")" 3 ge "QUARANTINE_REVIEW" "$(grep -c 'QUARANTINE_REVIEW' "$PLAN")" 1 ge "Verifiser i Cowork x6" "$(grep -c 'Verifiser i Cowork' "$PLAN")" 6 ge "playwright 0.0.80" "$(grep -c '0.0.80' "$PLAN")" 1 ge "browser_run_code_unsafe" "$(grep -c 'browser_run_code_unsafe' "$PLAN")" 1 ge "PreToolUse" "$(grep -ci 'pretooluse' "$PLAN")" 1 ge "tools/list" "$(grep -c 'tools/list' "$PLAN")" 1 ge "jobbsok-tools" "$(grep -c 'jobbsok-tools' "$PLAN")" 1 ge "laering >=10 decisions" "$(grep -ciE '(>=|minst|at least) ?10 (decisions|beslutninger)' "$PLAN")" 1 ge "hard filters" "$(grep -ciE 'hard filter|harde filtre' "$PLAN")" 1 echo "----" echo "PASS=$pass FAIL=$fail" [ "$fail" -eq 0 ]