@mmerterden/multi-agent-pipeline 18.0.0 → 19.0.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 +183 -0
- package/README.md +34 -18
- package/README.tr.md +14 -16
- package/docs/adr/0002-instruction-driven-flag.md +1 -0
- package/docs/adr/0005-lazy-phase-docs.md +11 -1
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +1 -0
- package/docs/adr/0010-own-code-graph.md +1 -0
- package/docs/adr/0014-six-phase-consolidation.md +134 -0
- package/docs/adr/README.md +2 -1
- package/docs/architecture.md +37 -38
- package/docs/best-practices.md +1 -1
- package/docs/ecosystem.md +37 -26
- package/docs/engineering.md +1 -1
- package/docs/facts.json +45 -0
- package/docs/features.md +54 -53
- package/docs/performance.md +5 -5
- package/docs/recovery-guide.md +9 -9
- package/docs/token-budget-history.md +3 -1
- package/index.js +2 -2
- package/install/_codex-agents.mjs +1 -1
- package/install/templates/claude-hooks.json +1 -1
- package/install/templates/codex-instructions.md +1 -1
- package/install/templates/copilot-instructions.md +28 -28
- package/manifest.json +209 -193
- package/package.json +2 -2
- package/pipeline/agents/dev-critic.md +3 -3
- package/pipeline/commands/figma-to-swiftui.md +1 -1
- package/pipeline/commands/multi-agent/SKILL.md +8 -8
- package/pipeline/commands/multi-agent/analysis/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +7 -7
- package/pipeline/commands/multi-agent/channels/SKILL.md +15 -15
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +6 -6
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/graph/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/help/SKILL.md +62 -62
- package/pipeline/commands/multi-agent/language/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/local/SKILL.md +11 -11
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +13 -13
- package/pipeline/commands/multi-agent/log/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/model/SKILL.md +69 -0
- package/pipeline/commands/multi-agent/refactor/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/resume/SKILL.md +4 -4
- package/pipeline/commands/multi-agent/resume-local/SKILL.md +19 -17
- package/pipeline/commands/multi-agent/review/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/route-off/SKILL.md +36 -0
- package/pipeline/commands/multi-agent/route-on/SKILL.md +74 -0
- package/pipeline/commands/multi-agent/route-status/SKILL.md +56 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/status/SKILL.md +5 -5
- package/pipeline/commands/multi-agent/steer/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/sync/SKILL.md +12 -13
- package/pipeline/commands/multi-agent/test/SKILL.md +1 -1
- package/pipeline/lib/credential-inventory.sh +1 -1
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/model-rung.sh +142 -0
- package/pipeline/lib/phase-schema.mjs +88 -0
- package/pipeline/lib/plan-todos.sh +5 -5
- package/pipeline/lib/route-state.sh +161 -0
- package/pipeline/lib/run-paths.sh +2 -2
- 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/_input-parser.md +1 -1
- package/pipeline/multi-agent-refs/analysis/evidence.md +0 -9
- package/pipeline/multi-agent-refs/analysis/intake.md +1 -1
- package/pipeline/multi-agent-refs/analysis/locked.md +21 -22
- package/pipeline/multi-agent-refs/analysis/render.md +1 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +12 -6
- package/pipeline/multi-agent-refs/android-guide.md +1 -1
- package/pipeline/multi-agent-refs/audit-guide.md +13 -13
- package/pipeline/multi-agent-refs/channels/issue-comment.md +2 -2
- package/pipeline/multi-agent-refs/channels/jira.md +3 -3
- package/pipeline/multi-agent-refs/channels/pr.md +4 -4
- package/pipeline/multi-agent-refs/channels/wiki.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
- package/pipeline/multi-agent-refs/cross-cli-contract.md +31 -6
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +4 -4
- package/pipeline/multi-agent-refs/features/code-graph.md +5 -5
- package/pipeline/multi-agent-refs/features/design-conformance.md +1 -1
- package/pipeline/multi-agent-refs/features/dev-critic.md +3 -3
- package/pipeline/multi-agent-refs/features/doctor.md +2 -2
- package/pipeline/multi-agent-refs/features/external-context-injection.md +3 -3
- package/pipeline/multi-agent-refs/features/maturity-followup.md +3 -3
- package/pipeline/multi-agent-refs/features/model-fallback.md +5 -5
- package/pipeline/multi-agent-refs/features/plan-todos.md +1 -1
- package/pipeline/multi-agent-refs/features/repo-map.md +1 -1
- package/pipeline/multi-agent-refs/features/review-delta.md +3 -3
- package/pipeline/multi-agent-refs/features/review-multi-repo.md +1 -1
- package/pipeline/multi-agent-refs/features/scope-check.md +4 -4
- package/pipeline/multi-agent-refs/features/skill-conformance.md +2 -2
- package/pipeline/multi-agent-refs/features/stack-skill-routing.md +1 -1
- package/pipeline/multi-agent-refs/features/verify-by-test.md +4 -4
- package/pipeline/multi-agent-refs/features/visual-evidence.md +19 -19
- package/pipeline/multi-agent-refs/features/worktree-finalize.md +6 -6
- package/pipeline/multi-agent-refs/issue-jira-triad.md +10 -10
- package/pipeline/multi-agent-refs/knowledge.md +11 -11
- package/pipeline/multi-agent-refs/multi-repo-integration-build.md +13 -13
- package/pipeline/multi-agent-refs/payload-contracts.md +8 -8
- package/pipeline/multi-agent-refs/phases/log-format.md +10 -10
- package/pipeline/multi-agent-refs/phases/modes.md +30 -30
- package/pipeline/multi-agent-refs/phases/operations.md +8 -8
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +24 -24
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +599 -0
- package/pipeline/multi-agent-refs/phases/{phase-3-dev.md → phase-2-dev.md} +129 -49
- package/pipeline/multi-agent-refs/phases/{phase-4-review.md → phase-3-review.md} +225 -107
- package/pipeline/multi-agent-refs/phases/{phase-6-commit.md → phase-4-commit.md} +23 -23
- package/pipeline/multi-agent-refs/phases/{phase-7-report.md → phase-5-report.md} +29 -29
- package/pipeline/multi-agent-refs/phases.md +44 -48
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/progress-contract.md +6 -6
- package/pipeline/multi-agent-refs/readiness-review.md +1 -1
- package/pipeline/multi-agent-refs/rules.md +7 -7
- package/pipeline/multi-agent-refs/swiftui-guide.md +2 -2
- package/pipeline/multi-agent-refs/tracker-contract.md +31 -32
- package/pipeline/multi-agent-refs/wiki-capture.md +14 -14
- package/pipeline/preferences-template.json +9 -1
- package/pipeline/rules/outside-the-pipeline.md +1 -1
- package/pipeline/schemas/agent-state.schema.json +50 -50
- package/pipeline/schemas/analysis-output.schema.json +2 -2
- package/pipeline/schemas/autopilot-config.schema.json +1 -1
- package/pipeline/schemas/code-graph.schema.json +1 -1
- package/pipeline/schemas/criteria-manifest.schema.json +1 -1
- package/pipeline/schemas/dev-critic-output.schema.json +1 -1
- package/pipeline/schemas/diff-risk.schema.json +1 -1
- package/pipeline/schemas/migrations/prefs-2.4.0-to-2.5.0.mjs +2 -2
- package/pipeline/schemas/migrations/prefs-2.6.0-to-2.7.0.mjs +31 -0
- package/pipeline/schemas/migrations/state-2.1.0-to-2.2.0.mjs +129 -0
- package/pipeline/schemas/phases.json +105 -0
- package/pipeline/schemas/plan-todos.schema.json +5 -5
- package/pipeline/schemas/planning-output.schema.json +1 -1
- package/pipeline/schemas/prefs.schema.json +100 -56
- package/pipeline/schemas/reviewer-output.schema.json +3 -3
- package/pipeline/schemas/route-config.schema.json +74 -0
- package/pipeline/schemas/scope-check.schema.json +1 -1
- package/pipeline/schemas/test-gap.schema.json +1 -1
- package/pipeline/schemas/token-budget.json +12 -18
- package/pipeline/schemas/triage-output.schema.json +6 -6
- package/pipeline/scripts/README.md +3 -3
- package/pipeline/scripts/_code-graph.mjs +2 -2
- package/pipeline/scripts/_run-paths.mjs +2 -2
- package/pipeline/scripts/_smoke-root.sh +1 -1
- package/pipeline/scripts/aggregate-metrics.mjs +1 -1
- package/pipeline/scripts/capture-flush.sh +8 -8
- package/pipeline/scripts/capture-resume.sh +3 -3
- package/pipeline/scripts/classify-plan-safety.mjs +1 -1
- package/pipeline/scripts/diff-explain.mjs +1 -1
- package/pipeline/scripts/doctor.mjs +2 -2
- package/pipeline/scripts/gc-abandoned.sh +3 -3
- package/pipeline/scripts/gc-tmp.sh +1 -1
- package/pipeline/scripts/gc-worktrees.sh +1 -1
- package/pipeline/scripts/gen-facts.mjs +175 -0
- package/pipeline/scripts/gen-mode-dispatch.mjs +32 -37
- package/pipeline/scripts/gen-ref-toc.mjs +1 -1
- package/pipeline/scripts/graph-report.mjs +1 -1
- package/pipeline/scripts/jira-attach.sh +1 -1
- package/pipeline/scripts/learn-from-transcripts.mjs +1 -1
- package/pipeline/scripts/learning-curve.mjs +2 -2
- package/pipeline/scripts/log-metric.sh +17 -4
- package/pipeline/scripts/memory-save.sh +1 -1
- package/pipeline/scripts/migrate-prefs.mjs +22 -5
- package/pipeline/scripts/phase-banner.sh +20 -20
- package/pipeline/scripts/phase-tracker.sh +7 -7
- package/pipeline/scripts/plan-coverage-gate.mjs +2 -2
- package/pipeline/scripts/render-agent-log-cost.sh +1 -1
- package/pipeline/scripts/render-work-summary.sh +3 -3
- package/pipeline/scripts/review-file-filter.mjs +1 -1
- package/pipeline/scripts/run-aggregator.mjs +13 -6
- package/pipeline/scripts/run-metrics.mjs +1 -1
- package/pipeline/scripts/runs-index.mjs +11 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +6 -6
- package/pipeline/scripts/smoke-schema-validation.sh +26 -7
- package/pipeline/scripts/token-budget-report.mjs +13 -2
- package/pipeline/scripts/triage-memory.mjs +2 -2
- package/pipeline/scripts/validate-analysis-doc.mjs +73 -17
- package/pipeline/scripts/validate-planning.mjs +1 -1
- package/pipeline/scripts/validate-reviewer.mjs +1 -1
- package/pipeline/scripts/validate-state.mjs +45 -5
- package/pipeline/scripts/validate-triage.mjs +3 -3
- package/pipeline/scripts/worktree-finalize.sh +5 -5
- package/pipeline/skills/.skill-manifest.json +37 -21
- package/pipeline/skills/.skills-index.json +49 -5
- package/pipeline/skills/shared/README.md +10 -6
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +2 -2
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +69 -71
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +14 -14
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +5 -5
- package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +25 -23
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +8 -8
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +6 -6
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +71 -0
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-resume-local/SKILL.md +7 -7
- package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +39 -0
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +76 -0
- package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +59 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +5 -5
- package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +6 -5
- package/pipeline/skills/skills-index.md +8 -4
- package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +0 -263
- package/pipeline/multi-agent-refs/phases/phase-2-planning.md +0 -344
- package/pipeline/multi-agent-refs/phases/phase-5-test.md +0 -182
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
//
|
|
14
14
|
// Section level is DERIVED, not assumed. These files are not consistent: some
|
|
15
15
|
// open at `##` and section at `###` (keychain.md), others open at `###` and
|
|
16
|
-
// section at `##` (phases/phase-
|
|
16
|
+
// section at `##` (phases/phase-2-dev.md). The rule is the shallowest heading
|
|
17
17
|
// depth that occurs more than once - a depth used exactly once is a title, not
|
|
18
18
|
// a section level.
|
|
19
19
|
//
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file graph-report.mjs - GRAPH_REPORT.md, the human-and-model readable summary.
|
|
5
5
|
*
|
|
6
|
-
* Phase 1 reads this before deciding how wide to explore, and Phase
|
|
6
|
+
* Phase 1 reads this before deciding how wide to explore, and Phase 5 ships it
|
|
7
7
|
* next to the knowledge base. Sections are ordered by how much they narrow a
|
|
8
8
|
* search: hubs first (the types everything touches), then the module map, then
|
|
9
9
|
* the long tail that is usually safe to ignore.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
# Two callers need this and they used to carry their own curl: the issue
|
|
7
7
|
# generator (`generate-issue.md` step 12) and visual evidence (Phase 3 / Phase 5
|
|
8
|
-
# captures rendered into the Phase
|
|
8
|
+
# captures rendered into the Phase 5 Jira comment). Two copies of an upload is
|
|
9
9
|
# two places for the `X-Atlassian-Token: no-check` header to go missing, which
|
|
10
10
|
# fails as a 403 that reads like an auth problem.
|
|
11
11
|
#
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* WHY THIS EXISTS
|
|
6
6
|
*
|
|
7
|
-
* Phase
|
|
7
|
+
* Phase 5 asks a subagent to read the run log and propose a few memory entries.
|
|
8
8
|
* That works for what the model noticed, and it is structurally blind to what it
|
|
9
9
|
* did not: the same wrong path tried in three sessions, the command that fails
|
|
10
10
|
* every time until its `--flag` variant is used, the directory that never has
|
|
@@ -87,9 +87,9 @@ for (const e of events) {
|
|
|
87
87
|
}
|
|
88
88
|
if (e.ts && (!t.firstTs || e.ts < t.firstTs)) t.firstTs = e.ts;
|
|
89
89
|
const d = e.details || {};
|
|
90
|
-
// phase-
|
|
90
|
+
// phase-3-review.md's actual review.completed emission (raw_count=/
|
|
91
91
|
// accepted=/deferred=/rejected=/approved=/duration_ms=) carries no
|
|
92
|
-
// review_cycles field - that name only appears on Phase
|
|
92
|
+
// review_cycles field - that name only appears on Phase 5's task.completed
|
|
93
93
|
// summary event, which this never matched. Phase 4 re-runs (and logs its
|
|
94
94
|
// own review.completed) once per rework cycle, so the cycle count for a
|
|
95
95
|
// task is how many review.completed events share its task_id - the same
|
|
@@ -6,11 +6,19 @@
|
|
|
6
6
|
# {
|
|
7
7
|
# "ts": "<ISO 8601 timestamp>",
|
|
8
8
|
# "task_id": "<jira id, github issue, or run id>",
|
|
9
|
-
# "phase": "<0..
|
|
9
|
+
# "phase": "<0..5>",
|
|
10
10
|
# "event": "<event name>",
|
|
11
|
-
# "details": { ...arbitrary key/value pairs... }
|
|
11
|
+
# "details": { ...arbitrary key/value pairs... },
|
|
12
|
+
# "phaseSchema": 2
|
|
12
13
|
# }
|
|
13
14
|
#
|
|
15
|
+
# phaseSchema names the phase vocabulary the line was written under, because
|
|
16
|
+
# this file is append-only and v19.0.0 renumbered the phases. A line with
|
|
17
|
+
# phase 3 means Dev under schema 1 and Review under schema 2. Lines with no
|
|
18
|
+
# phaseSchema field predate v19.0.0 and are schema 1. Aggregators pick their
|
|
19
|
+
# name table from this field; without it the two vocabularies are
|
|
20
|
+
# indistinguishable and every historical roll-up is quietly wrong.
|
|
21
|
+
#
|
|
14
22
|
# Usage:
|
|
15
23
|
# log-metric.sh <task_id> <phase> <event> [key=value ...]
|
|
16
24
|
#
|
|
@@ -18,7 +26,7 @@
|
|
|
18
26
|
# log-metric.sh PROJ-1234 4 review.completed raw_count=8 accepted=3 deferred=2 rejected=3 approved=true duration_ms=42000
|
|
19
27
|
# log-metric.sh PROJ-1234 4 triage.edge_case case=high-rejection-rate
|
|
20
28
|
# log-metric.sh PROJ-1234 3 rework.started iteration=2 accepted_blocking=2
|
|
21
|
-
# log-metric.sh #316
|
|
29
|
+
# log-metric.sh #316 5 task.completed phases=6 review_cycles=2 lang=tr
|
|
22
30
|
#
|
|
23
31
|
# Atomic append: each call uses `>> "$file"` which the kernel guarantees
|
|
24
32
|
# atomic for writes ≤ PIPE_BUF (4 KB on macOS/Linux). One JSONL line is well
|
|
@@ -64,8 +72,13 @@ for kv in "$@"; do
|
|
|
64
72
|
done
|
|
65
73
|
DETAILS="${DETAILS}}"
|
|
66
74
|
|
|
75
|
+
# Read from the phase contract rather than hardcoding: the next renumbering
|
|
76
|
+
# bumps one JSON field instead of hunting for a literal in a shell script.
|
|
77
|
+
PHASE_SCHEMA="$(node -e 'const c=require("'"$(cd "$(dirname "$0")" && pwd)"'/../schemas/phases.json"); process.stdout.write(String(c.phaseSchema))' 2>/dev/null)"
|
|
78
|
+
[ -n "$PHASE_SCHEMA" ] || PHASE_SCHEMA=2
|
|
79
|
+
|
|
67
80
|
TS="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
68
|
-
LINE="{\"ts\":\"${TS}\",\"task_id\":\"${TASK_ID}\",\"phase\":\"${PHASE}\",\"event\":\"${EVENT}\",\"details\":${DETAILS}}"
|
|
81
|
+
LINE="{\"ts\":\"${TS}\",\"task_id\":\"${TASK_ID}\",\"phase\":\"${PHASE}\",\"event\":\"${EVENT}\",\"details\":${DETAILS},\"phaseSchema\":${PHASE_SCHEMA}}"
|
|
69
82
|
|
|
70
83
|
# Atomic append (one line, well under PIPE_BUF).
|
|
71
84
|
echo "$LINE" >> "$METRICS_FILE" 2>/dev/null || {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# memory-save.sh - v6.2.E
|
|
3
3
|
#
|
|
4
4
|
# Writes a single per-repo memory file and updates the MEMORY.md index.
|
|
5
|
-
# Called by Phase
|
|
5
|
+
# Called by Phase 5's synthesis step (or any user skill that wants to
|
|
6
6
|
# persist a finding). Opt-in via prefs.global.perRepoMemory.
|
|
7
7
|
#
|
|
8
8
|
# Usage:
|
|
@@ -18,9 +18,26 @@ import { runMain } from "../lib/fatal.mjs";
|
|
|
18
18
|
|
|
19
19
|
const DEFAULT_FILE = path.join(os.homedir(), ".claude", "multi-agent-preferences.json");
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
|
|
21
|
+
// The migration target, read from the schema rather than written here. It was
|
|
22
|
+
// a literal, and a literal is how it came to say 2.6.0 while the schema had
|
|
23
|
+
// moved to 2.7.0 - the runner then reported every current file as needing a
|
|
24
|
+
// migration it had already had. Referenced by the migrate() bump chain AND
|
|
25
|
+
// every user-facing message, so they cannot drift from each other either.
|
|
26
|
+
const TARGET_VERSION = (() => {
|
|
27
|
+
const schemaPath = path.join(
|
|
28
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
29
|
+
"..",
|
|
30
|
+
"schemas",
|
|
31
|
+
"prefs.schema.json",
|
|
32
|
+
);
|
|
33
|
+
const sv = JSON.parse(fs.readFileSync(schemaPath, "utf-8"))?.properties?.schemaVersion;
|
|
34
|
+
const v = sv?.const ?? sv?.enum?.at(-1);
|
|
35
|
+
if (!v) {
|
|
36
|
+
console.error("migrate-prefs: prefs.schema.json declares no schemaVersion");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
return v;
|
|
40
|
+
})();
|
|
24
41
|
|
|
25
42
|
const USAGE = "Usage: migrate-prefs.mjs [--dry-run] [--file <path>]";
|
|
26
43
|
|
|
@@ -327,7 +344,7 @@ function migrate(prefs) {
|
|
|
327
344
|
out.global.routines = [];
|
|
328
345
|
changes.push("added empty routines (v2.4.0 user-defined /multi-agent:save routines)");
|
|
329
346
|
}
|
|
330
|
-
// v2.5.0 / v14.0.0: Phase
|
|
347
|
+
// v2.5.0 / v14.0.0: Phase 3 Review entered the --dev phase sets and Step 1.78
|
|
331
348
|
// (criteria resolution) landed. Default false because only Swift plus the two
|
|
332
349
|
// store-compliance catalogs ship a scoped registry today, so blocking on a
|
|
333
350
|
// coverage gap would stop every Kotlin/Python/Node/ObjC run from day one. The
|
|
@@ -488,7 +505,7 @@ function migrateReportChannels(out, changes) {
|
|
|
488
505
|
if (typeof g.autopilotReportTimeoutSeconds !== "number") {
|
|
489
506
|
g.autopilotReportTimeoutSeconds = 1800;
|
|
490
507
|
changes.push(
|
|
491
|
-
"added autopilotReportTimeoutSeconds: 1800 (30 min) - Phase
|
|
508
|
+
"added autopilotReportTimeoutSeconds: 1800 (30 min) - Phase 5 always-pause timeout",
|
|
492
509
|
);
|
|
493
510
|
}
|
|
494
511
|
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
# phase-banner.sh label <phase> (print canonical name)
|
|
13
13
|
#
|
|
14
14
|
# Examples:
|
|
15
|
-
# phase-banner.sh start
|
|
16
|
-
# phase-banner.sh start
|
|
17
|
-
# PHASE_LANG=tr phase-banner.sh start
|
|
15
|
+
# phase-banner.sh start 3 "Review" "parallel + triage + user test"
|
|
16
|
+
# phase-banner.sh start 3 auto # resolves to "Review" (en) or "İnceleme" (tr)
|
|
17
|
+
# PHASE_LANG=tr phase-banner.sh start 3 auto # "Faz 3: İnceleme"
|
|
18
18
|
#
|
|
19
19
|
# Status values for `end`: done | failed | skipped
|
|
20
20
|
#
|
|
@@ -32,28 +32,28 @@ set -uo pipefail
|
|
|
32
32
|
|
|
33
33
|
PHASE_LANG="${PHASE_LANG:-en}"
|
|
34
34
|
|
|
35
|
-
# Canonical phase label table.
|
|
36
|
-
# pipeline/
|
|
37
|
-
#
|
|
35
|
+
# Canonical phase label table. The English half is checked against
|
|
36
|
+
# pipeline/schemas/phases.json by smoke-phase-contract.sh, so it cannot drift
|
|
37
|
+
# from the contract in silence the way it did through the eight-phase era. It
|
|
38
|
+
# stays a case statement rather than a jq read because this runs on every
|
|
39
|
+
# banner and the pipeline's zero-dependency rule (ADR-0004) applies to the hot
|
|
40
|
+
# path. The Turkish half has no contract entry - labels are translations, not
|
|
41
|
+
# identifiers - and is kept beside it.
|
|
38
42
|
phase_label() {
|
|
39
43
|
local phase="$1" lang="${2:-en}"
|
|
40
44
|
case "$lang:$phase" in
|
|
41
45
|
en:0) echo "Init" ;;
|
|
42
|
-
en:1) echo "
|
|
43
|
-
en:2) echo "
|
|
44
|
-
en:3) echo "
|
|
45
|
-
en:4) echo "
|
|
46
|
-
en:5) echo "
|
|
47
|
-
en:6) echo "Commit & PR" ;;
|
|
48
|
-
en:7) echo "Report" ;;
|
|
46
|
+
en:1) echo "Plan" ;;
|
|
47
|
+
en:2) echo "Dev" ;;
|
|
48
|
+
en:3) echo "Review" ;;
|
|
49
|
+
en:4) echo "Commit & PR" ;;
|
|
50
|
+
en:5) echo "Report" ;;
|
|
49
51
|
tr:0) echo "Başlangıç" ;;
|
|
50
|
-
tr:1) echo "
|
|
51
|
-
tr:2) echo "
|
|
52
|
-
tr:3) echo "
|
|
53
|
-
tr:4) echo "
|
|
54
|
-
tr:5) echo "
|
|
55
|
-
tr:6) echo "Commit & PR" ;;
|
|
56
|
-
tr:7) echo "Rapor" ;;
|
|
52
|
+
tr:1) echo "Plan" ;;
|
|
53
|
+
tr:2) echo "Geliştirme" ;;
|
|
54
|
+
tr:3) echo "İnceleme" ;;
|
|
55
|
+
tr:4) echo "Commit & PR" ;;
|
|
56
|
+
tr:5) echo "Rapor" ;;
|
|
57
57
|
*) echo "" ;;
|
|
58
58
|
esac
|
|
59
59
|
}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
#
|
|
44
44
|
# Examples:
|
|
45
45
|
# phase-tracker.sh init "TASK-123"
|
|
46
|
-
# for p in 0:Init 1:
|
|
46
|
+
# for p in 0:Init 1:Plan 2:Dev 3:Review 4:Commit 5:Report; do
|
|
47
47
|
# phase-tracker.sh add "${p%%:*}" "${p#*:}"
|
|
48
48
|
# done
|
|
49
49
|
# phase-tracker.sh update 0 in_progress
|
|
@@ -141,7 +141,7 @@ need_jq() {
|
|
|
141
141
|
# Live usage ping (best-effort). Emits one per-phase update to the private
|
|
142
142
|
# dashboard via usage-report.mjs, always status=running so per-phase updates
|
|
143
143
|
# never fold the run into rollup counters - the terminal fold comes only from
|
|
144
|
-
# the Phase
|
|
144
|
+
# the Phase 5 / halt emit that reads the real run status. The emitter no-ops
|
|
145
145
|
# unless prefs.global.usageLog.enabled; detached so it never blocks a boundary.
|
|
146
146
|
usage_live_ping() {
|
|
147
147
|
# Smoke runs exercise this script's state handling, never the live dashboard -
|
|
@@ -461,7 +461,7 @@ save_state() {
|
|
|
461
461
|
|
|
462
462
|
# --- read-modify-write lock ---------------------------------------------------
|
|
463
463
|
# tmp+rename makes each save atomic, but two concurrent invocations (e.g. two
|
|
464
|
-
# parallel Phase
|
|
464
|
+
# parallel Phase 3 reviewers reporting `tokens`) both load the same state and
|
|
465
465
|
# the second save silently drops the first delta. Guard every load->save
|
|
466
466
|
# sequence with a portable mkdir spinlock (macOS bash 3.2: no flock builtin).
|
|
467
467
|
# The wait is bounded and the lock FAILS OPEN with a warning so a stuck lock
|
|
@@ -612,7 +612,7 @@ tracker_next_hint() {
|
|
|
612
612
|
# Not every session carries the task tools: Claude Code provides them by
|
|
613
613
|
# default only up to Opus 4.7 / Sonnet 4.6, a default that landed in
|
|
614
614
|
# v2.1.268. Naming the fallback on the same line is what keeps a newer model
|
|
615
|
-
# from advancing
|
|
615
|
+
# from advancing six phases in silence.
|
|
616
616
|
# `subjects` now carries Phase 2's plan steps as indented rows, and
|
|
617
617
|
# update_plan takes the whole list anyway, so re-reading it is what puts
|
|
618
618
|
# those steps on the Codex plan without a second mechanism. Codex has no
|
|
@@ -643,7 +643,7 @@ format_span() {
|
|
|
643
643
|
}
|
|
644
644
|
|
|
645
645
|
# The end-of-run report: what the pipeline spent, phase by phase, and what it
|
|
646
|
-
# has to say about phases it could not price. Printed by Phase
|
|
646
|
+
# has to say about phases it could not price. Printed by Phase 5 next to the
|
|
647
647
|
# work summary, which covers what actually changed on disk.
|
|
648
648
|
report() {
|
|
649
649
|
need_jq
|
|
@@ -800,7 +800,7 @@ subjects() {
|
|
|
800
800
|
#
|
|
801
801
|
# Creation order is the ONLY ordering the native widget has - it renders by the
|
|
802
802
|
# order tiles were made, not by any id inside them - so a plan that arrives at
|
|
803
|
-
# Phase 2 cannot simply be appended: its rows would land after Phase
|
|
803
|
+
# Phase 2 cannot simply be appended: its rows would land after Phase 5. The
|
|
804
804
|
# answer is a rebuild at that one boundary, which is the same thing `:resume`
|
|
805
805
|
# already does for a different reason.
|
|
806
806
|
tiles_script() {
|
|
@@ -811,7 +811,7 @@ tiles_script() {
|
|
|
811
811
|
has_subs=$(echo "$state" | jq '[.phases[]?.subs[]?] | length')
|
|
812
812
|
|
|
813
813
|
# A list carrying sub-steps has to be rebuilt whole, so the rebuild wins over a
|
|
814
|
-
# narrowed batch: appending to it would land the new rows after Phase
|
|
814
|
+
# narrowed batch: appending to it would land the new rows after Phase 5.
|
|
815
815
|
[ "${has_subs:-0}" -gt 0 ] && new_only=""
|
|
816
816
|
|
|
817
817
|
if [ -n "$new_only" ]; then
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Phase 4 answers "is what changed correct" and Step 1.45 answers "did every
|
|
5
5
|
// planned TEST land". Nothing answered "did every planned TASK land". The
|
|
6
6
|
// criteria manifest's denominator is rule IDs, not plan steps, and the only
|
|
7
|
-
// place a step's status surfaced was render-work-summary.sh at Phase
|
|
7
|
+
// place a step's status surfaced was render-work-summary.sh at Phase 5 - a
|
|
8
8
|
// report, printed after the commit. So a plan with seven steps could ship five
|
|
9
9
|
// and read as done.
|
|
10
10
|
//
|
|
@@ -116,7 +116,7 @@ if (isMain) {
|
|
|
116
116
|
"",
|
|
117
117
|
"Fails when a plan step never reached a terminal status, when a skip or",
|
|
118
118
|
"failure carries no reason, or when an analysis Section 14 `Add new` file",
|
|
119
|
-
"is missing from the tree. Run before Phase
|
|
119
|
+
"is missing from the tree. Run before Phase 4 commit.",
|
|
120
120
|
"",
|
|
121
121
|
].join("\n"),
|
|
122
122
|
);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#
|
|
8
8
|
# This is the agent-log counterpart to render-cost-summary.sh (which
|
|
9
9
|
# targets PR/Jira channel bodies). The agent-log version is rendered
|
|
10
|
-
# unconditionally on every Phase
|
|
10
|
+
# unconditionally on every Phase 5 run; the channels version is opt-in
|
|
11
11
|
# via prefs.global.reportContent.costSummary.
|
|
12
12
|
#
|
|
13
13
|
# Usage:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# render-work-summary.sh - v7.1.0
|
|
3
3
|
#
|
|
4
4
|
# Reads agent-state.json + phase-tracker.json + git diff, emits a concise
|
|
5
|
-
# "### Work Summary" markdown block for Phase
|
|
5
|
+
# "### Work Summary" markdown block for Phase 5 channels dispatch. Intended
|
|
6
6
|
# as an executive-summary companion to the existing Normal Analysis /
|
|
7
7
|
# Technical Details / Test Scenarios sections - gives Jira/Confluence
|
|
8
8
|
# readers and PR reviewers a single-screen answer to "what actually
|
|
@@ -85,7 +85,7 @@ if [ -n "$WORKTREE" ]; then
|
|
|
85
85
|
[ -f "$WORKTREE/triage-output.json" ] && TRIAGE_FILE="$WORKTREE/triage-output.json"
|
|
86
86
|
fi
|
|
87
87
|
|
|
88
|
-
# Fall back to the salvaged artefacts when the worktree is gone. Phase
|
|
88
|
+
# Fall back to the salvaged artefacts when the worktree is gone. Phase 4 removes it
|
|
89
89
|
# once the PR is open (worktree-finalize), and this script used to resolve state
|
|
90
90
|
# ONLY from the worktree - so it exited 2 and the whole Work Summary silently
|
|
91
91
|
# disappeared from the PR body and the Jira comment. render-agent-log-cost.sh has
|
|
@@ -203,7 +203,7 @@ total_add=0; total_del=0
|
|
|
203
203
|
# repository check. Testing -d "$WORKTREE/.git" would be wrong regardless: in a
|
|
204
204
|
# linked worktree .git is a file, not a directory.
|
|
205
205
|
# Prefer the worktree; fall back to the project root with the branch by name. A
|
|
206
|
-
# finalized task (Phase
|
|
206
|
+
# finalized task (Phase 4 removed the worktree after the PR) has no worktree but
|
|
207
207
|
# the branch is still local, so without this the Changed-files section vanished
|
|
208
208
|
# from the PR body and the Jira comment even though the data was right there.
|
|
209
209
|
DIFF_IN=""; DIFF_TIP=""
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @file review-file-filter.mjs - decide what the reviewers are asked to read.
|
|
5
5
|
*
|
|
6
6
|
* Phase 4 has a size cap and no exclusion list. When the diff exceeds the
|
|
7
|
-
* budget the cap truncates the LARGEST files first (`phase-
|
|
7
|
+
* budget the cap truncates the LARGEST files first (`phase-3-review.md`, Step
|
|
8
8
|
* 1.9), so a regenerated lockfile or a snapshot dump does not merely waste
|
|
9
9
|
* tokens - it is the thing that survives while real code is cut. The cheapest
|
|
10
10
|
* fix is to decide what is worth reading before the cap decides what fits.
|
|
@@ -39,6 +39,7 @@ import { join, dirname } from "node:path";
|
|
|
39
39
|
import { fileURLToPath } from "node:url";
|
|
40
40
|
import { costUsd } from "./_cost.mjs";
|
|
41
41
|
import { resolveRunFile, canonicalRunDir } from "./_run-paths.mjs";
|
|
42
|
+
import { toCurrentPhase, CURRENT_SCHEMA } from "../lib/phase-schema.mjs";
|
|
42
43
|
|
|
43
44
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
44
45
|
|
|
@@ -157,16 +158,22 @@ function computeCost(modelKey, tokensIn, tokensOut, costTable) {
|
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
/**
|
|
160
|
-
* Heuristic:
|
|
161
|
-
* Sonnet by default unless the run is a Short pipeline (Opus)
|
|
162
|
-
* is
|
|
161
|
+
* Heuristic: Plan (1) uses Opus per personas + dev-mode docs; Dev (2) uses
|
|
162
|
+
* Sonnet by default unless the run is a Short pipeline (Opus); Review (3)
|
|
163
|
+
* triage is Opus and the reviewer breakdown comes from spans.
|
|
163
164
|
*
|
|
164
165
|
* This is a fallback when phase-tracker doesn't record the model used. Live
|
|
165
166
|
* runs that emit OTel spans get per-call model attribution from the spans.
|
|
167
|
+
*
|
|
168
|
+
* The phase number is normalised first. The old body compared against the
|
|
169
|
+
* literals "1", "2" and "4", which under the six-phase contract are Plan, Dev
|
|
170
|
+
* and Commit - so a pre-v19 row and a post-v19 row would have been priced
|
|
171
|
+
* against different phases with no error anywhere.
|
|
166
172
|
*/
|
|
167
|
-
function inferModelForPhase(phaseId) {
|
|
168
|
-
|
|
169
|
-
if (
|
|
173
|
+
function inferModelForPhase(phaseId, schema = CURRENT_SCHEMA) {
|
|
174
|
+
const p = toCurrentPhase(phaseId, schema);
|
|
175
|
+
if (p === 1) return "opus";
|
|
176
|
+
if (p === 3) return "opus";
|
|
170
177
|
return "sonnet";
|
|
171
178
|
}
|
|
172
179
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* consensusVerdict - unanimous-* / split / unverified
|
|
25
25
|
* buildPassed - per-repo build outcome
|
|
26
26
|
* diff.filesTouched / locAdded / - size of the change, from state.diffRisk
|
|
27
|
-
* locRemoved / maxScore (Phase
|
|
27
|
+
* locRemoved / maxScore (Phase 3 Step 1.75); null when the
|
|
28
28
|
* run predates the persisted totals
|
|
29
29
|
* reviewDelta.stillPresentFinal / - cross-round classification of the
|
|
30
30
|
* resolvedTotal / tripped last iteration (state.reviewIterations[].delta)
|
|
@@ -42,6 +42,16 @@ import { listRuns, logsRoot, resolveRunDir, taskIdVariants } from "./_run-paths.
|
|
|
42
42
|
import { runMain } from "../lib/fatal.mjs";
|
|
43
43
|
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The phase from which a run counts as "waiting on you", read from the phase
|
|
47
|
+
* contract rather than written here. This threshold moved once already (it was
|
|
48
|
+
* 6 under the eight-phase contract, it is 4 under six) and nothing connected it
|
|
49
|
+
* to the renumbering, so it would have silently regrouped every run.
|
|
50
|
+
*/
|
|
51
|
+
const PHASE_WAITING_FROM = JSON.parse(
|
|
52
|
+
readFileSync(new URL("../schemas/phases.json", import.meta.url), "utf8"),
|
|
53
|
+
).thresholds.waitingFromPhase;
|
|
54
|
+
|
|
45
55
|
const GROUPS = {
|
|
46
56
|
waiting: "Waiting on you",
|
|
47
57
|
stopped: "Stopped mid-development",
|
|
@@ -166,7 +176,7 @@ function groupOf(state) {
|
|
|
166
176
|
if (status === "awaiting_input" || status === "awaiting-user-test-main-checkout")
|
|
167
177
|
return "waiting";
|
|
168
178
|
if (prUrl) return "waiting";
|
|
169
|
-
if (Number.isFinite(phase) && phase >=
|
|
179
|
+
if (Number.isFinite(phase) && phase >= PHASE_WAITING_FROM) return "waiting";
|
|
170
180
|
if (Number.isFinite(phase) && phase === 0) return "question";
|
|
171
181
|
return "stopped";
|
|
172
182
|
}
|
|
@@ -204,21 +204,21 @@ echo "→ reviewer-count contract (Claude=3, Copilot=3, Codex=3)"
|
|
|
204
204
|
# a broken installation. _smoke-root.sh handles both layouts.
|
|
205
205
|
# shellcheck source=pipeline/scripts/_smoke-root.sh
|
|
206
206
|
. "$(dirname "${BASH_SOURCE[0]}")/_smoke-root.sh"
|
|
207
|
-
P4="${MA_REFS:+$MA_REFS/phases/phase-
|
|
207
|
+
P4="${MA_REFS:+$MA_REFS/phases/phase-3-review.md}"
|
|
208
208
|
REVSCHEMA="${MA_SCHEMAS:+$MA_SCHEMAS/reviewer-output.schema.json}"
|
|
209
209
|
TRSCHEMA="${MA_SCHEMAS:+$MA_SCHEMAS/triage-output.schema.json}"
|
|
210
210
|
|
|
211
211
|
if [ -z "$P4" ] || [ ! -f "$P4" ]; then
|
|
212
|
-
echo " ↷ SKIP: phase-
|
|
212
|
+
echo " ↷ SKIP: phase-3-review.md not present in this $MA_LAYOUT layout"
|
|
213
213
|
# Two independent statements, because they can drift apart: the count sentence is
|
|
214
214
|
# the contract, and the matrix is what a reader dispatches from. Three regexes over
|
|
215
215
|
# overlapping prose used to stand in for this and let the count sentence 300 lines
|
|
216
216
|
# further down go stale for a whole release without failing.
|
|
217
217
|
elif grep -qF "Claude Code 3, Copilot CLI 3, Codex CLI 3" "$P4" \
|
|
218
218
|
&& grep -qE '^\| Reviewer 3 .*\|.*\|.*\|.*\|' "$P4"; then
|
|
219
|
-
pass "phase-
|
|
219
|
+
pass "phase-3-review declares Claude=3 / Copilot=3 / Codex=3 reviewers, and the matrix has all three host columns"
|
|
220
220
|
else
|
|
221
|
-
fail "phase-
|
|
221
|
+
fail "phase-3-review does not declare the CLI-aware reviewer count for all three hosts"
|
|
222
222
|
fi
|
|
223
223
|
|
|
224
224
|
# The two Codex constraints are silent-failure shaped, so the contract has to name
|
|
@@ -226,9 +226,9 @@ fi
|
|
|
226
226
|
# 4-slot ceiling (orchestrator included) is why the count is 3 and not more.
|
|
227
227
|
if [ -n "$P4" ] && [ -f "$P4" ]; then
|
|
228
228
|
if grep -q 'fork_turns' "$P4" && grep -qiE "concurrency|slots" "$P4"; then
|
|
229
|
-
pass "phase-
|
|
229
|
+
pass "phase-3-review documents the fork_turns override rule + the concurrency ceiling"
|
|
230
230
|
else
|
|
231
|
-
fail "phase-
|
|
231
|
+
fail "phase-3-review must document fork_turns and the Codex concurrency ceiling"
|
|
232
232
|
fi
|
|
233
233
|
fi
|
|
234
234
|
|
|
@@ -24,6 +24,26 @@ TEMPLATE="$SMOKE_DIR/../preferences-template.json"
|
|
|
24
24
|
[ -f "$TEMPLATE" ] || TEMPLATE="$HOME/multi-agent-pipeline/pipeline/preferences-template.json"
|
|
25
25
|
LIVE_PREFS="$HOME/.claude/multi-agent-preferences.json"
|
|
26
26
|
|
|
27
|
+
# The migration target, derived the way migrate-prefs.mjs derives it: the last
|
|
28
|
+
# entry of the schema's schemaVersion enum, read from the schema that sits
|
|
29
|
+
# beside the migrator being checked. It used to be grepped as a
|
|
30
|
+
# `TARGET_VERSION = "x.y.z"` literal out of the migrator, and when that literal
|
|
31
|
+
# was replaced by the schema read - precisely because a literal had drifted a
|
|
32
|
+
# minor behind - the grep started matching nothing and both checks that depend
|
|
33
|
+
# on it reported "no reference point". A gate that reads the source of truth
|
|
34
|
+
# cannot go stale against it; a gate that reads a transcription of it can.
|
|
35
|
+
migration_target() {
|
|
36
|
+
local schema="$1/../schemas/prefs.schema.json"
|
|
37
|
+
[ -f "$schema" ] || schema="$PREFS_SCHEMA"
|
|
38
|
+
[ -f "$schema" ] || return 1
|
|
39
|
+
node -e "
|
|
40
|
+
const sv = JSON.parse(require('fs').readFileSync('$schema','utf8'))?.properties?.schemaVersion;
|
|
41
|
+
const v = sv?.const ?? sv?.enum?.at(-1);
|
|
42
|
+
if (!v) process.exit(1);
|
|
43
|
+
process.stdout.write(v);
|
|
44
|
+
" 2>/dev/null
|
|
45
|
+
}
|
|
46
|
+
|
|
27
47
|
# ──────────────────────────────────────────────────────────────────────────
|
|
28
48
|
echo "→ 1. Schema files parse as JSON"
|
|
29
49
|
for f in "$PREFS_SCHEMA" "$STATE_SCHEMA"; do
|
|
@@ -145,10 +165,9 @@ if [ -f "$TEMPLATE" ]; then
|
|
|
145
165
|
# every old entry in the migrator's accepted set became load-bearing purely to
|
|
146
166
|
# rescue the template this gate was holding back. A template behind the target
|
|
147
167
|
# is a defect, not the expected shape.
|
|
148
|
-
TEMPLATE_TARGET=$(
|
|
149
|
-
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
|
|
168
|
+
TEMPLATE_TARGET=$(migration_target "$SMOKE_DIR")
|
|
150
169
|
if [ -z "$TEMPLATE_TARGET" ]; then
|
|
151
|
-
fail "cannot
|
|
170
|
+
fail "cannot derive the migration target from prefs.schema.json - the check has no reference point"
|
|
152
171
|
elif [ "$TVER" = "$TEMPLATE_TARGET" ]; then
|
|
153
172
|
pass "template schemaVersion: $TVER (at the migration target)"
|
|
154
173
|
else
|
|
@@ -201,17 +220,17 @@ if [ -f "$LIVE_PREFS" ]; then
|
|
|
201
220
|
# correctly migrated to 2.4.0 hit the else arm and FAILED as "unknown". The
|
|
202
221
|
# gate was rejecting the only fully-migrated state it exists to encourage.
|
|
203
222
|
#
|
|
204
|
-
# Reading the target
|
|
205
|
-
#
|
|
223
|
+
# Reading the target and the accepted set from the same schema enum the
|
|
224
|
+
# migrator reads means this can never disagree with it again.
|
|
206
225
|
MIGRATOR="$SMOKE_DIR/migrate-prefs.mjs"
|
|
207
|
-
TARGET=$(
|
|
226
|
+
TARGET=$(migration_target "$(dirname "$MIGRATOR")")
|
|
208
227
|
KNOWN=$(node -e "
|
|
209
228
|
const s = require('$PREFS_SCHEMA');
|
|
210
229
|
process.stdout.write((s.properties.schemaVersion.enum || []).join(' '));
|
|
211
230
|
" 2>/dev/null)
|
|
212
231
|
|
|
213
232
|
if [ -z "$TARGET" ]; then
|
|
214
|
-
fail "cannot
|
|
233
|
+
fail "cannot derive the migration target from prefs.schema.json - the check has no reference point"
|
|
215
234
|
elif [ "$LVER" = "$TARGET" ]; then
|
|
216
235
|
pass "live prefs at the migration target (v$TARGET)"
|
|
217
236
|
elif [ "$LVER" = "none" ]; then
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import os from "node:os";
|
|
23
23
|
import path from "node:path";
|
|
24
|
+
import { rowPhase } from "../lib/phase-schema.mjs";
|
|
24
25
|
|
|
25
26
|
const args = parseArgs(process.argv.slice(2));
|
|
26
27
|
const METRICS =
|
|
@@ -64,7 +65,12 @@ for (const e of events) {
|
|
|
64
65
|
models: new Set(),
|
|
65
66
|
});
|
|
66
67
|
const t = byTask.get(e.task_id);
|
|
67
|
-
|
|
68
|
+
// Normalised to the current vocabulary before it goes in the set. This log
|
|
69
|
+
// is append-only across the v19.0.0 renumbering, so the raw field carries
|
|
70
|
+
// two different meanings and a set of raw values cannot be compared to
|
|
71
|
+
// anything.
|
|
72
|
+
const cp = rowPhase(e);
|
|
73
|
+
if (cp !== null) t.phases.add(cp);
|
|
68
74
|
const d = e.details || {};
|
|
69
75
|
if (typeof d.tokens_in === "number") t.tokens_in += d.tokens_in;
|
|
70
76
|
if (typeof d.tokens_out === "number") t.tokens_out += d.tokens_out;
|
|
@@ -113,7 +119,12 @@ for (const [taskId, t] of byTask) {
|
|
|
113
119
|
summary.totalTokensOut += t.tokens_out;
|
|
114
120
|
summary.totalUsd += usd;
|
|
115
121
|
const total = t.tokens_in + t.tokens_out;
|
|
116
|
-
|
|
122
|
+
// Heuristic: a task that reached Review with many premium calls is a
|
|
123
|
+
// multi-repo run. Keyed on Review (3), not on the literal "4" this line used
|
|
124
|
+
// to carry - under the six-phase contract 4 is Commit, and every run reaches
|
|
125
|
+
// Commit, so the old literal would have classified nearly everything as
|
|
126
|
+
// multi-repo and applied the wrong ceiling.
|
|
127
|
+
const isMulti = t.phases.has(3) && t.premium_calls > 5;
|
|
117
128
|
const tokenLimit = isMulti ? limits.perTaskTokensMultiRepo : limits.perTaskTokens;
|
|
118
129
|
const usdLimit = isMulti ? limits.perTaskUsdMultiRepo : limits.perTaskUsd;
|
|
119
130
|
if (total > tokenLimit)
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file triage-memory.mjs - v8.3.0
|
|
5
5
|
*
|
|
6
|
-
* Lightweight, zero-dep persistence layer for past Phase
|
|
7
|
-
* Used by Phase
|
|
6
|
+
* Lightweight, zero-dep persistence layer for past Phase 3 triage findings.
|
|
7
|
+
* Used by Phase 5 to ingest results, by Phase 1/4 to look up prior art when
|
|
8
8
|
* a new task overlaps with a previous one, and by /multi-agent:search.
|
|
9
9
|
*
|
|
10
10
|
* Storage: append-only JSONL, one file per repo:
|