@mmerterden/multi-agent-pipeline 12.7.0 → 12.8.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 +126 -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/phases/operations.md +28 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -0
- 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 +49 -4
- package/pipeline/schemas/prefs.schema.json +6 -0
- package/pipeline/scripts/_smoke-root.sh +61 -0
- 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,216 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-run-aggregator.sh - v7.8.0 Paket C: unified telemetry aggregator.
|
|
3
|
-
#
|
|
4
|
-
# Validates run-aggregator.mjs reads phase-tracker + otel-spans + cost table
|
|
5
|
-
# and emits a normalized pipeline-run.jsonl with:
|
|
6
|
-
# 1. Time-sorted events
|
|
7
|
-
# 2. Correct cost computation per cost-table.json
|
|
8
|
-
# 3. Span passthrough with task_id stamping
|
|
9
|
-
# 4. Summary as last event with totals
|
|
10
|
-
# 5. Unknown model graceful degradation
|
|
11
|
-
# 6. --summary-only mode
|
|
12
|
-
# 7. Read-only contract (no writes to source files)
|
|
13
|
-
# 8. Missing inputs handled with clear errors
|
|
14
|
-
# 9. Idempotent (running twice produces identical output)
|
|
15
|
-
|
|
16
|
-
set -uo pipefail
|
|
17
|
-
|
|
18
|
-
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
19
|
-
SCRIPT="$REPO_ROOT/pipeline/scripts/run-aggregator.mjs"
|
|
20
|
-
|
|
21
|
-
PASS=0
|
|
22
|
-
FAIL=0
|
|
23
|
-
pass() { PASS=$((PASS + 1)); echo " ✓ $1"; }
|
|
24
|
-
fail() { FAIL=$((FAIL + 1)); echo " ✗ $1"; }
|
|
25
|
-
|
|
26
|
-
cleanup() { [ -n "${TMP:-}" ] && rm -rf "$TMP"; }
|
|
27
|
-
trap cleanup EXIT
|
|
28
|
-
TMP=$(mktemp -d)
|
|
29
|
-
|
|
30
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
31
|
-
echo "→ 1. Setup synthetic task dir + tracker + spans"
|
|
32
|
-
cat > "$TMP/phase-tracker.json" <<'EOF'
|
|
33
|
-
{
|
|
34
|
-
"task_id": "PROJ-100",
|
|
35
|
-
"started_at": "2026-04-27T10:00:00Z",
|
|
36
|
-
"phases": [
|
|
37
|
-
{"id":"0","name":"Init","status":"completed","started_at":"2026-04-27T10:00:00Z","completed_at":"2026-04-27T10:00:30Z","tokens_in":1000,"tokens_out":200,"model":"sonnet","subs":[]},
|
|
38
|
-
{"id":"1","name":"Analysis","status":"completed","started_at":"2026-04-27T10:00:30Z","completed_at":"2026-04-27T10:05:00Z","tokens_in":50000,"tokens_out":3000,"model":"opus","subs":[{"id":"1.0","name":"Explore","status":"completed"}]},
|
|
39
|
-
{"id":"3","name":"Dev","status":"failed","started_at":"2026-04-27T10:10:00Z","completed_at":"2026-04-27T10:30:00Z","tokens_in":10000,"tokens_out":2000,"model":"sonnet","subs":[]}
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
EOF
|
|
43
|
-
cat > "$TMP/otel-spans.jsonl" <<'EOF'
|
|
44
|
-
{"name":"phase.update","ts":"2026-04-27T10:00:30Z","attributes":{"multi_agent.status":"completed"}}
|
|
45
|
-
{"name":"phase.tokens","ts":"2026-04-27T10:25:00Z","attributes":{"multi_agent.tokens_in_delta":10000}}
|
|
46
|
-
EOF
|
|
47
|
-
[ -f "$TMP/phase-tracker.json" ] && pass "synthetic phase-tracker.json written"
|
|
48
|
-
[ -f "$TMP/otel-spans.jsonl" ] && pass "synthetic otel-spans.jsonl written"
|
|
49
|
-
|
|
50
|
-
# Compute hash of source files BEFORE running aggregator
|
|
51
|
-
HASH_BEFORE=$(md5 -q "$TMP/phase-tracker.json" "$TMP/otel-spans.jsonl" 2>/dev/null || \
|
|
52
|
-
md5sum "$TMP/phase-tracker.json" "$TMP/otel-spans.jsonl" 2>/dev/null | awk '{print $1}' | tr -d '\n')
|
|
53
|
-
|
|
54
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
55
|
-
echo "→ 2. Run aggregator → pipeline-run.jsonl produced"
|
|
56
|
-
node "$SCRIPT" --task-dir "$TMP" 2>/dev/null
|
|
57
|
-
if [ -f "$TMP/pipeline-run.jsonl" ]; then
|
|
58
|
-
pass "pipeline-run.jsonl created"
|
|
59
|
-
else
|
|
60
|
-
fail "pipeline-run.jsonl not created"
|
|
61
|
-
fi
|
|
62
|
-
|
|
63
|
-
LINE_COUNT=$(wc -l < "$TMP/pipeline-run.jsonl" | tr -d ' ')
|
|
64
|
-
if [ "$LINE_COUNT" -ge 8 ]; then
|
|
65
|
-
pass "output has $LINE_COUNT events (≥ 8 expected)"
|
|
66
|
-
else
|
|
67
|
-
fail "too few events: $LINE_COUNT"
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
71
|
-
echo "→ 3. Read-only contract - source files untouched"
|
|
72
|
-
HASH_AFTER=$(md5 -q "$TMP/phase-tracker.json" "$TMP/otel-spans.jsonl" 2>/dev/null || \
|
|
73
|
-
md5sum "$TMP/phase-tracker.json" "$TMP/otel-spans.jsonl" 2>/dev/null | awk '{print $1}' | tr -d '\n')
|
|
74
|
-
if [ "$HASH_BEFORE" = "$HASH_AFTER" ]; then
|
|
75
|
-
pass "source files unchanged after aggregation"
|
|
76
|
-
else
|
|
77
|
-
fail "source files were modified (hash drift)"
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
# Static check: aggregator script does not write to phase-tracker or otel-spans
|
|
81
|
-
if grep -qE "writeFileSync.*phase-tracker|writeFileSync.*otel-spans" "$SCRIPT"; then
|
|
82
|
-
fail "run-aggregator.mjs writes to source telemetry files (read-only contract violated)"
|
|
83
|
-
else
|
|
84
|
-
pass "no writes to source telemetry files in aggregator"
|
|
85
|
-
fi
|
|
86
|
-
|
|
87
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
88
|
-
echo "→ 4. Time-sorted events"
|
|
89
|
-
# Extract ts values and verify sorted (lexicographic = time-sorted for ISO 8601)
|
|
90
|
-
TSS=$(grep -oE '"ts":"[^"]*"' "$TMP/pipeline-run.jsonl" | sed 's/"ts":"//;s/"//')
|
|
91
|
-
if [ "$TSS" = "$(echo "$TSS" | sort)" ]; then
|
|
92
|
-
pass "events time-sorted (ISO ts ascending)"
|
|
93
|
-
else
|
|
94
|
-
fail "events out of time order"
|
|
95
|
-
fi
|
|
96
|
-
|
|
97
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
98
|
-
echo "→ 5. Cost computation correct"
|
|
99
|
-
# sonnet 1000+200 = 0.001*3 + 0.0002*15 = 0.003 + 0.003 = 0.006
|
|
100
|
-
# opus 50000+3000 = 0.05*5 + 0.003*25 = 0.25 + 0.075 = 0.325
|
|
101
|
-
# sonnet 10000+2000 = 0.01*3 + 0.002*15 = 0.03 + 0.03 = 0.060
|
|
102
|
-
# total = 0.006 + 0.325 + 0.060 = 0.391
|
|
103
|
-
SUMMARY=$(tail -1 "$TMP/pipeline-run.jsonl")
|
|
104
|
-
TOTAL=$(echo "$SUMMARY" | grep -oE '"total_cost_usd":[^,}]*' | sed 's/"total_cost_usd"://')
|
|
105
|
-
if [ "$TOTAL" = "0.391" ]; then
|
|
106
|
-
pass "total_cost_usd = $TOTAL (matches expected)"
|
|
107
|
-
else
|
|
108
|
-
fail "total_cost_usd = $TOTAL (expected 0.391)"
|
|
109
|
-
fi
|
|
110
|
-
|
|
111
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
112
|
-
echo "→ 6. Summary as last event"
|
|
113
|
-
LAST_KIND=$(tail -1 "$TMP/pipeline-run.jsonl" | grep -oE '"kind":"[^"]*"' | head -1)
|
|
114
|
-
if [ "$LAST_KIND" = '"kind":"summary"' ]; then
|
|
115
|
-
pass "summary is the final event"
|
|
116
|
-
else
|
|
117
|
-
fail "last event is not summary: $LAST_KIND"
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
121
|
-
echo "→ 7. Phase status counted correctly"
|
|
122
|
-
COMPLETED=$(echo "$SUMMARY" | grep -oE '"phases_completed":[0-9]+' | grep -oE '[0-9]+')
|
|
123
|
-
FAILED=$(echo "$SUMMARY" | grep -oE '"phases_failed":[0-9]+' | grep -oE '[0-9]+')
|
|
124
|
-
if [ "$COMPLETED" = "2" ] && [ "$FAILED" = "1" ]; then
|
|
125
|
-
pass "phases_completed=$COMPLETED phases_failed=$FAILED (matches fixture)"
|
|
126
|
-
else
|
|
127
|
-
fail "phase counts wrong: completed=$COMPLETED failed=$FAILED (expected 2/1)"
|
|
128
|
-
fi
|
|
129
|
-
|
|
130
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
131
|
-
echo "→ 8. Span passthrough with task_id stamping"
|
|
132
|
-
SPAN_COUNT=$(grep -c '"kind":"span"' "$TMP/pipeline-run.jsonl" || true)
|
|
133
|
-
if [ "$SPAN_COUNT" = "2" ]; then
|
|
134
|
-
pass "all 2 spans passed through"
|
|
135
|
-
else
|
|
136
|
-
fail "span passthrough count wrong: $SPAN_COUNT (expected 2)"
|
|
137
|
-
fi
|
|
138
|
-
if grep -q '"kind":"span".*"task_id":"PROJ-100"' "$TMP/pipeline-run.jsonl"; then
|
|
139
|
-
pass "spans stamped with task_id"
|
|
140
|
-
else
|
|
141
|
-
fail "spans missing task_id stamp"
|
|
142
|
-
fi
|
|
143
|
-
|
|
144
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
145
|
-
echo "→ 9. --summary-only mode"
|
|
146
|
-
SUMMARY_OUT=$(node "$SCRIPT" --task-dir "$TMP" --stdout --summary-only 2>/dev/null)
|
|
147
|
-
SUMMARY_LINES=$(echo "$SUMMARY_OUT" | grep -c "^{" || true)
|
|
148
|
-
if [ "$SUMMARY_LINES" = "1" ]; then
|
|
149
|
-
pass "--summary-only emits exactly 1 line"
|
|
150
|
-
else
|
|
151
|
-
fail "--summary-only emitted $SUMMARY_LINES lines"
|
|
152
|
-
fi
|
|
153
|
-
|
|
154
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
155
|
-
echo "→ 10. Unknown model graceful degradation"
|
|
156
|
-
cat > "$TMP/phase-tracker.json" <<'EOF'
|
|
157
|
-
{
|
|
158
|
-
"task_id": "PROJ-200",
|
|
159
|
-
"started_at": "2026-04-27T11:00:00Z",
|
|
160
|
-
"phases": [
|
|
161
|
-
{"id":"0","name":"Init","status":"completed","started_at":"2026-04-27T11:00:00Z","completed_at":"2026-04-27T11:00:10Z","tokens_in":500,"tokens_out":50,"model":"made-up-model","subs":[]}
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
EOF
|
|
165
|
-
rm -f "$TMP/otel-spans.jsonl"
|
|
166
|
-
node "$SCRIPT" --task-dir "$TMP" --stdout 2>/dev/null > "$TMP/run.jsonl"
|
|
167
|
-
if grep -q '"cost_unknown_model":true' "$TMP/run.jsonl"; then
|
|
168
|
-
pass "unknown model marked with cost_unknown_model flag"
|
|
169
|
-
else
|
|
170
|
-
fail "unknown model not flagged"
|
|
171
|
-
fi
|
|
172
|
-
SUMMARY=$(tail -1 "$TMP/run.jsonl")
|
|
173
|
-
if echo "$SUMMARY" | grep -q '"unknown_model_phases":1'; then
|
|
174
|
-
pass "summary records unknown_model_phases count"
|
|
175
|
-
else
|
|
176
|
-
fail "summary missing unknown_model_phases counter"
|
|
177
|
-
fi
|
|
178
|
-
|
|
179
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
180
|
-
echo "→ 11. Missing task-dir errors clearly"
|
|
181
|
-
set +e
|
|
182
|
-
node "$SCRIPT" --task-dir /nonexistent/path 2>"$TMP/err.txt"
|
|
183
|
-
EC=$?
|
|
184
|
-
set -e
|
|
185
|
-
if [ "$EC" -ne 0 ] && grep -qE "not found" "$TMP/err.txt"; then
|
|
186
|
-
pass "missing task-dir exits $EC with 'not found' error"
|
|
187
|
-
else
|
|
188
|
-
fail "missing task-dir error handling weak (exit=$EC)"
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
192
|
-
echo "→ 12. Idempotent - second run produces identical content"
|
|
193
|
-
# Restore the first fixture
|
|
194
|
-
cat > "$TMP/phase-tracker.json" <<'EOF'
|
|
195
|
-
{
|
|
196
|
-
"task_id": "PROJ-100",
|
|
197
|
-
"started_at": "2026-04-27T10:00:00Z",
|
|
198
|
-
"phases": [
|
|
199
|
-
{"id":"0","name":"Init","status":"completed","started_at":"2026-04-27T10:00:00Z","completed_at":"2026-04-27T10:00:30Z","tokens_in":1000,"tokens_out":200,"model":"sonnet","subs":[]}
|
|
200
|
-
]
|
|
201
|
-
}
|
|
202
|
-
EOF
|
|
203
|
-
node "$SCRIPT" --task-dir "$TMP" 2>/dev/null
|
|
204
|
-
H1=$(md5 -q "$TMP/pipeline-run.jsonl" 2>/dev/null || md5sum "$TMP/pipeline-run.jsonl" | awk '{print $1}')
|
|
205
|
-
node "$SCRIPT" --task-dir "$TMP" 2>/dev/null
|
|
206
|
-
H2=$(md5 -q "$TMP/pipeline-run.jsonl" 2>/dev/null || md5sum "$TMP/pipeline-run.jsonl" | awk '{print $1}')
|
|
207
|
-
if [ "$H1" = "$H2" ]; then
|
|
208
|
-
pass "two consecutive runs produce identical output"
|
|
209
|
-
else
|
|
210
|
-
fail "output drift between runs ($H1 vs $H2)"
|
|
211
|
-
fi
|
|
212
|
-
|
|
213
|
-
# ──────────────────────────────────────────────────────────────────────────
|
|
214
|
-
echo ""
|
|
215
|
-
echo "══ run-aggregator smoke: $PASS passed, $FAIL failed ══"
|
|
216
|
-
[ "$FAIL" -eq 0 ]
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-run-metrics.sh - run-metrics.mjs extracts the right outcome numbers
|
|
3
|
-
# from an agent-state.json. This is the evidence-collection harness: run it
|
|
4
|
-
# after each real task and the corpus becomes the real-world validation.
|
|
5
|
-
#
|
|
6
|
-
# Exit 0 = all pass, 1 = any failure.
|
|
7
|
-
|
|
8
|
-
set -uo pipefail
|
|
9
|
-
|
|
10
|
-
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
11
|
-
M="$ROOT/pipeline/scripts/run-metrics.mjs"
|
|
12
|
-
FIX="$ROOT/pipeline/eval/run-metrics-fixture.json"
|
|
13
|
-
PASS=0; FAIL=0
|
|
14
|
-
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
15
|
-
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
16
|
-
command -v node >/dev/null 2>&1 || { echo "error: node required" >&2; exit 127; }
|
|
17
|
-
command -v jq >/dev/null 2>&1 || { echo "error: jq required" >&2; exit 127; }
|
|
18
|
-
[ -f "$M" ] || { echo "FAIL: run-metrics.mjs missing" >&2; exit 1; }
|
|
19
|
-
[ -f "$FIX" ] || { echo "FAIL: fixture missing" >&2; exit 1; }
|
|
20
|
-
|
|
21
|
-
out=$(node "$M" --state "$FIX" 2>/dev/null)
|
|
22
|
-
|
|
23
|
-
check() { # jq-expr desc
|
|
24
|
-
if jq -e "$1" >/dev/null 2>&1 <<< "$out"; then pass "$2"; else fail "$2 (got: $(jq -c "$3" <<< "$out" 2>/dev/null))"; fi
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
echo "→ 1. core outcome fields"
|
|
28
|
-
check '.status == "complete"' "status parsed" '.status'
|
|
29
|
-
check '.reviewIterations == 2' "review iterations counted (rework loop)" '.reviewIterations'
|
|
30
|
-
check '.firstPassClean == false' "first-pass-clean detects iteration-1 blocker" '.firstPassClean'
|
|
31
|
-
check '.buildPassed == true' "build outcome aggregated across repos" '.buildPassed'
|
|
32
|
-
|
|
33
|
-
echo ""
|
|
34
|
-
echo "→ 2. review signal-to-noise"
|
|
35
|
-
check '.reviewSignal.rawFindings == 3' "raw reviewer findings summed" '.reviewSignal.rawFindings'
|
|
36
|
-
check '.reviewSignal.acceptedAll == 1' "accepted summed across iterations" '.reviewSignal.acceptedAll'
|
|
37
|
-
check '.reviewSignal.acceptedRatio == 0.33' "accepted ratio (signal-to-noise)" '.reviewSignal.acceptedRatio'
|
|
38
|
-
|
|
39
|
-
echo ""
|
|
40
|
-
echo "→ 3. consensus surfaced"
|
|
41
|
-
check '.consensusVerdict == "unanimous-pass"' "consensus verdict extracted" '.consensusVerdict'
|
|
42
|
-
|
|
43
|
-
echo ""
|
|
44
|
-
echo "→ 4. stdin + missing-field resilience"
|
|
45
|
-
echo '{"taskId":"X","status":"failed"}' | node "$M" --state - >/dev/null 2>&1 && pass "minimal state via stdin does not crash" || fail "stdin/minimal state crashed"
|
|
46
|
-
node "$M" 2>/dev/null; [ "$?" = "2" ] && pass "no --state -> usage exit 2" || fail "missing --state wrong exit"
|
|
47
|
-
|
|
48
|
-
echo ""
|
|
49
|
-
echo "══ run-metrics smoke: $PASS passed, $FAIL failed ══"
|
|
50
|
-
[ "$FAIL" -eq 0 ]
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-search.sh - WS v5.1.0 log-search self-verification.
|
|
3
|
-
#
|
|
4
|
-
# Verifies (on synthetic fixture tree, never touches real ~/.claude/logs/):
|
|
5
|
-
# 1. Script executable, --help shows banner.
|
|
6
|
-
# 2. Plain query returns matching tasks.
|
|
7
|
-
# 3. --project filter narrows results.
|
|
8
|
-
# 4. --since 7d drops old files.
|
|
9
|
-
# 5. --phase N limits search to phase section.
|
|
10
|
-
# 6. --limit caps results.
|
|
11
|
-
# 7. JSON output is valid JSON with matched_tasks count.
|
|
12
|
-
# 8. TSV output has header + one row per task.
|
|
13
|
-
# 9. No-match returns exit 1 + friendly message.
|
|
14
|
-
# 10. Ranking: recent matches score higher than old ones.
|
|
15
|
-
|
|
16
|
-
set -uo pipefail
|
|
17
|
-
|
|
18
|
-
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
19
|
-
ROOT="$(cd "$HERE/../.." && pwd)"
|
|
20
|
-
SEARCH="$ROOT/pipeline/scripts/search-logs.sh"
|
|
21
|
-
|
|
22
|
-
PASS=0
|
|
23
|
-
FAIL=0
|
|
24
|
-
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
25
|
-
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
26
|
-
|
|
27
|
-
need() { command -v "$1" >/dev/null 2>&1 || { echo "error: $1 required" >&2; exit 127; }; }
|
|
28
|
-
need jq
|
|
29
|
-
|
|
30
|
-
FIX=$(mktemp -d)
|
|
31
|
-
trap 'rm -rf "$FIX"' EXIT
|
|
32
|
-
|
|
33
|
-
# --- Fixture tree --------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
# Shape: $FIX/<project>/<task_id>/agent-log.md
|
|
36
|
-
|
|
37
|
-
mkdir -p "$FIX/app/PROJ-1234" "$FIX/app/PROJ-1337" "$FIX/api/API-42" "$FIX/app/PROJ-OLD"
|
|
38
|
-
|
|
39
|
-
cat > "$FIX/app/PROJ-1234/agent-log.md" <<'EOF'
|
|
40
|
-
# PROJ-1234 - Add flight price filter
|
|
41
|
-
|
|
42
|
-
**Branch**: feature/PROJ-1234-flight-filter | **Project**: app
|
|
43
|
-
|
|
44
|
-
## Phase 1: Analysis
|
|
45
|
-
Explored the flight booking module.
|
|
46
|
-
|
|
47
|
-
## Phase 3: Dev
|
|
48
|
-
Wrote FlightFilterView. Null check added for optional price range.
|
|
49
|
-
|
|
50
|
-
## Phase 4: Review
|
|
51
|
-
0 blocking, 2 important, 5 suggestion.
|
|
52
|
-
EOF
|
|
53
|
-
|
|
54
|
-
cat > "$FIX/app/PROJ-1337/agent-log.md" <<'EOF'
|
|
55
|
-
# PROJ-1337 - Guard null in BookingViewModel
|
|
56
|
-
|
|
57
|
-
**Branch**: bugfix/PROJ-1337-null-deref | **Project**: app
|
|
58
|
-
|
|
59
|
-
## Phase 3: Dev
|
|
60
|
-
Null-deref fixed at BookingViewModel.swift:142 via guard let.
|
|
61
|
-
Added regression test.
|
|
62
|
-
|
|
63
|
-
## Phase 4: Review
|
|
64
|
-
Reviewer flagged the null check as important. Blocking.
|
|
65
|
-
EOF
|
|
66
|
-
|
|
67
|
-
cat > "$FIX/api/API-42/agent-log.md" <<'EOF'
|
|
68
|
-
# API-42 - Rate limit header mismatch
|
|
69
|
-
|
|
70
|
-
**Branch**: bugfix/API-42-rate-limit | **Project**: api
|
|
71
|
-
|
|
72
|
-
## Phase 3: Dev
|
|
73
|
-
Fixed X-RateLimit-Remaining header emission.
|
|
74
|
-
EOF
|
|
75
|
-
|
|
76
|
-
cat > "$FIX/app/PROJ-OLD/agent-log.md" <<'EOF'
|
|
77
|
-
# PROJ-OLD - Old task
|
|
78
|
-
|
|
79
|
-
**Branch**: feature/PROJ-OLD-archive | **Project**: app
|
|
80
|
-
|
|
81
|
-
## Phase 3: Dev
|
|
82
|
-
Contains the word null but from long ago.
|
|
83
|
-
EOF
|
|
84
|
-
# make PROJ-OLD old: 60 days ago
|
|
85
|
-
OLD_EPOCH=$(date -v-60d +%s 2>/dev/null || date -d "-60 days" +%s)
|
|
86
|
-
touch -t "$(date -r "$OLD_EPOCH" +%Y%m%d%H%M 2>/dev/null || date -d "@$OLD_EPOCH" +%Y%m%d%H%M)" "$FIX/app/PROJ-OLD/agent-log.md"
|
|
87
|
-
|
|
88
|
-
# --- 1. Executable + help -----------------------------------------------
|
|
89
|
-
|
|
90
|
-
echo "→ 1. search-logs.sh executable + help"
|
|
91
|
-
[ -x "$SEARCH" ] && pass "search-logs.sh is executable" || fail "search-logs.sh not executable"
|
|
92
|
-
bash "$SEARCH" --help 2>&1 | head -1 | grep -q "search-logs" && pass "--help banner present" || fail "--help banner missing"
|
|
93
|
-
|
|
94
|
-
# --- 2. Plain query -----------------------------------------------------
|
|
95
|
-
|
|
96
|
-
echo ""
|
|
97
|
-
echo "→ 2. plain query returns matching tasks"
|
|
98
|
-
OUT=$(bash "$SEARCH" --root "$FIX" "null" 2>&1)
|
|
99
|
-
echo "$OUT" | grep -q "PROJ-1337" && pass "PROJ-1337 (high match count) returned" || fail "PROJ-1337 missing"
|
|
100
|
-
echo "$OUT" | grep -q "PROJ-1234" && pass "PROJ-1234 (single match) returned" || fail "PROJ-1234 missing"
|
|
101
|
-
echo "$OUT" | grep -q "API-42" && fail "API-42 wrongly returned (no 'null')" || pass "API-42 correctly excluded (no 'null')"
|
|
102
|
-
|
|
103
|
-
# --- 3. --project filter ------------------------------------------------
|
|
104
|
-
|
|
105
|
-
echo ""
|
|
106
|
-
echo "→ 3. --project filter narrows results"
|
|
107
|
-
OUT=$(bash "$SEARCH" --root "$FIX" --project api "null" 2>&1)
|
|
108
|
-
echo "$OUT" | grep -q "no matches" && pass "api project has no 'null' → correctly empty" || fail "api project filter leaked"
|
|
109
|
-
OUT=$(bash "$SEARCH" --root "$FIX" --project app "null" 2>&1)
|
|
110
|
-
echo "$OUT" | grep -q "PROJ-1234" && pass "app project filter includes PROJ-1234" || fail "app project filter broken"
|
|
111
|
-
|
|
112
|
-
# --- 4. --since filter --------------------------------------------------
|
|
113
|
-
|
|
114
|
-
echo ""
|
|
115
|
-
echo "→ 4. --since 7d drops old tasks"
|
|
116
|
-
OUT=$(bash "$SEARCH" --root "$FIX" --since 7d "null" 2>&1)
|
|
117
|
-
echo "$OUT" | grep -q "PROJ-OLD" && fail "PROJ-OLD (60d) wrongly included with --since 7d" || pass "PROJ-OLD correctly dropped with --since 7d"
|
|
118
|
-
echo "$OUT" | grep -q "PROJ-1337" && pass "recent PROJ-1337 still included with --since 7d" || fail "recent task lost with --since 7d"
|
|
119
|
-
|
|
120
|
-
# --- 5. --phase filter --------------------------------------------------
|
|
121
|
-
|
|
122
|
-
echo ""
|
|
123
|
-
echo "→ 5. --phase 4 limits to phase section"
|
|
124
|
-
OUT=$(bash "$SEARCH" --root "$FIX" --phase 4 "blocking" 2>&1)
|
|
125
|
-
echo "$OUT" | grep -q "PROJ-1337" && pass "--phase 4 matches Phase 4 content" || fail "--phase 4 broke"
|
|
126
|
-
|
|
127
|
-
# --- 6. --limit -----------------------------------------------------
|
|
128
|
-
|
|
129
|
-
echo ""
|
|
130
|
-
echo "→ 6. --limit caps results"
|
|
131
|
-
OUT=$(bash "$SEARCH" --root "$FIX" --limit 1 "null" 2>&1)
|
|
132
|
-
count=$(echo "$OUT" | grep -c "^PROJ-\|^API-\|^FIX-")
|
|
133
|
-
# just verify command runs and limits in JSON (safer check)
|
|
134
|
-
OUT=$(bash "$SEARCH" --root "$FIX" --limit 1 "null" --json 2>&1)
|
|
135
|
-
count=$(echo "$OUT" | jq -r '.tasks | length')
|
|
136
|
-
[ "$count" -eq 1 ] && pass "--limit 1 returns exactly 1 task" || fail "--limit 1 returned $count tasks"
|
|
137
|
-
|
|
138
|
-
# --- 7. JSON output -----------------------------------------------------
|
|
139
|
-
|
|
140
|
-
echo ""
|
|
141
|
-
echo "→ 7. JSON output valid"
|
|
142
|
-
OUT=$(bash "$SEARCH" --root "$FIX" "null" --json 2>&1)
|
|
143
|
-
if echo "$OUT" | jq . >/dev/null 2>&1; then
|
|
144
|
-
pass "JSON is valid"
|
|
145
|
-
else
|
|
146
|
-
fail "JSON invalid"
|
|
147
|
-
fi
|
|
148
|
-
MATCHED=$(echo "$OUT" | jq -r '.matched_tasks')
|
|
149
|
-
[ "$MATCHED" -ge 2 ] && pass "JSON matched_tasks ≥ 2 (got $MATCHED)" || fail "JSON matched_tasks = $MATCHED"
|
|
150
|
-
|
|
151
|
-
# --- 8. TSV output ------------------------------------------------------
|
|
152
|
-
|
|
153
|
-
echo ""
|
|
154
|
-
echo "→ 8. TSV output has header + rows"
|
|
155
|
-
OUT=$(bash "$SEARCH" --root "$FIX" "null" --tsv 2>&1)
|
|
156
|
-
echo "$OUT" | head -1 | grep -q "^score" && pass "TSV has header row" || fail "TSV missing header"
|
|
157
|
-
BODY_LINES=$(echo "$OUT" | tail -n +2 | wc -l | tr -d ' ')
|
|
158
|
-
[ "$BODY_LINES" -ge 2 ] && pass "TSV has ≥ 2 body rows" || fail "TSV body rows = $BODY_LINES"
|
|
159
|
-
|
|
160
|
-
# --- 9. No-match path ---------------------------------------------------
|
|
161
|
-
|
|
162
|
-
echo ""
|
|
163
|
-
echo "→ 9. no-match → exit 1 + friendly message"
|
|
164
|
-
set +e
|
|
165
|
-
bash "$SEARCH" --root "$FIX" "nonexistent-string-xyz" > /tmp/search-out 2>&1
|
|
166
|
-
RC=$?
|
|
167
|
-
set -e
|
|
168
|
-
[ "$RC" -eq 1 ] && pass "no-match exit code = 1" || fail "expected 1, got $RC"
|
|
169
|
-
grep -q "no matches" /tmp/search-out && pass "no-match message shown" || fail "no-match message missing"
|
|
170
|
-
|
|
171
|
-
# --- 10. Ranking: recent > old ------------------------------------------
|
|
172
|
-
|
|
173
|
-
echo ""
|
|
174
|
-
echo "→ 10. ranking prefers recent matches (score = matches × recency)"
|
|
175
|
-
# PROJ-1234: 1 match, recent → score=100 (100% weight)
|
|
176
|
-
# PROJ-1337: multiple matches, recent → score>100
|
|
177
|
-
# PROJ-OLD: 1 match, 60d old → score=20 (20% weight)
|
|
178
|
-
OUT=$(bash "$SEARCH" --root "$FIX" "null" --json 2>&1)
|
|
179
|
-
FIRST_ID=$(echo "$OUT" | jq -r '.tasks[0].task_id')
|
|
180
|
-
FIRST_SCORE=$(echo "$OUT" | jq -r '.tasks[0].score')
|
|
181
|
-
[ "$FIRST_ID" = "PROJ-1337" ] && pass "highest score is PROJ-1337 ($FIRST_SCORE)" || fail "expected PROJ-1337 on top, got $FIRST_ID"
|
|
182
|
-
|
|
183
|
-
# --- Summary ------------------------------------------------------------
|
|
184
|
-
|
|
185
|
-
echo ""
|
|
186
|
-
echo "══ search smoke: $PASS passed, $FAIL failed ══"
|
|
187
|
-
[ "$FAIL" -eq 0 ]
|