@smartmemory/compose 0.2.6-beta → 0.2.8-beta
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/bin/compose.js +45 -3
- package/bin/git-hooks/pre-push.template +41 -13
- package/contracts/gsd-stuck.json +141 -0
- package/dist/assets/{App-j8fWZcGr.js → App-D3ehVPvi.js} +4 -4
- package/dist/assets/{arc-BFqOo_jJ.js → arc-Dmf69iHG.js} +1 -1
- package/dist/assets/{architectureDiagram-3BPJPVTR-D722w0RE.js → architectureDiagram-3BPJPVTR-xYo993Yw.js} +1 -1
- package/dist/assets/{blockDiagram-GPEHLZMM-B4w0mOAJ.js → blockDiagram-GPEHLZMM-UX4EF98O.js} +1 -1
- package/dist/assets/{c4Diagram-AAUBKEIU-D6LE8-j8.js → c4Diagram-AAUBKEIU-DaP9CGWb.js} +1 -1
- package/dist/assets/channel-D_RXsFFT.js +1 -0
- package/dist/assets/{chunk-2J33WTMH-CrazA7xu.js → chunk-2J33WTMH-CKk_RN3A.js} +1 -1
- package/dist/assets/{chunk-4BX2VUAB-Cp90GiCM.js → chunk-4BX2VUAB-DboAwYKw.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-Bnais1SK.js → chunk-55IACEB6-Dsy9RYvI.js} +1 -1
- package/dist/assets/{chunk-727SXJPM-kD07Sqp5.js → chunk-727SXJPM-fAH0QO9v.js} +1 -1
- package/dist/assets/{chunk-AQP2D5EJ-DmIxhJc8.js → chunk-AQP2D5EJ-DyZYerFP.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-Jti_und8.js → chunk-FMBD7UC4-BnboGO5t.js} +1 -1
- package/dist/assets/{chunk-ND2GUHAM-Ipx3noKz.js → chunk-ND2GUHAM-Di9tYXme.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-CeblRnPF.js → chunk-QZHKN3VN-zRPRlAIL.js} +1 -1
- package/dist/assets/classDiagram-4FO5ZUOK-K6wdB4ic.js +1 -0
- package/dist/assets/classDiagram-v2-Q7XG4LA2-K6wdB4ic.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-fNQlSmHt.js → cose-bilkent-S5V4N54A-C7Hqukaf.js} +1 -1
- package/dist/assets/{dagre-BM42HDAG-D27D6YAL.js → dagre-BM42HDAG-B-cR-BjI.js} +1 -1
- package/dist/assets/{diagram-2AECGRRQ-CtXeohzN.js → diagram-2AECGRRQ-B6-5onDk.js} +1 -1
- package/dist/assets/{diagram-5GNKFQAL-C_BqZkx0.js → diagram-5GNKFQAL-DoZZgFAM.js} +1 -1
- package/dist/assets/{diagram-KO2AKTUF-B29ynQz4.js → diagram-KO2AKTUF-77jEGlJh.js} +1 -1
- package/dist/assets/{diagram-LMA3HP47-DAYJMc2I.js → diagram-LMA3HP47-D3S7XDRD.js} +1 -1
- package/dist/assets/{diagram-OG6HWLK6-CBJMis3l.js → diagram-OG6HWLK6-KbYL9aCY.js} +1 -1
- package/dist/assets/{erDiagram-TEJ5UH35-nd3GWiPn.js → erDiagram-TEJ5UH35-DezFbJP-.js} +1 -1
- package/dist/assets/{flowDiagram-I6XJVG4X-HFUno_nV.js → flowDiagram-I6XJVG4X-4x31cK9j.js} +1 -1
- package/dist/assets/{ganttDiagram-6RSMTGT7-CPPAAjwR.js → ganttDiagram-6RSMTGT7-FopfSTyZ.js} +1 -1
- package/dist/assets/{gitGraphDiagram-PVQCEYII-NBq1F6K2.js → gitGraphDiagram-PVQCEYII-DSiQGKbN.js} +1 -1
- package/dist/assets/graph-Cs_vqCR0.js +331 -0
- package/dist/assets/{index-uHKnp74B.js → index-ClX6LVAf.js} +2 -2
- package/dist/assets/{infoDiagram-5YYISTIA-D-TOBtCq.js → infoDiagram-5YYISTIA-DE6BqzK_.js} +1 -1
- package/dist/assets/{ishikawaDiagram-YF4QCWOH-nXOztZiZ.js → ishikawaDiagram-YF4QCWOH-Dml8NwQI.js} +1 -1
- package/dist/assets/{journeyDiagram-JHISSGLW-Bko3tTdh.js → journeyDiagram-JHISSGLW-CwWeJgjE.js} +1 -1
- package/dist/assets/{kanban-definition-UN3LZRKU-1e-7i8st.js → kanban-definition-UN3LZRKU-DnG956Wh.js} +1 -1
- package/dist/assets/{linear-Dx5ZJB7F.js → linear-CA3N7Rpi.js} +1 -1
- package/dist/assets/{mindmap-definition-RKZ34NQL-CNwNkDqN.js → mindmap-definition-RKZ34NQL-CxfIOjLX.js} +1 -1
- package/dist/assets/{pieDiagram-4H26LBE5-C5fvCej-.js → pieDiagram-4H26LBE5-O7aIwy1x.js} +1 -1
- package/dist/assets/{quadrantDiagram-W4KKPZXB-4NoQsF61.js → quadrantDiagram-W4KKPZXB-CPQ2qq7c.js} +1 -1
- package/dist/assets/{requirementDiagram-4Y6WPE33-q5WxB9LO.js → requirementDiagram-4Y6WPE33-C23horL4.js} +1 -1
- package/dist/assets/{sankeyDiagram-5OEKKPKP-DlQNB367.js → sankeyDiagram-5OEKKPKP-DPY04kOW.js} +1 -1
- package/dist/assets/{sequenceDiagram-3UESZ5HK-BzHclOKt.js → sequenceDiagram-3UESZ5HK-BKaTfIvo.js} +1 -1
- package/dist/assets/{stateDiagram-AJRCARHV-BvWRI9zK.js → stateDiagram-AJRCARHV-B9na_6mY.js} +1 -1
- package/dist/assets/stateDiagram-v2-BHNVJYJU-Cf84VDiH.js +1 -0
- package/dist/assets/{timeline-definition-PNZ67QCA-j2wKjAti.js → timeline-definition-PNZ67QCA-BBWPqd7X.js} +1 -1
- package/dist/assets/{vennDiagram-CIIHVFJN-B77g7htC.js → vennDiagram-CIIHVFJN-tWqiHsOZ.js} +1 -1
- package/dist/assets/{wardley-L42UT6IY-83Im2mo2.js → wardley-L42UT6IY-DorxG6os.js} +1 -1
- package/dist/assets/{wardleyDiagram-YWT4CUSO-CK-XB-bO.js → wardleyDiagram-YWT4CUSO-B49f8GzW.js} +1 -1
- package/dist/assets/{xychartDiagram-2RQKCTM6-D42FcVOY.js → xychartDiagram-2RQKCTM6-BgKSj8Qb.js} +1 -1
- package/dist/index.html +1 -1
- package/lib/budget-ledger.js +84 -0
- package/lib/build-stream-schema.js +5 -3
- package/lib/build.js +91 -2
- package/lib/feature-validator.js +40 -8
- package/lib/gsd-budget.js +205 -0
- package/lib/gsd-stuck.js +275 -0
- package/lib/gsd.js +499 -8
- package/lib/result-normalizer.js +5 -1
- package/package.json +2 -2
- package/server/agent-spawn.js +7 -1
- package/server/compose-mcp-tools.js +103 -1
- package/server/compose-mcp.js +34 -4
- package/server/design-routes.js +4 -1
- package/server/mcp-tool-policy.js +112 -0
- package/dist/assets/channel-BD-5_hPW.js +0 -1
- package/dist/assets/classDiagram-4FO5ZUOK-mSW5R7DY.js +0 -1
- package/dist/assets/classDiagram-v2-Q7XG4LA2-mSW5R7DY.js +0 -1
- package/dist/assets/graph-CJVNlri5.js +0 -331
- package/dist/assets/stateDiagram-v2-BHNVJYJU-CDlF0VA8.js +0 -1
package/bin/compose.js
CHANGED
|
@@ -1654,6 +1654,13 @@ Exit codes:
|
|
|
1654
1654
|
else if (a === '--code') code = args[++i]
|
|
1655
1655
|
else if (a.startsWith('--block-on=')) blockOn = a.slice('--block-on='.length)
|
|
1656
1656
|
else if (a === '--block-on') blockOn = args[++i]
|
|
1657
|
+
else if (a === '--workspace' || a.startsWith('--workspace=')) {
|
|
1658
|
+
// --workspace is a valid global flag consumed by resolveCwdWithWorkspace(args)
|
|
1659
|
+
// below; skip it here so the unknown-flag guard doesn't reject it. Don't
|
|
1660
|
+
// consume the next token: a bare `--workspace <id>` leaves <id> as a
|
|
1661
|
+
// positional (harmlessly ignored by this loop, parsed by resolveCwdWith-
|
|
1662
|
+
// Workspace), so `--workspace --help` still resolves --help correctly.
|
|
1663
|
+
}
|
|
1657
1664
|
else if (a.startsWith('--')) {
|
|
1658
1665
|
console.error(`Unknown flag: ${a}`)
|
|
1659
1666
|
process.exit(2)
|
|
@@ -1962,14 +1969,22 @@ if (cmd === 'build') {
|
|
|
1962
1969
|
// pipeline (pipelines/gsd.stratum.yaml). Hard-requires existing
|
|
1963
1970
|
// docs/features/<code>/blueprint.md with a parseable Boundary Map.
|
|
1964
1971
|
const gsdCode = args.find(a => !a.startsWith('-'))
|
|
1972
|
+
const gsdResume = args.includes('--resume')
|
|
1973
|
+
const gsdResetBudget = args.includes('--reset-budget')
|
|
1965
1974
|
if (!gsdCode) {
|
|
1966
|
-
console.error('Usage: compose gsd <feature-code>')
|
|
1975
|
+
console.error('Usage: compose gsd <feature-code> [--resume] [--reset-budget]')
|
|
1967
1976
|
console.error('')
|
|
1968
1977
|
console.error('Runs the per-task fresh-context dispatch pipeline (COMP-GSD-2).')
|
|
1969
1978
|
console.error('Hard-requires docs/features/<code>/blueprint.md with a valid Boundary Map.')
|
|
1979
|
+
console.error('Detects stuck tasks (COMP-GSD-5) and halts with a structured diagnostic.')
|
|
1980
|
+
console.error('Enforces budget ceilings (COMP-GSD-4) from .compose/compose.json gsd.budget.*')
|
|
1970
1981
|
console.error('')
|
|
1971
1982
|
console.error('Options:')
|
|
1972
|
-
console.error(' --
|
|
1983
|
+
console.error(' --resume Resume a halted run: re-dispatch the unfinished tasks')
|
|
1984
|
+
console.error(' from .compose/gsd/<code>/pause.json (skips completed tasks).')
|
|
1985
|
+
console.error(' --reset-budget Clear the feature\'s cumulative budget ledger before running')
|
|
1986
|
+
console.error(' (use after raising or removing a spent gsd.budget.cumulative cap).')
|
|
1987
|
+
console.error(' --cwd <path> Working directory (defaults to current)')
|
|
1973
1988
|
process.exit(1)
|
|
1974
1989
|
}
|
|
1975
1990
|
const { root: gsdCwd } = resolveCwdWithWorkspace(args)
|
|
@@ -1977,7 +1992,34 @@ if (cmd === 'build') {
|
|
|
1977
1992
|
const gsdAgentCwd = cwdIdx !== -1 ? resolve(args[cwdIdx + 1]) : gsdCwd
|
|
1978
1993
|
const { runGsd } = await import('../lib/gsd.js')
|
|
1979
1994
|
try {
|
|
1980
|
-
|
|
1995
|
+
if (gsdResetBudget) {
|
|
1996
|
+
// COMP-GSD-4: clear the cumulative ledger so a spent ceiling no longer
|
|
1997
|
+
// refuses the run. Runs before dispatch; per-run windows reset anyway.
|
|
1998
|
+
const { resetGsdUsage } = await import('../lib/budget-ledger.js')
|
|
1999
|
+
resetGsdUsage(resolve(gsdAgentCwd, '.compose'), gsdCode)
|
|
2000
|
+
console.log(`gsd: cleared cumulative budget ledger for ${gsdCode}.`)
|
|
2001
|
+
}
|
|
2002
|
+
const result = await runGsd(gsdCode, { cwd: gsdAgentCwd, resume: gsdResume })
|
|
2003
|
+
if (result.status === 'stuck') {
|
|
2004
|
+
// COMP-GSD-5: a stuck halt is a clean, recoverable stop — not a crash.
|
|
2005
|
+
console.error(`gsd stuck: task ${result.stuckTaskId} tripped the ${result.signal} detector.`)
|
|
2006
|
+
console.error(`Diagnostic: .compose/gsd/${gsdCode}/stuck.md`)
|
|
2007
|
+
console.error(`Resume with: compose gsd ${gsdCode} --resume`)
|
|
2008
|
+
process.exit(2)
|
|
2009
|
+
}
|
|
2010
|
+
if (result.status === 'budget') {
|
|
2011
|
+
// COMP-GSD-4: a budget halt is a clean, recoverable stop — not a crash.
|
|
2012
|
+
if (result.axis === 'cumulative') {
|
|
2013
|
+
console.error(`gsd budget: cumulative ceiling for ${gsdCode} is already spent.`)
|
|
2014
|
+
console.error(`Diagnostic: .compose/gsd/${gsdCode}/budget.md`)
|
|
2015
|
+
console.error(`Raise gsd.budget.cumulative.* or clear it: compose gsd ${gsdCode} --reset-budget`)
|
|
2016
|
+
} else {
|
|
2017
|
+
console.error(`gsd budget: the ${result.axis} ceiling tripped mid-run.`)
|
|
2018
|
+
console.error(`Diagnostic: .compose/gsd/${gsdCode}/budget.md`)
|
|
2019
|
+
console.error(`Raise gsd.budget.* and resume: compose gsd ${gsdCode} --resume`)
|
|
2020
|
+
}
|
|
2021
|
+
process.exit(2)
|
|
2022
|
+
}
|
|
1981
2023
|
console.log(`gsd complete: ${result.blackboardEntries} task results captured.`)
|
|
1982
2024
|
} catch (err) {
|
|
1983
2025
|
console.error(`gsd failed: ${err.message}`)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Compose pre-push hook —
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# Compose pre-push hook — blocks the push on a red `npm test` suite (HARD gate) and
|
|
3
|
+
# runs `compose validate` as an ADVISORY drift check (prints findings, does not
|
|
4
|
+
# block — re-enable strict drift-blocking once the repo's drift backlog is
|
|
5
|
+
# reconciled). Installed by `compose hooks install --pre-push`; placeholders
|
|
6
|
+
# below are substituted at install time.
|
|
5
7
|
#
|
|
6
8
|
# External-reference (xref) resolution is OFF here by default: github xref:
|
|
7
9
|
# citations / kind:"external" links emit XREF_RESOLUTION_SKIPPED (warning,
|
|
@@ -18,18 +20,44 @@ COMPOSE_WORKSPACE_ID="__COMPOSE_WORKSPACE_ID__"
|
|
|
18
20
|
LOG="${COMPOSE_HOOK_LOG:-.compose/data/pre-push.log}"
|
|
19
21
|
mkdir -p "$(dirname "$LOG")" 2>/dev/null || true
|
|
20
22
|
|
|
23
|
+
# Drift check (ADVISORY — COMP-RESUME follow-up): print findings for visibility,
|
|
24
|
+
# never block. The repo carries pre-existing error-severity drift (much from the
|
|
25
|
+
# COMP-MCP-ENFORCE lifecycle-as-truth projection); hard-blocking on it would make
|
|
26
|
+
# the whole hook unusable, so the TEST gate below is the hard blocker. Re-enable
|
|
27
|
+
# strict drift-blocking once the backlog is reconciled (tracked separately).
|
|
21
28
|
OUTPUT=$("$COMPOSE_NODE" "$COMPOSE_BIN" validate --scope=project --block-on=error --workspace="$COMPOSE_WORKSPACE_ID" 2>&1)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if [ "$
|
|
25
|
-
echo "$OUTPUT" | tee -a "$LOG" >&2
|
|
29
|
+
VALIDATE_EXIT=$?
|
|
30
|
+
echo "$OUTPUT"
|
|
31
|
+
if [ "$VALIDATE_EXIT" -ne 0 ]; then
|
|
26
32
|
echo "" >&2
|
|
27
|
-
echo "compose validate
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
echo "pre-push: compose validate reported drift (ADVISORY — not blocking). Review with \`compose validate\`." >&2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# ── Test gate (COMP-RESUME follow-up) ───────────────────────────────────────
|
|
37
|
+
# Block the push if the suite is red. This is the gate whose absence let a broken
|
|
38
|
+
# integration test (and a stale-schema consumer bug) reach main — nothing ran the
|
|
39
|
+
# suite before push. Heavy (full `npm test`) but authoritative. Auto-skips in a
|
|
40
|
+
# repo with no npm `test` script. Emergency bypass (sparingly): git push --no-verify
|
|
41
|
+
if [ -f package.json ]; then
|
|
42
|
+
# Probe scripts.test: exit 0 = present, 1 = definitively absent, anything else
|
|
43
|
+
# = could not read package.json. Skip ONLY on a definitive "absent" (1); on
|
|
44
|
+
# ambiguity run the suite anyway so a broken/unreadable package.json fails
|
|
45
|
+
# CLOSED (blocks), never open (silently skips the gate).
|
|
46
|
+
"$COMPOSE_NODE" -e "let s={};try{s=require(process.cwd()+'/package.json').scripts||{}}catch(e){process.exit(3)};process.exit(s.test?0:1)" 2>/dev/null
|
|
47
|
+
PROBE=$?
|
|
48
|
+
if [ "$PROBE" -ne 1 ]; then
|
|
49
|
+
echo "pre-push: running full test suite (npm test)…" >&2
|
|
50
|
+
PATH="$(dirname "$COMPOSE_NODE"):$PATH" npm test >> "$LOG" 2>&1
|
|
51
|
+
TEST_EXIT=$?
|
|
52
|
+
if [ "$TEST_EXIT" -ne 0 ]; then
|
|
53
|
+
tail -n 40 "$LOG" >&2
|
|
54
|
+
echo "" >&2
|
|
55
|
+
echo "npm test failed — push aborted (full log: $LOG)." >&2
|
|
56
|
+
echo "Bypass at your own risk: git push --no-verify" >&2
|
|
57
|
+
exit "$TEST_EXIT"
|
|
58
|
+
fi
|
|
59
|
+
echo "pre-push: test suite green." >&2
|
|
60
|
+
fi
|
|
31
61
|
fi
|
|
32
62
|
|
|
33
|
-
# Below-threshold findings (warnings/info) are still printed for visibility.
|
|
34
|
-
echo "$OUTPUT"
|
|
35
63
|
exit 0
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gsd-stuck.json",
|
|
4
|
+
"_source": "COMP-GSD-5",
|
|
5
|
+
"_also": "COMP-GSD-4",
|
|
6
|
+
"_roadmap": "COMP-GSD-5",
|
|
7
|
+
"title": "GsdStuckContracts",
|
|
8
|
+
"description": "Artifacts written when a `compose gsd` run halts. A STUCK halt (COMP-GSD-5) writes stuck.json/stuck.md; a BUDGET halt (COMP-GSD-4) writes budget.json/budget.md. Both persist `pause.json` (machine-readable resume state); `compose gsd <feature> --resume` reads it, validates ownership/mode, and re-dispatches decomposedTasks minus completedTaskIds (completed results already live in the blackboard). The pause `kind` field (optional; absent ⇒ 'stuck' for back-compat) discriminates: a 'stuck' pause carries the stuck-specific fields, a 'budget' pause carries the `budget` block. GSD-6 reuses the `pause` shape for automatic crash-recovery.",
|
|
9
|
+
"definitions": {
|
|
10
|
+
"stuck": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"title": "GsdStuckDiagnostic",
|
|
13
|
+
"description": "Structured diagnostic emitted on the first stuck verdict for a task.",
|
|
14
|
+
"required": ["feature", "taskId", "signal", "detail", "attemptCounts", "ts"],
|
|
15
|
+
"additionalProperties": false,
|
|
16
|
+
"properties": {
|
|
17
|
+
"feature": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Feature code the gsd run is building (e.g. COMP-GSD-5)."
|
|
20
|
+
},
|
|
21
|
+
"taskId": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "The decomposed task id that tripped the detector."
|
|
24
|
+
},
|
|
25
|
+
"signal": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"enum": ["same_file", "error_recurrence", "no_progress", "wall_clock"],
|
|
28
|
+
"description": "Which stuck pattern fired. same_file: one file edited >= sameFileEdits times. error_recurrence: a normalized error hash recurred >= errorRepeats. no_progress: >= noProgressCalls consecutive non-file-changing tool calls. wall_clock: task ran >= wallClockMs without finishing."
|
|
29
|
+
},
|
|
30
|
+
"detail": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "Human-readable explanation of the offending file / error / stall."
|
|
33
|
+
},
|
|
34
|
+
"attemptCounts": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"description": "Snapshot of the per-task counters at the moment of the verdict.",
|
|
37
|
+
"properties": {
|
|
38
|
+
"sameFileEdits": { "type": "integer", "minimum": 0, "description": "Max edit count across files for this task." },
|
|
39
|
+
"errorRepeats": { "type": "integer", "minimum": 0, "description": "Max repeat count across normalized error hashes." },
|
|
40
|
+
"noProgressCalls": { "type": "integer", "minimum": 0, "description": "Current consecutive non-file-changing tool-call count." }
|
|
41
|
+
},
|
|
42
|
+
"additionalProperties": true
|
|
43
|
+
},
|
|
44
|
+
"partialDiff": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "Optional unified diff of the stuck task's worktree at halt time, for triage."
|
|
47
|
+
},
|
|
48
|
+
"ts": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"format": "date-time",
|
|
51
|
+
"description": "ISO-8601 timestamp of the verdict."
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"pause": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"title": "GsdPauseState",
|
|
58
|
+
"description": "Resume state persisted on a stuck OR budget halt. Drives blackboard-driven re-dispatch on --resume — NOT mid-task re-entry. Base required fields are kind-agnostic; the `kind` field (optional; absent ⇒ stuck) selects which extra fields are required via the if/then/else at the end.",
|
|
59
|
+
"required": ["flowId", "stepId", "decomposedTasks", "completedTaskIds", "pid", "mode", "ts"],
|
|
60
|
+
"additionalProperties": false,
|
|
61
|
+
"properties": {
|
|
62
|
+
"kind": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"enum": ["stuck", "budget"],
|
|
65
|
+
"description": "Halt kind. Optional for back-compat: an absent kind is interpreted as 'stuck'. Determines which extra fields are required (see if/then/else)."
|
|
66
|
+
},
|
|
67
|
+
"budget": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"description": "Present on a budget halt (kind='budget'). The enforced axis that tripped + the stratum budget_state snapshot.",
|
|
70
|
+
"required": ["axis", "caps", "consumed"],
|
|
71
|
+
"additionalProperties": true,
|
|
72
|
+
"properties": {
|
|
73
|
+
"axis": {
|
|
74
|
+
"type": ["string", "null"],
|
|
75
|
+
"enum": ["ms", "max_agent_dispatches", "max_tokens", "usd", null],
|
|
76
|
+
"description": "Which enforced stratum axis reached its cap (null if indeterminate)."
|
|
77
|
+
},
|
|
78
|
+
"caps": { "type": "object", "description": "The flow budget caps {ms?,max_agent_dispatches?,max_tokens?,usd?}." },
|
|
79
|
+
"consumed": { "type": "object", "description": "Consumed totals {tokens,dispatches,wall_s,dollars}." }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"flowId": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "Stratum flow id of the halted run (informational; resume opens a fresh flow)."
|
|
85
|
+
},
|
|
86
|
+
"stepId": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"description": "The parallel_dispatch step id that was cancelled (e.g. execute)."
|
|
89
|
+
},
|
|
90
|
+
"stuckTaskId": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"description": "The task id that tripped the detector."
|
|
93
|
+
},
|
|
94
|
+
"signal": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"enum": ["same_file", "error_recurrence", "no_progress", "wall_clock"],
|
|
97
|
+
"description": "Which stuck pattern fired (mirrors stuck.signal)."
|
|
98
|
+
},
|
|
99
|
+
"detail": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"description": "Human-readable explanation (mirrors stuck.detail)."
|
|
102
|
+
},
|
|
103
|
+
"decomposedTasks": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"minItems": 1,
|
|
106
|
+
"description": "The full decomposed task list, persisted so --resume does NOT re-decompose (stable task ids).",
|
|
107
|
+
"items": { "type": "object" }
|
|
108
|
+
},
|
|
109
|
+
"completedTaskIds": {
|
|
110
|
+
"type": "array",
|
|
111
|
+
"description": "Task ids whose VALIDATED result is already in the blackboard. --resume skips these.",
|
|
112
|
+
"items": { "type": "string" }
|
|
113
|
+
},
|
|
114
|
+
"pid": {
|
|
115
|
+
"type": "integer",
|
|
116
|
+
"description": "OS pid of the process that wrote the pause file. --resume refuses if this pid is still alive (another owner)."
|
|
117
|
+
},
|
|
118
|
+
"mode": {
|
|
119
|
+
"type": "string",
|
|
120
|
+
"const": "gsd",
|
|
121
|
+
"description": "Run mode. --resume refuses if this is not 'gsd' (mirrors `compose fix --resume` mode guard)."
|
|
122
|
+
},
|
|
123
|
+
"ts": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"format": "date-time",
|
|
126
|
+
"description": "ISO-8601 timestamp the pause file was written."
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"if": {
|
|
130
|
+
"properties": { "kind": { "const": "budget" } },
|
|
131
|
+
"required": ["kind"]
|
|
132
|
+
},
|
|
133
|
+
"then": {
|
|
134
|
+
"required": ["budget"]
|
|
135
|
+
},
|
|
136
|
+
"else": {
|
|
137
|
+
"required": ["stuckTaskId", "signal", "detail"]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|