@mmerterden/multi-agent-pipeline 12.7.0 → 12.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +207 -0
- package/install/_common.mjs +48 -0
- package/install/_dev-only-files.mjs +125 -5
- package/install/claude.mjs +14 -8
- package/install/copilot.mjs +5 -8
- package/package.json +17 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -1
- package/pipeline/lib/credential-store.sh +20 -0
- package/pipeline/multi-agent-refs/_account-picker.md +1 -1
- package/pipeline/multi-agent-refs/_dev-context.md +1 -1
- package/pipeline/multi-agent-refs/_repo-picker.md +1 -1
- package/pipeline/multi-agent-refs/features/review-multi-repo.md +65 -0
- package/pipeline/multi-agent-refs/features/url-enrichment.md +93 -0
- package/pipeline/multi-agent-refs/phases/operations.md +28 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +3 -83
- package/pipeline/multi-agent-refs/phases/phase-2-planning.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +1 -2
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +50 -62
- package/pipeline/schemas/prefs.schema.json +6 -0
- package/pipeline/scripts/_smoke-root.sh +61 -0
- package/pipeline/scripts/agent-guard.py +57 -3
- package/pipeline/scripts/audit-log.sh +25 -0
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +21 -7
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-1-analysis.json +0 -25
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-2-plan.json +0 -30
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-review.json +0 -20
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/expected/phase-4-triage.json +0 -15
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/01-ios-bugfix-darkmode/task.json +0 -12
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-2-plan.json +0 -43
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-review.json +0 -35
- package/pipeline/eval/golden-tasks/02-android-feature-compose/expected/phase-4-triage.json +0 -35
- package/pipeline/eval/golden-tasks/02-android-feature-compose/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/02-android-feature-compose/task.json +0 -12
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-2-plan.json +0 -42
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-review.json +0 -20
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/expected/phase-4-triage.json +0 -15
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/03-backend-python-ratelimit/task.json +0 -12
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-2-plan.json +0 -40
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-review.json +0 -20
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/expected/phase-4-triage.json +0 -15
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/04-frontend-next-hydration/task.json +0 -12
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-2-plan.json +0 -42
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-review.json +0 -28
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/expected/phase-4-triage.json +0 -27
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/05-ios-security-keychain/task.json +0 -12
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-2-plan.json +0 -41
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-review.json +0 -12
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/expected/phase-4-triage.json +0 -6
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/06-android-refactor-usecase/task.json +0 -12
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-1-analysis.json +0 -29
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-2-plan.json +0 -42
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-review.json +0 -28
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/expected/phase-4-triage.json +0 -27
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/07-backend-node-idempotency/task.json +0 -12
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-1-analysis.json +0 -25
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-2-plan.json +0 -31
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-review.json +0 -12
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/expected/phase-4-triage.json +0 -18
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/metadata.json +0 -14
- package/pipeline/eval/golden-tasks/08-ios-auth-consensus-unverified/task.json +0 -12
- package/pipeline/eval/golden-tasks/README.md +0 -65
- package/pipeline/eval/intent-cases.json +0 -40
- package/pipeline/eval/run-metrics-fixture.json +0 -93
- package/pipeline/eval/triage/01-empty-findings/expected.json +0 -6
- package/pipeline/eval/triage/01-empty-findings/input.json +0 -5
- package/pipeline/eval/triage/01-empty-findings/notes.md +0 -7
- package/pipeline/eval/triage/02-real-blocker/expected.json +0 -15
- package/pipeline/eval/triage/02-real-blocker/input.json +0 -14
- package/pipeline/eval/triage/02-real-blocker/notes.md +0 -7
- package/pipeline/eval/triage/03-out-of-scope-defer/expected.json +0 -18
- package/pipeline/eval/triage/03-out-of-scope-defer/input.json +0 -14
- package/pipeline/eval/triage/03-out-of-scope-defer/notes.md +0 -10
- package/pipeline/eval/triage/04-false-positive-reject/expected.json +0 -18
- package/pipeline/eval/triage/04-false-positive-reject/input.json +0 -14
- package/pipeline/eval/triage/04-false-positive-reject/notes.md +0 -10
- package/pipeline/eval/triage/05-mixed-classification/expected.json +0 -43
- package/pipeline/eval/triage/05-mixed-classification/input.json +0 -38
- package/pipeline/eval/triage/05-mixed-classification/notes.md +0 -17
- package/pipeline/eval/triage/06-severity-mismatch/expected.json +0 -15
- package/pipeline/eval/triage/06-severity-mismatch/input.json +0 -14
- package/pipeline/eval/triage/06-severity-mismatch/notes.md +0 -9
- package/pipeline/eval/triage/07-duplicate-reviewers/expected.json +0 -27
- package/pipeline/eval/triage/07-duplicate-reviewers/input.json +0 -22
- package/pipeline/eval/triage/07-duplicate-reviewers/notes.md +0 -9
- package/pipeline/eval/triage/08-style-misclassified/expected.json +0 -18
- package/pipeline/eval/triage/08-style-misclassified/input.json +0 -14
- package/pipeline/eval/triage/08-style-misclassified/notes.md +0 -9
- package/pipeline/eval/triage/09-cascading-finding/expected.json +0 -23
- package/pipeline/eval/triage/09-cascading-finding/input.json +0 -22
- package/pipeline/eval/triage/09-cascading-finding/notes.md +0 -9
- package/pipeline/eval/triage/10-deferred-crossref/expected.json +0 -18
- package/pipeline/eval/triage/10-deferred-crossref/input.json +0 -14
- package/pipeline/eval/triage/10-deferred-crossref/notes.md +0 -9
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/expected.json +0 -27
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/input.json +0 -22
- package/pipeline/eval/triage/11-vercel-token-leak-blocker/notes.md +0 -14
- package/pipeline/eval/triage/README.md +0 -54
- package/pipeline/scripts/benchmark-phase-0.sh +0 -128
- package/pipeline/scripts/check-md-links.mjs +0 -88
- package/pipeline/scripts/eval-golden-tasks-live.mjs +0 -302
- package/pipeline/scripts/eval-golden-tasks.mjs +0 -224
- package/pipeline/scripts/eval-intent.mjs +0 -107
- package/pipeline/scripts/eval-mine-corpus.mjs +0 -211
- package/pipeline/scripts/eval-triage.mjs +0 -171
- package/pipeline/scripts/fixtures/diff-risk-android.diff +0 -40
- package/pipeline/scripts/fixtures/diff-risk-ios.diff +0 -48
- package/pipeline/scripts/fixtures/diff-risk-test-removal.diff +0 -40
- package/pipeline/scripts/fixtures/install-layout.tsv +0 -19
- package/pipeline/scripts/fixtures/pack-expected-count.txt +0 -1
- package/pipeline/scripts/fixtures/test-gap-node.diff +0 -30
- package/pipeline/scripts/fixtures/test-gap-python.diff +0 -32
- package/pipeline/scripts/lint-mcp-refs.mjs +0 -218
- package/pipeline/scripts/lint-skills.mjs +0 -154
- package/pipeline/scripts/run-smokes.mjs +0 -130
- package/pipeline/scripts/scorecard.mjs +0 -258
- package/pipeline/scripts/smoke-add-detail.sh +0 -137
- package/pipeline/scripts/smoke-agent-guard.sh +0 -74
- package/pipeline/scripts/smoke-agent-log-cost.sh +0 -262
- package/pipeline/scripts/smoke-agent-model-routing.sh +0 -87
- package/pipeline/scripts/smoke-ask-choice.sh +0 -42
- package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +0 -36
- package/pipeline/scripts/smoke-bitbucket-contract.sh +0 -255
- package/pipeline/scripts/smoke-changelog-version.sh +0 -47
- package/pipeline/scripts/smoke-channels-approval-gate.sh +0 -60
- package/pipeline/scripts/smoke-channels-flow.sh +0 -130
- package/pipeline/scripts/smoke-ci-workflows.sh +0 -88
- package/pipeline/scripts/smoke-clarify.sh +0 -148
- package/pipeline/scripts/smoke-command-inventory.sh +0 -81
- package/pipeline/scripts/smoke-commands-skills-parity.sh +0 -87
- package/pipeline/scripts/smoke-community-gates.sh +0 -75
- package/pipeline/scripts/smoke-compliance-skills.sh +0 -119
- package/pipeline/scripts/smoke-config-hygiene.sh +0 -58
- package/pipeline/scripts/smoke-context-budget.sh +0 -72
- package/pipeline/scripts/smoke-cost-budget.sh +0 -70
- package/pipeline/scripts/smoke-cost-summary.sh +0 -139
- package/pipeline/scripts/smoke-cross-phase-cohesion.sh +0 -128
- package/pipeline/scripts/smoke-description-tr.sh +0 -82
- package/pipeline/scripts/smoke-dev-critic.sh +0 -144
- package/pipeline/scripts/smoke-diff-explain.sh +0 -147
- package/pipeline/scripts/smoke-diff-risk.sh +0 -190
- package/pipeline/scripts/smoke-dynamic-skill-loading.sh +0 -160
- package/pipeline/scripts/smoke-eval-live.sh +0 -136
- package/pipeline/scripts/smoke-evidence-gate.sh +0 -93
- package/pipeline/scripts/smoke-extract-conventions.sh +0 -163
- package/pipeline/scripts/smoke-fetchers-offline.sh +0 -448
- package/pipeline/scripts/smoke-figma-dispatch.sh +0 -112
- package/pipeline/scripts/smoke-gate-hooks.sh +0 -74
- package/pipeline/scripts/smoke-gc-tmp.sh +0 -130
- package/pipeline/scripts/smoke-gc-worktrees.sh +0 -125
- package/pipeline/scripts/smoke-generate-issue.sh +0 -120
- package/pipeline/scripts/smoke-handoff-contract.sh +0 -92
- package/pipeline/scripts/smoke-identity-isolation.sh +0 -70
- package/pipeline/scripts/smoke-install-layout.sh +0 -248
- package/pipeline/scripts/smoke-intent-guard.sh +0 -86
- package/pipeline/scripts/smoke-issue-comment-template.sh +0 -86
- package/pipeline/scripts/smoke-issue-jira-triad.sh +0 -120
- package/pipeline/scripts/smoke-keychain.sh +0 -158
- package/pipeline/scripts/smoke-language-axis.sh +0 -109
- package/pipeline/scripts/smoke-learning-curve.sh +0 -61
- package/pipeline/scripts/smoke-learnings-ledger.sh +0 -86
- package/pipeline/scripts/smoke-lib-scripts.sh +0 -448
- package/pipeline/scripts/smoke-mcp-gate.sh +0 -68
- package/pipeline/scripts/smoke-md-links.sh +0 -8
- package/pipeline/scripts/smoke-md2confluence.sh +0 -126
- package/pipeline/scripts/smoke-metrics-cache-ratio.sh +0 -72
- package/pipeline/scripts/smoke-migrate-state.sh +0 -102
- package/pipeline/scripts/smoke-mode-dispatch-drift.sh +0 -161
- package/pipeline/scripts/smoke-model-fallback.sh +0 -89
- package/pipeline/scripts/smoke-multi-repo-integration.sh +0 -116
- package/pipeline/scripts/smoke-multi-repo-worktree.sh +0 -61
- package/pipeline/scripts/smoke-no-mcp-in-dev-phases.sh +0 -194
- package/pipeline/scripts/smoke-no-token-prompt.sh +0 -85
- package/pipeline/scripts/smoke-own-punctuation.sh +0 -103
- package/pipeline/scripts/smoke-pack-contents.sh +0 -140
- package/pipeline/scripts/smoke-pat-audit.sh +0 -128
- package/pipeline/scripts/smoke-per-repo-memory.sh +0 -156
- package/pipeline/scripts/smoke-phase-0-multi-repo.sh +0 -170
- package/pipeline/scripts/smoke-phase-6-multi.sh +0 -79
- package/pipeline/scripts/smoke-phase-banner.sh +0 -101
- package/pipeline/scripts/smoke-phase-tracker.sh +0 -324
- package/pipeline/scripts/smoke-phase0-bridge-contract.sh +0 -241
- package/pipeline/scripts/smoke-phase4-gates.sh +0 -45
- package/pipeline/scripts/smoke-phase4-triage.sh +0 -229
- package/pipeline/scripts/smoke-plan-approval-gate.sh +0 -71
- package/pipeline/scripts/smoke-plan-safety.sh +0 -139
- package/pipeline/scripts/smoke-plan-todos.sh +0 -196
- package/pipeline/scripts/smoke-pr-review-actions.sh +0 -152
- package/pipeline/scripts/smoke-pre-commit.sh +0 -170
- package/pipeline/scripts/smoke-pref-migration.sh +0 -226
- package/pipeline/scripts/smoke-prefs-language.sh +0 -134
- package/pipeline/scripts/smoke-progress-contract.sh +0 -127
- package/pipeline/scripts/smoke-prune-logs.sh +0 -137
- package/pipeline/scripts/smoke-purge.sh +0 -138
- package/pipeline/scripts/smoke-push-retry.sh +0 -75
- package/pipeline/scripts/smoke-repo-map.sh +0 -300
- package/pipeline/scripts/smoke-review-readiness.sh +0 -92
- package/pipeline/scripts/smoke-review-watch.sh +0 -146
- package/pipeline/scripts/smoke-routines.sh +0 -84
- package/pipeline/scripts/smoke-run-aggregator.sh +0 -216
- package/pipeline/scripts/smoke-run-metrics.sh +0 -50
- package/pipeline/scripts/smoke-search.sh +0 -187
- package/pipeline/scripts/smoke-shadow-git.sh +0 -224
- package/pipeline/scripts/smoke-skill-authoring.sh +0 -137
- package/pipeline/scripts/smoke-skill-language.sh +0 -83
- package/pipeline/scripts/smoke-skill-manifest.sh +0 -138
- package/pipeline/scripts/smoke-skill-scan.sh +0 -198
- package/pipeline/scripts/smoke-source-parity.sh +0 -85
- package/pipeline/scripts/smoke-subagent-validators.sh +0 -108
- package/pipeline/scripts/smoke-sync-parity.sh +0 -92
- package/pipeline/scripts/smoke-tasklist-ordering.sh +0 -112
- package/pipeline/scripts/smoke-telemetry.sh +0 -147
- package/pipeline/scripts/smoke-test-gap.sh +0 -183
- package/pipeline/scripts/smoke-token-budget.sh +0 -67
- package/pipeline/scripts/smoke-token-preflight.sh +0 -82
- package/pipeline/scripts/smoke-tracker-contract.sh +0 -191
- package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +0 -73
- package/pipeline/scripts/smoke-triage-memory.sh +0 -174
- package/pipeline/scripts/smoke-update-check.sh +0 -135
- package/pipeline/scripts/smoke-url-enrichment.sh +0 -70
- package/pipeline/scripts/smoke-validate-analysis-doc.sh +0 -161
- package/pipeline/scripts/smoke-validator-contradiction.sh +0 -67
- package/pipeline/scripts/smoke-validator-gates.sh +0 -164
- package/pipeline/scripts/smoke-vercel-deploy-redact.sh +0 -129
- package/pipeline/scripts/smoke-verify-by-test.sh +0 -148
- package/pipeline/scripts/smoke-wiki-integration.sh +0 -122
- package/pipeline/scripts/smoke-work-summary.sh +0 -163
- package/pipeline/scripts/smoke-workflow-audit.sh +0 -101
- package/pipeline/scripts/smoke-worktree-path-convention.sh +0 -86
- package/pipeline/scripts/smoke-wrapper-preservation.sh +0 -68
- package/pipeline/scripts/smoke-write-state.sh +0 -159
- package/pipeline/scripts/sync-parity-check.sh +0 -135
- package/pipeline/scripts/test-gap-rules/android.json +0 -25
- package/pipeline/scripts/test-gap-rules/ios.json +0 -34
- package/pipeline/scripts/test-gap-rules/node.json +0 -29
- package/pipeline/scripts/test-gap-rules/python.json +0 -25
- package/pipeline/scripts/validate-schemas.mjs +0 -88
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-telemetry.sh - contract check for log-metric.sh + aggregate-metrics.mjs.
|
|
3
|
-
#
|
|
4
|
-
# Verifies:
|
|
5
|
-
# 1. log-metric.sh appends valid JSONL (one line, parses, has required fields).
|
|
6
|
-
# 2. Type coercion works (booleans, ints, strings).
|
|
7
|
-
# 3. Concurrent appends don't interleave (10 parallel writers → 10 lines).
|
|
8
|
-
# 4. aggregate-metrics.mjs handles missing file gracefully.
|
|
9
|
-
# 5. aggregate-metrics.mjs computes accept_rate / reject_rate correctly.
|
|
10
|
-
# 6. aggregate-metrics.mjs --json produces valid JSON.
|
|
11
|
-
|
|
12
|
-
set -uo pipefail
|
|
13
|
-
|
|
14
|
-
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
15
|
-
ROOT="$(cd "$HERE/../.." && pwd)"
|
|
16
|
-
TMP="$(mktemp -d -t multi-agent-smoke-XXXX)"
|
|
17
|
-
trap 'rm -rf "$TMP"' EXIT
|
|
18
|
-
|
|
19
|
-
PASS=0
|
|
20
|
-
FAIL=0
|
|
21
|
-
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
22
|
-
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
23
|
-
|
|
24
|
-
need() { command -v "$1" >/dev/null 2>&1 || { echo "error: $1 is required" >&2; exit 127; }; }
|
|
25
|
-
need node
|
|
26
|
-
need jq
|
|
27
|
-
|
|
28
|
-
LOG="$ROOT/pipeline/scripts/log-metric.sh"
|
|
29
|
-
AGG="$ROOT/pipeline/scripts/aggregate-metrics.mjs"
|
|
30
|
-
export METRICS_FILE="$TMP/metrics.jsonl"
|
|
31
|
-
|
|
32
|
-
echo "→ 1. log-metric writes a JSONL line with required fields"
|
|
33
|
-
"$LOG" TASK-1 4 review.completed raw_count=8 accepted=3 deferred=2 rejected=3 approved=true
|
|
34
|
-
LINE=$(tail -1 "$METRICS_FILE")
|
|
35
|
-
if echo "$LINE" | jq -e '.ts and .task_id and .phase and .event and .details' >/dev/null; then
|
|
36
|
-
pass "JSONL line has all required fields"
|
|
37
|
-
else
|
|
38
|
-
fail "missing required field in: $LINE"
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
echo ""
|
|
42
|
-
echo "→ 2. type coercion: bool, int, string"
|
|
43
|
-
TYPES=$(echo "$LINE" | jq -r '.details | "approved=" + (.approved | type) + " accepted=" + (.accepted | type) + " raw_count=" + (.raw_count | type)')
|
|
44
|
-
if [ "$TYPES" = "approved=boolean accepted=number raw_count=number" ]; then
|
|
45
|
-
pass "bool/int coerce correctly: $TYPES"
|
|
46
|
-
else
|
|
47
|
-
fail "type coercion wrong: $TYPES"
|
|
48
|
-
fi
|
|
49
|
-
"$LOG" TASK-1 4 triage.edge_case case=high-rejection-rate
|
|
50
|
-
STR_TYPE=$(tail -1 "$METRICS_FILE" | jq -r '.details.case | type')
|
|
51
|
-
if [ "$STR_TYPE" = "string" ]; then
|
|
52
|
-
pass "non-numeric strings stay strings"
|
|
53
|
-
else
|
|
54
|
-
fail "string coercion wrong: got $STR_TYPE"
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
echo ""
|
|
58
|
-
echo "→ 3. concurrent appends (10 parallel writers → 10 lines)"
|
|
59
|
-
rm -f "$METRICS_FILE"
|
|
60
|
-
PIDS=()
|
|
61
|
-
for i in 1 2 3 4 5 6 7 8 9 10; do
|
|
62
|
-
"$LOG" TASK-$i 4 review.completed raw_count=$i accepted=0 deferred=0 rejected=0 approved=true &
|
|
63
|
-
PIDS+=($!)
|
|
64
|
-
done
|
|
65
|
-
FAILED=0
|
|
66
|
-
for pid in "${PIDS[@]}"; do
|
|
67
|
-
wait "$pid" || FAILED=$((FAILED+1))
|
|
68
|
-
done
|
|
69
|
-
if [ "$FAILED" -gt 0 ]; then
|
|
70
|
-
fail "$FAILED of 10 background log-metric calls failed"
|
|
71
|
-
fi
|
|
72
|
-
LINE_COUNT=$(wc -l < "$METRICS_FILE" | tr -d ' ')
|
|
73
|
-
if [ "$LINE_COUNT" = "10" ]; then
|
|
74
|
-
pass "10 concurrent writes produced 10 lines (no interleaving)"
|
|
75
|
-
else
|
|
76
|
-
fail "expected 10 lines, got $LINE_COUNT"
|
|
77
|
-
fi
|
|
78
|
-
PARSE_OK=$(awk '{ print }' "$METRICS_FILE" | jq -e '.task_id' >/dev/null && echo ok || echo fail)
|
|
79
|
-
if [ "$PARSE_OK" = "ok" ]; then
|
|
80
|
-
pass "all 10 lines parse as valid JSON"
|
|
81
|
-
else
|
|
82
|
-
fail "concurrent append corrupted JSON"
|
|
83
|
-
fi
|
|
84
|
-
|
|
85
|
-
echo ""
|
|
86
|
-
echo "→ 4. aggregator handles missing file gracefully"
|
|
87
|
-
EXIT_OK=0
|
|
88
|
-
node "$AGG" --json >/dev/null 2>&1 || EXIT_OK=$?
|
|
89
|
-
# Above call uses default METRICS_FILE which IS set, so let's force missing.
|
|
90
|
-
unset METRICS_FILE
|
|
91
|
-
EXIT_MISSING=0
|
|
92
|
-
METRICS_FILE="$TMP/does-not-exist.jsonl" node "$AGG" --json > "$TMP/missing-out.json" 2>&1 || EXIT_MISSING=$?
|
|
93
|
-
if [ "$EXIT_MISSING" = "0" ] && jq -e '.ok == false' "$TMP/missing-out.json" >/dev/null 2>&1; then
|
|
94
|
-
pass "missing file → exit 0 + ok:false"
|
|
95
|
-
else
|
|
96
|
-
fail "missing file handling wrong (exit=$EXIT_MISSING)"
|
|
97
|
-
fi
|
|
98
|
-
export METRICS_FILE="$TMP/metrics.jsonl"
|
|
99
|
-
|
|
100
|
-
echo ""
|
|
101
|
-
echo "→ 5. accept_rate and reject_rate computed correctly"
|
|
102
|
-
rm -f "$METRICS_FILE"
|
|
103
|
-
"$LOG" T 4 review.completed raw_count=10 accepted=4 deferred=2 rejected=4 approved=true
|
|
104
|
-
"$LOG" T 4 review.completed raw_count=10 accepted=2 deferred=4 rejected=4 approved=true
|
|
105
|
-
# Total: raw=20, accepted=6, deferred=6, rejected=8 → accept=0.30, reject=0.40
|
|
106
|
-
SUMMARY=$(node "$AGG" --json)
|
|
107
|
-
ACCEPT_RATE=$(echo "$SUMMARY" | jq -r '.triage_totals.accept_rate')
|
|
108
|
-
REJECT_RATE=$(echo "$SUMMARY" | jq -r '.triage_totals.reject_rate')
|
|
109
|
-
if [ "$ACCEPT_RATE" = "0.3" ] && [ "$REJECT_RATE" = "0.4" ]; then
|
|
110
|
-
pass "accept_rate=$ACCEPT_RATE reject_rate=$REJECT_RATE (expected 0.3 / 0.4)"
|
|
111
|
-
else
|
|
112
|
-
fail "rates wrong: accept=$ACCEPT_RATE reject=$REJECT_RATE"
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
echo ""
|
|
116
|
-
echo "→ 6. --json output is valid JSON"
|
|
117
|
-
if echo "$SUMMARY" | jq empty >/dev/null 2>&1; then
|
|
118
|
-
pass "--json output parses"
|
|
119
|
-
else
|
|
120
|
-
fail "--json output is not valid JSON"
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
echo ""
|
|
124
|
-
echo "→ 7. cost_per_model section aggregates per-model totals"
|
|
125
|
-
rm -f "$METRICS_FILE"
|
|
126
|
-
"$LOG" T 4 review.completed model=opus duration_ms=12000 tokens_in=4500 tokens_out=600
|
|
127
|
-
"$LOG" T 4 review.completed model=opus duration_ms=8000 tokens_in=3000 tokens_out=400
|
|
128
|
-
"$LOG" T 4 review.completed model=sonnet duration_ms=5000 tokens_in=4500 tokens_out=350
|
|
129
|
-
SUMMARY=$(node "$AGG" --json)
|
|
130
|
-
OPUS_CALLS=$(echo "$SUMMARY" | jq -r '.cost_per_model.opus.calls')
|
|
131
|
-
OPUS_TOKENS_IN=$(echo "$SUMMARY" | jq -r '.cost_per_model.opus.tokens_in')
|
|
132
|
-
SONNET_DURATION=$(echo "$SUMMARY" | jq -r '.cost_per_model.sonnet.duration_ms')
|
|
133
|
-
[ "$OPUS_CALLS" = "2" ] && pass "opus calls summed (=2)" || fail "opus calls expected 2, got $OPUS_CALLS"
|
|
134
|
-
[ "$OPUS_TOKENS_IN" = "7500" ] && pass "opus tokens_in summed (=7500)" || fail "opus tokens_in expected 7500, got $OPUS_TOKENS_IN"
|
|
135
|
-
[ "$SONNET_DURATION" = "5000" ] && pass "sonnet duration_ms summed (=5000)" || fail "sonnet duration_ms expected 5000, got $SONNET_DURATION"
|
|
136
|
-
|
|
137
|
-
echo ""
|
|
138
|
-
echo "→ 8. cost section absent when no model fields present"
|
|
139
|
-
rm -f "$METRICS_FILE"
|
|
140
|
-
"$LOG" T 0 init.completed phases=8
|
|
141
|
-
SUMMARY=$(node "$AGG" --json)
|
|
142
|
-
COST_KEYS=$(echo "$SUMMARY" | jq -r '.cost_per_model | keys | length')
|
|
143
|
-
[ "$COST_KEYS" = "0" ] && pass "cost_per_model is empty when no model fields emitted" || fail "expected 0 keys, got $COST_KEYS"
|
|
144
|
-
|
|
145
|
-
echo ""
|
|
146
|
-
echo "══ telemetry smoke: $PASS passed, $FAIL failed ══"
|
|
147
|
-
[ "$FAIL" -eq 0 ]
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-test-gap.sh - v8.3.0
|
|
3
|
-
#
|
|
4
|
-
# Verifies the Phase 5 test-gap pipeline:
|
|
5
|
-
# 1. Rules files load + parse for ios/android/python/node
|
|
6
|
-
# 2. iOS fixture: scanner finds save/load/fetch as gaps; testRenders
|
|
7
|
-
# isn't a gap because it's the test, not source
|
|
8
|
-
# 3. Android fixture: composable_fun symbol gets `important` severity
|
|
9
|
-
# 4. Python fixture: detects async_def + top_def, ignores test files
|
|
10
|
-
# 5. Node fixture: catches named_export Parser; tokenize is covered by
|
|
11
|
-
# paired test → no gap
|
|
12
|
-
# 6. validate-test-gap.mjs accepts valid output, rejects malformed
|
|
13
|
-
# 7. --severity-promote bumps suggestion → important
|
|
14
|
-
# 8. Empty / wrong-stack diff exits 2
|
|
15
|
-
# 9. phase-5-test.md ref doc declares the Test Gap Report step
|
|
16
|
-
# 10. prefs.schema.json exposes testGap settings group
|
|
17
|
-
#
|
|
18
|
-
# Exit 0 = all pass, 1 = any failure.
|
|
19
|
-
|
|
20
|
-
set -euo pipefail
|
|
21
|
-
|
|
22
|
-
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
23
|
-
SCAN="$ROOT/pipeline/scripts/test-gap-scan.mjs"
|
|
24
|
-
VAL="$ROOT/pipeline/scripts/validate-test-gap.mjs"
|
|
25
|
-
PHASE5="$ROOT/pipeline/multi-agent-refs/phases/phase-5-test.md"
|
|
26
|
-
PREFS="$ROOT/pipeline/schemas/prefs.schema.json"
|
|
27
|
-
RULES_DIR="$ROOT/pipeline/scripts/test-gap-rules"
|
|
28
|
-
FIX_IOS="$ROOT/pipeline/scripts/fixtures/diff-risk-ios.diff"
|
|
29
|
-
FIX_AND="$ROOT/pipeline/scripts/fixtures/diff-risk-android.diff"
|
|
30
|
-
FIX_PY="$ROOT/pipeline/scripts/fixtures/test-gap-python.diff"
|
|
31
|
-
FIX_NODE="$ROOT/pipeline/scripts/fixtures/test-gap-node.diff"
|
|
32
|
-
|
|
33
|
-
pass=0
|
|
34
|
-
fail=0
|
|
35
|
-
failures=()
|
|
36
|
-
record_pass() { pass=$((pass + 1)); printf ' \033[0;32mPASS\033[0m %s\n' "$1"; }
|
|
37
|
-
record_fail() { fail=$((fail + 1)); failures+=("$1"); printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; }
|
|
38
|
-
|
|
39
|
-
printf '→ smoke-test-gap (v8.3.0): Phase 5 test-gap detector contract\n'
|
|
40
|
-
|
|
41
|
-
# --- 1: rules files exist + parse for each stack ---
|
|
42
|
-
for stack in ios android python node; do
|
|
43
|
-
if jq -e '.stack and .sourceExtensions and .publicApiPatterns' "$RULES_DIR/$stack.json" >/dev/null 2>&1; then
|
|
44
|
-
record_pass "$stack rules parse and contain stack/extensions/patterns"
|
|
45
|
-
else
|
|
46
|
-
record_fail "$stack rules malformed"
|
|
47
|
-
fi
|
|
48
|
-
done
|
|
49
|
-
|
|
50
|
-
# --- 2: iOS fixture - KeychainStore.save/load + ApiClient.fetch detected ---
|
|
51
|
-
out_ios=$(node "$SCAN" --diff "$FIX_IOS" --stack ios 2>/dev/null)
|
|
52
|
-
gap_count=$(jq '.totals.gapCount' <<< "$out_ios")
|
|
53
|
-
if [ "$gap_count" -ge 3 ]; then
|
|
54
|
-
record_pass "iOS: at least 3 gaps reported (got $gap_count)"
|
|
55
|
-
else
|
|
56
|
-
record_fail "iOS: expected >=3 gaps, got $gap_count"
|
|
57
|
-
fi
|
|
58
|
-
if jq -e '.gaps[] | select(.symbol == "save")' <<< "$out_ios" >/dev/null 2>&1; then
|
|
59
|
-
record_pass "iOS: KeychainStore.save flagged as gap"
|
|
60
|
-
else
|
|
61
|
-
record_fail "iOS: KeychainStore.save missing from gaps"
|
|
62
|
-
fi
|
|
63
|
-
if jq -e '.gaps[] | select(.symbol == "fetch")' <<< "$out_ios" >/dev/null 2>&1; then
|
|
64
|
-
record_pass "iOS: ApiClient.fetch flagged as gap"
|
|
65
|
-
else
|
|
66
|
-
record_fail "iOS: ApiClient.fetch missing from gaps"
|
|
67
|
-
fi
|
|
68
|
-
# Test method itself shouldn't show up as a gap
|
|
69
|
-
if jq -e '.gaps[] | select(.symbol == "testRenders")' <<< "$out_ios" >/dev/null 2>&1; then
|
|
70
|
-
record_fail "iOS: testRenders should not be a gap (it's already a test)"
|
|
71
|
-
else
|
|
72
|
-
record_pass "iOS: test methods excluded from gap list"
|
|
73
|
-
fi
|
|
74
|
-
|
|
75
|
-
# --- 3: Android fixture - composable_fun → important severity ---
|
|
76
|
-
out_and=$(node "$SCAN" --diff "$FIX_AND" --stack android 2>/dev/null)
|
|
77
|
-
if jq -e '.gaps[] | select(.kind == "composable_fun" and .severity == "important")' <<< "$out_and" >/dev/null 2>&1; then
|
|
78
|
-
record_pass "Android: composable_fun gets 'important' severity"
|
|
79
|
-
else
|
|
80
|
-
record_fail "Android: composable_fun severity wrong"
|
|
81
|
-
fi
|
|
82
|
-
if jq -e '.gaps[] | select(.symbol == "login")' <<< "$out_and" >/dev/null 2>&1; then
|
|
83
|
-
record_pass "Android: AuthRepository.login flagged"
|
|
84
|
-
else
|
|
85
|
-
record_fail "Android: AuthRepository.login missing"
|
|
86
|
-
fi
|
|
87
|
-
|
|
88
|
-
# --- 4: Python fixture - async_def + top_def detected, test file ignored ---
|
|
89
|
-
out_py=$(node "$SCAN" --diff "$FIX_PY" --stack python 2>/dev/null)
|
|
90
|
-
if jq -e '.gaps[] | select(.kind == "async_def" and .symbol == "refund")' <<< "$out_py" >/dev/null 2>&1; then
|
|
91
|
-
record_pass "Python: async_def refund detected"
|
|
92
|
-
else
|
|
93
|
-
record_fail "Python: async_def refund missing"
|
|
94
|
-
fi
|
|
95
|
-
if jq -e '.gaps[] | select(.symbol == "normalize_currency")' <<< "$out_py" >/dev/null 2>&1; then
|
|
96
|
-
record_pass "Python: normalize_currency detected"
|
|
97
|
-
else
|
|
98
|
-
record_fail "Python: normalize_currency missing"
|
|
99
|
-
fi
|
|
100
|
-
if jq -e '.totals.testsScanned >= 1' <<< "$out_py" >/dev/null 2>&1; then
|
|
101
|
-
record_pass "Python: test file recognised in counter"
|
|
102
|
-
else
|
|
103
|
-
record_fail "Python: testsScanned should include the new test_processor.py"
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
# --- 5: Node fixture - Parser flagged, tokenize covered by paired test ---
|
|
107
|
-
out_node=$(node "$SCAN" --diff "$FIX_NODE" --stack node 2>/dev/null)
|
|
108
|
-
if jq -e '.gaps[] | select(.symbol == "Parser")' <<< "$out_node" >/dev/null 2>&1; then
|
|
109
|
-
record_pass "Node: Parser export flagged"
|
|
110
|
-
else
|
|
111
|
-
record_fail "Node: Parser export missing from gaps"
|
|
112
|
-
fi
|
|
113
|
-
if jq -e '.gaps[] | select(.symbol == "tokenize")' <<< "$out_node" >/dev/null 2>&1; then
|
|
114
|
-
record_fail "Node: tokenize should be covered by added test, not flagged"
|
|
115
|
-
else
|
|
116
|
-
record_pass "Node: tokenize correctly excluded (paired test mentions it)"
|
|
117
|
-
fi
|
|
118
|
-
|
|
119
|
-
# --- 6: Validator accepts/rejects ---
|
|
120
|
-
set +e
|
|
121
|
-
echo "$out_ios" | node "$VAL" - >/dev/null 2>&1
|
|
122
|
-
rc_ok=$?
|
|
123
|
-
echo '{"schemaVersion":"0.0.0","gaps":[]}' | node "$VAL" - >/dev/null 2>&1
|
|
124
|
-
rc_bad=$?
|
|
125
|
-
set -e
|
|
126
|
-
if [ "$rc_ok" -eq 0 ]; then record_pass "validator accepts valid output"; else record_fail "validator rejected valid output"; fi
|
|
127
|
-
if [ "$rc_bad" -ne 0 ]; then record_pass "validator rejects malformed"; else record_fail "validator should reject malformed"; fi
|
|
128
|
-
|
|
129
|
-
# --- 7: --severity-promote ---
|
|
130
|
-
out_prom=$(node "$SCAN" --diff "$FIX_IOS" --stack ios --severity-promote 2>/dev/null)
|
|
131
|
-
if jq -e 'all(.gaps[]; .severity == "important")' <<< "$out_prom" >/dev/null 2>&1; then
|
|
132
|
-
record_pass "--severity-promote forces all gaps to 'important'"
|
|
133
|
-
else
|
|
134
|
-
record_fail "--severity-promote did not promote severities"
|
|
135
|
-
fi
|
|
136
|
-
|
|
137
|
-
# --- 8: Empty diff exits 2 ---
|
|
138
|
-
empty=$(mktemp)
|
|
139
|
-
set +e
|
|
140
|
-
node "$SCAN" --diff "$empty" --stack ios >/dev/null 2>&1
|
|
141
|
-
rc=$?
|
|
142
|
-
set -e
|
|
143
|
-
rm -f "$empty"
|
|
144
|
-
if [ "$rc" -eq 2 ]; then
|
|
145
|
-
record_pass "empty diff exits 2"
|
|
146
|
-
else
|
|
147
|
-
record_fail "empty diff should exit 2 (got $rc)"
|
|
148
|
-
fi
|
|
149
|
-
|
|
150
|
-
# Wrong-stack: iOS diff scanned with python rules → no python sources → exit 2
|
|
151
|
-
set +e
|
|
152
|
-
node "$SCAN" --diff "$FIX_IOS" --stack python >/dev/null 2>&1
|
|
153
|
-
rc=$?
|
|
154
|
-
set -e
|
|
155
|
-
if [ "$rc" -eq 2 ]; then
|
|
156
|
-
record_pass "iOS diff with python rules exits 2 (no matching sources)"
|
|
157
|
-
else
|
|
158
|
-
record_fail "wrong-stack should exit 2 (got $rc)"
|
|
159
|
-
fi
|
|
160
|
-
|
|
161
|
-
# --- 9: phase-5-test.md declares the Test Gap Report step ---
|
|
162
|
-
if grep -qE 'Test Gap Report|test-gap-scan\.mjs' "$PHASE5"; then
|
|
163
|
-
record_pass "phase-5-test.md declares Test Gap Report step"
|
|
164
|
-
else
|
|
165
|
-
record_fail "phase-5-test.md missing Test Gap Report step"
|
|
166
|
-
fi
|
|
167
|
-
|
|
168
|
-
# --- 10: prefs schema exposes testGap group ---
|
|
169
|
-
if jq -e '.properties.global.properties.testGap' "$PREFS" >/dev/null 2>&1; then
|
|
170
|
-
record_pass "prefs schema exposes testGap settings group"
|
|
171
|
-
else
|
|
172
|
-
record_fail "prefs.schema.json missing global.testGap group"
|
|
173
|
-
fi
|
|
174
|
-
|
|
175
|
-
# --- Summary ---
|
|
176
|
-
total=$((pass + fail))
|
|
177
|
-
printf '\n→ smoke-test-gap: %d/%d passed\n' "$pass" "$total"
|
|
178
|
-
if [ "$fail" -ne 0 ]; then
|
|
179
|
-
printf '\nFailures:\n'
|
|
180
|
-
for f in "${failures[@]}"; do printf ' - %s\n' "$f"; done
|
|
181
|
-
exit 1
|
|
182
|
-
fi
|
|
183
|
-
exit 0
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-token-budget.sh - verify phase docs stay within token budget.
|
|
3
|
-
# Reads token-budget.json and checks each phase doc's char count / 4.
|
|
4
|
-
# Fails if any phase exceeds its max_tokens limit.
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
-
PIPELINE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
10
|
-
BUDGET_FILE="$PIPELINE_DIR/schemas/token-budget.json"
|
|
11
|
-
PHASES_DIR="$PIPELINE_DIR/multi-agent-refs/phases"
|
|
12
|
-
|
|
13
|
-
if [ ! -f "$BUDGET_FILE" ]; then
|
|
14
|
-
echo "FAIL: token-budget.json not found at $BUDGET_FILE" >&2
|
|
15
|
-
exit 1
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
|
-
command -v jq >/dev/null 2>&1 || { echo "jq is required" >&2; exit 64; }
|
|
19
|
-
|
|
20
|
-
PASS=0
|
|
21
|
-
FAIL=0
|
|
22
|
-
WARN=0
|
|
23
|
-
|
|
24
|
-
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
25
|
-
warn() { WARN=$((WARN+1)); echo " ⚠ $1"; }
|
|
26
|
-
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
27
|
-
|
|
28
|
-
TOTAL_TOKENS=0
|
|
29
|
-
TOTAL_MAX=$(jq -r '.total_max_tokens' "$BUDGET_FILE")
|
|
30
|
-
|
|
31
|
-
echo "→ Token budget check (chars/4 estimate)"
|
|
32
|
-
echo ""
|
|
33
|
-
|
|
34
|
-
for phase_key in $(jq -r '.phases | keys[]' "$BUDGET_FILE"); do
|
|
35
|
-
file="$PHASES_DIR/${phase_key}.md"
|
|
36
|
-
max_tokens=$(jq -r ".phases[\"$phase_key\"].max_tokens" "$BUDGET_FILE")
|
|
37
|
-
warn_tokens=$(jq -r ".phases[\"$phase_key\"].warn_tokens" "$BUDGET_FILE")
|
|
38
|
-
|
|
39
|
-
if [ ! -f "$file" ]; then
|
|
40
|
-
fail "$phase_key: file not found ($file)"
|
|
41
|
-
continue
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
chars=$(wc -c < "$file" | tr -d ' ')
|
|
45
|
-
tokens=$(( (chars + 3) / 4 ))
|
|
46
|
-
TOTAL_TOKENS=$((TOTAL_TOKENS + tokens))
|
|
47
|
-
|
|
48
|
-
if [ "$tokens" -gt "$max_tokens" ]; then
|
|
49
|
-
fail "$phase_key: ${tokens} tokens > max ${max_tokens} (${chars} chars)"
|
|
50
|
-
elif [ "$tokens" -gt "$warn_tokens" ]; then
|
|
51
|
-
warn "$phase_key: ${tokens} tokens > warn ${warn_tokens} (within max ${max_tokens})"
|
|
52
|
-
else
|
|
53
|
-
pass "$phase_key: ${tokens} tokens ≤ ${warn_tokens} warn (max ${max_tokens})"
|
|
54
|
-
fi
|
|
55
|
-
done
|
|
56
|
-
|
|
57
|
-
echo ""
|
|
58
|
-
echo "→ Total phase doc budget"
|
|
59
|
-
if [ "$TOTAL_TOKENS" -gt "$TOTAL_MAX" ]; then
|
|
60
|
-
fail "total: ${TOTAL_TOKENS} tokens > max ${TOTAL_MAX}"
|
|
61
|
-
else
|
|
62
|
-
pass "total: ${TOTAL_TOKENS} tokens ≤ max ${TOTAL_MAX}"
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
echo ""
|
|
66
|
-
echo "══ token-budget smoke: $((PASS)) passed, $((WARN)) warnings, $((FAIL)) failed ══"
|
|
67
|
-
[ "$FAIL" -eq 0 ]
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-token-preflight.sh - contract for the Phase 0 Step 0.7 token expiry pre-flight
|
|
3
|
-
# and the Figma MCP token lifecycle (silent refresh + generation-script escalation).
|
|
4
|
-
#
|
|
5
|
-
# Verifies:
|
|
6
|
-
# 1. phase-0-init.md has Step 0.7 with the probe table and figma-mcp-critical path.
|
|
7
|
-
# 2. Silent renewal runs BEFORE any question; autopilot never prompts.
|
|
8
|
-
# 3. keychain.md documents the Figma MCP lifecycle (refresh entry, tokenScripts, init cross-ref).
|
|
9
|
-
# 4. lib/figma-mcp-refresh.sh exists, is executable, parses, and never prints token values.
|
|
10
|
-
# 5. prefs.schema.json + preferences-template.json declare global.tokenScripts.
|
|
11
|
-
# 6. Network failure is not treated as expiry; mid-run 401 stays as safety net.
|
|
12
|
-
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
16
|
-
ROOT="$(cd "$HERE/../.." && pwd)"
|
|
17
|
-
PHASE0="$ROOT/pipeline/multi-agent-refs/phases/phase-0-init.md"
|
|
18
|
-
KEYCHAIN="$ROOT/pipeline/multi-agent-refs/keychain.md"
|
|
19
|
-
REFRESH="$ROOT/pipeline/lib/figma-mcp-refresh.sh"
|
|
20
|
-
SCHEMA="$ROOT/pipeline/schemas/prefs.schema.json"
|
|
21
|
-
TEMPLATE="$ROOT/pipeline/preferences-template.json"
|
|
22
|
-
|
|
23
|
-
PASS=0
|
|
24
|
-
FAIL=0
|
|
25
|
-
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
26
|
-
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
27
|
-
|
|
28
|
-
need() { command -v "$1" >/dev/null 2>&1 || { echo "error: $1 required" >&2; exit 127; }; }
|
|
29
|
-
need jq
|
|
30
|
-
|
|
31
|
-
for f in "$PHASE0" "$KEYCHAIN" "$REFRESH" "$SCHEMA" "$TEMPLATE"; do
|
|
32
|
-
[ -f "$f" ] || { echo "error: missing $f" >&2; exit 1; }
|
|
33
|
-
done
|
|
34
|
-
|
|
35
|
-
echo "→ 1. Step 0.7 pre-flight section"
|
|
36
|
-
grep -Fq "Step 0.7 - Token expiry pre-flight" "$PHASE0" && pass "Step 0.7 present" || fail "Step 0.7 missing"
|
|
37
|
-
for marker in "rest/api/2/myself" "mcp.figma.com/mcp" "serviceStatus" "CRITICAL"; do
|
|
38
|
-
grep -Fq "$marker" "$PHASE0" && pass "probe marker: $marker" || fail "probe marker missing: $marker"
|
|
39
|
-
done
|
|
40
|
-
|
|
41
|
-
echo ""
|
|
42
|
-
echo "→ 2. silent renewal first, autopilot never prompts"
|
|
43
|
-
grep -Fq "figma-mcp-refresh.sh" "$PHASE0" && pass "silent renewal wired" || fail "silent renewal missing"
|
|
44
|
-
grep -Fq "Silent renewal first" "$PHASE0" && pass "renewal precedes question" || fail "renewal-first rule missing"
|
|
45
|
-
grep -Fq "never prompt" "$PHASE0" && pass "autopilot no-prompt rule" || fail "autopilot no-prompt rule missing"
|
|
46
|
-
grep -Fq "Regenerate now (script)" "$PHASE0" && pass "script escalation option" || fail "script escalation option missing"
|
|
47
|
-
grep -Fq "Continue degraded" "$PHASE0" && pass "degrade option" || fail "degrade option missing"
|
|
48
|
-
|
|
49
|
-
echo ""
|
|
50
|
-
echo "→ 3. keychain.md lifecycle section"
|
|
51
|
-
grep -Fq "Figma MCP token lifecycle" "$KEYCHAIN" && pass "lifecycle section present" || fail "lifecycle section missing"
|
|
52
|
-
grep -Fq "_Refresh" "$KEYCHAIN" && pass "refresh Keychain entry documented" || fail "refresh entry missing"
|
|
53
|
-
grep -Fq "tokenScripts" "$KEYCHAIN" && pass "tokenScripts documented" || fail "tokenScripts missing"
|
|
54
|
-
grep -Fq "Step 0.7" "$KEYCHAIN" && pass "init cross-ref present" || fail "init cross-ref missing"
|
|
55
|
-
grep -Fq "never in synced command files" "$KEYCHAIN" && pass "personal-path hygiene rule" || fail "personal-path hygiene rule missing"
|
|
56
|
-
|
|
57
|
-
echo ""
|
|
58
|
-
echo "→ 4. figma-mcp-refresh.sh integrity"
|
|
59
|
-
[ -x "$REFRESH" ] && pass "executable" || fail "not executable"
|
|
60
|
-
bash -n "$REFRESH" && pass "parses (bash -n)" || fail "syntax error"
|
|
61
|
-
grep -Fq "grant_type=refresh_token" "$REFRESH" && pass "refresh grant" || fail "refresh grant missing"
|
|
62
|
-
if grep -E 'echo .*\$(NEW_ACCESS|NEW_REFRESH|REFRESH_TOKEN)' "$REFRESH" >/dev/null; then
|
|
63
|
-
fail "token value printed to stdout"
|
|
64
|
-
else
|
|
65
|
-
pass "no token values printed"
|
|
66
|
-
fi
|
|
67
|
-
grep -Fq 'security add-generic-password' "$REFRESH" && pass "saves back to Keychain" || fail "Keychain save missing"
|
|
68
|
-
|
|
69
|
-
echo ""
|
|
70
|
-
echo "→ 5. prefs schema + template declare tokenScripts"
|
|
71
|
-
TS_TYPE=$(jq -r '.properties.global.properties.tokenScripts.type // "missing"' "$SCHEMA")
|
|
72
|
-
[ "$TS_TYPE" = "object" ] && pass "schema tokenScripts is object" || fail "schema tokenScripts type = '$TS_TYPE'"
|
|
73
|
-
jq -e '.global | has("tokenScripts")' "$TEMPLATE" >/dev/null && pass "template has tokenScripts" || fail "template missing tokenScripts"
|
|
74
|
-
|
|
75
|
-
echo ""
|
|
76
|
-
echo "→ 6. network failure is not expiry; 401 safety net stays"
|
|
77
|
-
grep -Fq "NOT treated as expiry" "$PHASE0" && pass "network-failure rule" || fail "network-failure rule missing"
|
|
78
|
-
grep -Fq "safety net" "$PHASE0" && pass "401 safety net documented" || fail "401 safety net missing"
|
|
79
|
-
|
|
80
|
-
echo ""
|
|
81
|
-
echo "══ token-preflight smoke: $PASS passed, $FAIL failed ══"
|
|
82
|
-
[ "$FAIL" -eq 0 ]
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-tracker-contract.sh - v7.9.1
|
|
3
|
-
#
|
|
4
|
-
# Validates that every mode dispatch file (dev/SKILL.md, dev-local/SKILL.md, autopilot/SKILL.md,
|
|
5
|
-
# etc.) carries the mandatory phase-tracker.sh invocation contract.
|
|
6
|
-
#
|
|
7
|
-
# Without this, agent prompts can fall through to TaskCreate/TaskList UI which
|
|
8
|
-
# does NOT track elapsed time or token counts - users see only static
|
|
9
|
-
# checkboxes with no progress info. The 2026-04-27 regression that prompted
|
|
10
|
-
# this smoke: 8 mode dispatch files shipped through v7.6 → v7.9 with zero
|
|
11
|
-
# tracker references; agent went straight to Claude Code's plan UI.
|
|
12
|
-
#
|
|
13
|
-
# What this enforces:
|
|
14
|
-
# 1. Each mode file references phase-tracker.sh at least N times (init +
|
|
15
|
-
# add + update + tokens + render at minimum)
|
|
16
|
-
# 2. Each mode file links to refs/tracker-contract.md
|
|
17
|
-
# 3. The shared contract file exists and documents the invocation pattern
|
|
18
|
-
#
|
|
19
|
-
# What this does NOT enforce:
|
|
20
|
-
# - Runtime - that the agent actually invokes the tracker. That's a contract
|
|
21
|
-
# test the orchestrator carries; this smoke catches the prompt-side gap.
|
|
22
|
-
|
|
23
|
-
set -uo pipefail
|
|
24
|
-
|
|
25
|
-
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
26
|
-
CMDS_DIR="$REPO_ROOT/pipeline/commands/multi-agent"
|
|
27
|
-
CONTRACT_FILE="$HOME/.claude/multi-agent-refs/tracker-contract.md"
|
|
28
|
-
|
|
29
|
-
# Mode dispatch files that must reference the tracker contract.
|
|
30
|
-
# Updated when new mode files ship; no auto-discovery (false positives on
|
|
31
|
-
# helpers like _account-picker, status, log).
|
|
32
|
-
MODE_FILES=(
|
|
33
|
-
dev/SKILL.md
|
|
34
|
-
dev-local/SKILL.md
|
|
35
|
-
dev-autopilot/SKILL.md
|
|
36
|
-
dev-local-autopilot/SKILL.md
|
|
37
|
-
autopilot/SKILL.md
|
|
38
|
-
local/SKILL.md
|
|
39
|
-
local-autopilot/SKILL.md
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
# Minimum tracker references per file (init + at least one of the verbs).
|
|
43
|
-
# Set conservatively - the section template emits 6 references; bump if
|
|
44
|
-
# template is shortened in future.
|
|
45
|
-
MIN_REFS=4
|
|
46
|
-
|
|
47
|
-
PASS=0
|
|
48
|
-
FAIL=0
|
|
49
|
-
pass() { PASS=$((PASS + 1)); echo " ✓ $1"; }
|
|
50
|
-
fail() { FAIL=$((FAIL + 1)); echo " ✗ $1"; }
|
|
51
|
-
|
|
52
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
53
|
-
echo "→ 1. Tracker contract reference file exists"
|
|
54
|
-
if [ -f "$CONTRACT_FILE" ]; then
|
|
55
|
-
pass "refs/tracker-contract.md present"
|
|
56
|
-
else
|
|
57
|
-
fail "refs/tracker-contract.md missing - mode files have nowhere to link to"
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
61
|
-
echo "→ 2. Contract file documents the full invocation pattern"
|
|
62
|
-
if [ -f "$CONTRACT_FILE" ]; then
|
|
63
|
-
for verb in "init" "add" "update" "tokens" "render"; do
|
|
64
|
-
if grep -q "phase-tracker.sh $verb" "$CONTRACT_FILE"; then
|
|
65
|
-
pass "contract documents '$verb' verb"
|
|
66
|
-
else
|
|
67
|
-
fail "contract missing '$verb' verb in invocation pattern"
|
|
68
|
-
fi
|
|
69
|
-
done
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
73
|
-
echo "→ 3. Every mode file references phase-tracker.sh"
|
|
74
|
-
for mode_file in "${MODE_FILES[@]}"; do
|
|
75
|
-
full="$CMDS_DIR/$mode_file"
|
|
76
|
-
if [ ! -f "$full" ]; then
|
|
77
|
-
fail "$mode_file missing"
|
|
78
|
-
continue
|
|
79
|
-
fi
|
|
80
|
-
refs=$(grep -c "phase-tracker" "$full" || true)
|
|
81
|
-
if [ "$refs" -ge "$MIN_REFS" ]; then
|
|
82
|
-
pass "$mode_file: $refs tracker references (≥ $MIN_REFS)"
|
|
83
|
-
else
|
|
84
|
-
fail "$mode_file: only $refs tracker references (< $MIN_REFS expected)"
|
|
85
|
-
fi
|
|
86
|
-
done
|
|
87
|
-
|
|
88
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
89
|
-
echo "→ 4. Every mode file links to refs/tracker-contract.md"
|
|
90
|
-
for mode_file in "${MODE_FILES[@]}"; do
|
|
91
|
-
full="$CMDS_DIR/$mode_file"
|
|
92
|
-
[ -f "$full" ] || continue
|
|
93
|
-
if grep -q "tracker-contract" "$full"; then
|
|
94
|
-
pass "$mode_file → links to tracker-contract.md"
|
|
95
|
-
else
|
|
96
|
-
fail "$mode_file missing link to refs/tracker-contract.md"
|
|
97
|
-
fi
|
|
98
|
-
done
|
|
99
|
-
|
|
100
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
101
|
-
echo "→ 5. Anti-pattern guard - mode files warn against TaskCreate fallback"
|
|
102
|
-
for mode_file in "${MODE_FILES[@]}"; do
|
|
103
|
-
full="$CMDS_DIR/$mode_file"
|
|
104
|
-
[ -f "$full" ] || continue
|
|
105
|
-
if grep -qE "TaskCreate|checkbox UI" "$full"; then
|
|
106
|
-
pass "$mode_file mentions anti-pattern (TaskCreate / checkbox UI)"
|
|
107
|
-
else
|
|
108
|
-
fail "$mode_file has no anti-pattern guard"
|
|
109
|
-
fi
|
|
110
|
-
done
|
|
111
|
-
|
|
112
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
113
|
-
echo "→ 6. Phase 0 init pattern present in dispatch templates"
|
|
114
|
-
# This catches the specific bug from 2026-04-27: tracker was never init'd
|
|
115
|
-
# because dispatch files said "see refs" without inlining the call.
|
|
116
|
-
for mode_file in "${MODE_FILES[@]}"; do
|
|
117
|
-
full="$CMDS_DIR/$mode_file"
|
|
118
|
-
[ -f "$full" ] || continue
|
|
119
|
-
if grep -q 'phase-tracker.sh init' "$full"; then
|
|
120
|
-
pass "$mode_file inlines 'phase-tracker.sh init' (refs-only is not enough)"
|
|
121
|
-
else
|
|
122
|
-
fail "$mode_file does not inline init call"
|
|
123
|
-
fi
|
|
124
|
-
done
|
|
125
|
-
|
|
126
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
127
|
-
echo "→ 7. Live-tracker UX contract (now/cost actions, mirror rule, continuation)"
|
|
128
|
-
if grep -q 'phase-tracker.sh now' "$CONTRACT_FILE" \
|
|
129
|
-
&& grep -q 'cost <N>' "$CONTRACT_FILE"; then
|
|
130
|
-
pass "tracker-contract documents now + cost actions"
|
|
131
|
-
else
|
|
132
|
-
fail "tracker-contract missing now/cost action docs"
|
|
133
|
-
fi
|
|
134
|
-
if grep -q '\[cached\]' "$CONTRACT_FILE" || grep -q '\[cached_count\]' "$CONTRACT_FILE"; then
|
|
135
|
-
pass "tracker-contract documents the 4th cached tokens arg"
|
|
136
|
-
else
|
|
137
|
-
fail "tracker-contract missing the cached tokens arg"
|
|
138
|
-
fi
|
|
139
|
-
if grep -q 'Progress-line mirror' "$CONTRACT_FILE"; then
|
|
140
|
-
pass "tracker-contract declares the progress-line mirror rule"
|
|
141
|
-
else
|
|
142
|
-
fail "tracker-contract missing the progress-line mirror rule"
|
|
143
|
-
fi
|
|
144
|
-
if grep -q 'Continuation runs' "$CONTRACT_FILE" \
|
|
145
|
-
&& grep -q 'never re-initialized' "$CONTRACT_FILE"; then
|
|
146
|
-
pass "tracker-contract declares the continuation-runs rule"
|
|
147
|
-
else
|
|
148
|
-
fail "tracker-contract missing the continuation-runs rule"
|
|
149
|
-
fi
|
|
150
|
-
if grep -q 'Completion tile suffix' "$CONTRACT_FILE"; then
|
|
151
|
-
pass "tracker-contract declares the completion tile suffix"
|
|
152
|
-
else
|
|
153
|
-
fail "tracker-contract missing the completion tile suffix"
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
157
|
-
echo "→ 8. Continuation wiring in finish + manual-test + phase-5"
|
|
158
|
-
FINISH_FILE="$CMDS_DIR/finish/SKILL.md"
|
|
159
|
-
if grep -q '\[ ! -f "\$STATE" \]' "$FINISH_FILE"; then
|
|
160
|
-
pass "finish.md guards init behind a state-file existence check"
|
|
161
|
-
else
|
|
162
|
-
fail "finish.md must not init the tracker unconditionally"
|
|
163
|
-
fi
|
|
164
|
-
if grep -q 'Continuing' "$FINISH_FILE" && grep -q 'cost total' "$FINISH_FILE"; then
|
|
165
|
-
pass "finish.md prints the inherited-history line via cost total"
|
|
166
|
-
else
|
|
167
|
-
fail "finish.md missing the continuation summary line"
|
|
168
|
-
fi
|
|
169
|
-
MANUAL_FILE="$CMDS_DIR/manual-test/SKILL.md"
|
|
170
|
-
if grep -q 'now 5 "awaiting local test (user)"' "$MANUAL_FILE"; then
|
|
171
|
-
pass "manual-test.md sets the waiting state via now 5"
|
|
172
|
-
else
|
|
173
|
-
fail "manual-test.md missing the now 5 waiting state"
|
|
174
|
-
fi
|
|
175
|
-
PHASE5_FILE="$HOME/.claude/multi-agent-refs/phases/phase-5-test.md"
|
|
176
|
-
if grep -q 'now 5 "awaiting local test (user)"' "$PHASE5_FILE"; then
|
|
177
|
-
pass "phase-5-test.md sets the waiting state via now 5"
|
|
178
|
-
else
|
|
179
|
-
fail "phase-5-test.md missing the now 5 waiting state"
|
|
180
|
-
fi
|
|
181
|
-
RESUME_FILE="$CMDS_DIR/resume/SKILL.md"
|
|
182
|
-
if grep -q 'Rebuild the phase tiles' "$RESUME_FILE"; then
|
|
183
|
-
pass "resume.md rebuilds the phase tiles from state"
|
|
184
|
-
else
|
|
185
|
-
fail "resume.md missing the tile-rebuild step"
|
|
186
|
-
fi
|
|
187
|
-
|
|
188
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
189
|
-
echo ""
|
|
190
|
-
echo "══ tracker-contract smoke: $PASS passed, $FAIL failed ══"
|
|
191
|
-
[ "$FAIL" -eq 0 ]
|