@tea-agent/loop-agent 0.25.6 → 0.26.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.
Files changed (162) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +1020 -1006
  3. package/bin/loop-agent.js +21 -21
  4. package/dist/commands/cursor-prompt.js +6 -6
  5. package/dist/commands/loop-benchmark.js +11 -11
  6. package/dist/commands/pi-reuse-benchmark.js +16 -16
  7. package/dist/executors/dag-pi-executor.js +26 -20
  8. package/dist/executors/model-routing.js +34 -18
  9. package/dist/governance/manifest-types.js +33 -5
  10. package/dist/sidecars/cursor-prompt/executor.js +1 -1
  11. package/dist/task/task-demand-routing.js +3 -1
  12. package/dist/worker/console/chat/model-resolver.js +15 -3
  13. package/dist/worker/observe/static/constants.js +3 -2
  14. package/dist/worker/observe/static/copy.js +67 -67
  15. package/dist/worker/observe/static/dag-layout.d.ts +31 -31
  16. package/dist/worker/observe/static/dag-layout.js +83 -83
  17. package/dist/worker/observe/static/dag-model.js +1 -0
  18. package/dist/worker/observe/static/dom.js +220 -220
  19. package/dist/worker/observe/static/relations.js +133 -133
  20. package/dist/worker/observe/static/router.js +93 -93
  21. package/dist/worker/observe/static/run-processing.js +148 -148
  22. package/dist/worker/observe/static/styles.css +182 -42
  23. package/dist/worker/observe/static/views/batch.js +227 -227
  24. package/dist/worker/observe/static/views/dag-graph.js +172 -172
  25. package/dist/worker/observe/static/views/failures.js +143 -143
  26. package/dist/worker/observe/static/views/feature.js +492 -492
  27. package/dist/worker/observe/static/views/run.js +453 -453
  28. package/dist/worker/observe/static/views/shell.js +7 -7
  29. package/dist/worker/observe/static/views/timeline.js +163 -163
  30. package/dist/workflows/dag/canvas-observer.js +275 -275
  31. package/dist/workflows/dag/lifecycle.js +40 -30
  32. package/dist/workflows/dag/node-execution.js +13 -0
  33. package/dist/workflows/dag/types.js +59 -19
  34. package/docs/skills/README.md +7 -7
  35. package/docs/templates/adr.md +60 -60
  36. package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
  37. package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
  38. package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
  39. package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
  40. package/docs/templates/agent-dag-report.schema.json +473 -473
  41. package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
  42. package/docs/templates/backend-test-result.schema.json +99 -99
  43. package/docs/templates/feature-spec.md +53 -53
  44. package/docs/templates/frontend-design-contract.md +42 -42
  45. package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -17
  46. package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -16
  47. package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -16
  48. package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -16
  49. package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -16
  50. package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -16
  51. package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -21
  52. package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -29
  53. package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -28
  54. package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -28
  55. package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -29
  56. package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -27
  57. package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -28
  58. package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -28
  59. package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -27
  60. package/docs/templates/frontend-eval/metrics.md +138 -138
  61. package/docs/templates/frontend-eval/smoke-targets.md +53 -53
  62. package/docs/templates/frontend-task-constraints.md +35 -35
  63. package/docs/templates/frontend-task-requirement.md +70 -70
  64. package/docs/templates/harness.schema.json +29 -7
  65. package/docs/templates/init-evolution-review.md +35 -35
  66. package/docs/templates/interactive-ui-round2-experiment.md +66 -66
  67. package/docs/templates/knowledge-graph-bootstrap-dag.json +118 -118
  68. package/docs/templates/knowledge-sync-dag.json +178 -178
  69. package/docs/templates/knowledge-sync-draft.schema.json +71 -71
  70. package/docs/templates/product-line/closeout.yaml +9 -9
  71. package/docs/templates/product-line/design.md +13 -13
  72. package/docs/templates/product-line/links.md +10 -10
  73. package/docs/templates/product-line/requirement.md +17 -17
  74. package/docs/templates/product-line/test-plan.md +7 -7
  75. package/docs/templates/production-readiness-checklist.md +57 -57
  76. package/docs/templates/project-start-checklist.md +9 -9
  77. package/docs/templates/qa-report.md +48 -48
  78. package/docs/templates/sprint-contract.md +29 -29
  79. package/docs/templates/worker-dogfood-evidence.md +80 -80
  80. package/docs/templates/worker-dogfood-setup.md +68 -68
  81. package/harness.json +1 -2
  82. package/package.json +1 -1
  83. package/scripts/kb-bootstrap-init-skeleton.sh +0 -0
  84. package/scripts/kb-graph-incremental-prepare.mjs +386 -386
  85. package/scripts/kb-graph-materialize.mjs +105 -105
  86. package/scripts/kb-graph-promote.mjs +164 -164
  87. package/scripts/kb-query.mjs +554 -554
  88. package/skills/ai-engineering-context/SKILL.md +48 -48
  89. package/skills/analyze-product-dependencies/SKILL.md +67 -67
  90. package/skills/analyze-product-dependencies/agents/openai.yaml +4 -4
  91. package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -30
  92. package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -28
  93. package/skills/analyze-product-dependencies/references/example.md +76 -76
  94. package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -35
  95. package/skills/analyze-product-dependencies/references/input-contract.md +11 -11
  96. package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -61
  97. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -267
  98. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -101
  99. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -142
  100. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -76
  101. package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -146
  102. package/skills/analyze-product-requirements/SKILL.md +90 -90
  103. package/skills/analyze-product-requirements/agents/openai.yaml +4 -4
  104. package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -91
  105. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -56
  106. package/skills/analyze-product-requirements/references/example.md +86 -86
  107. package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -66
  108. package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -32
  109. package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -33
  110. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -35
  111. package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -193
  112. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -69
  113. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -97
  114. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -98
  115. package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -156
  116. package/skills/browser-tools/browser-content.js +103 -103
  117. package/skills/browser-tools/browser-cookies.js +35 -35
  118. package/skills/browser-tools/browser-eval.js +53 -53
  119. package/skills/browser-tools/browser-hn-scraper.js +108 -108
  120. package/skills/browser-tools/browser-nav.js +44 -44
  121. package/skills/browser-tools/browser-pick.js +162 -162
  122. package/skills/browser-tools/browser-screenshot.js +34 -34
  123. package/skills/browser-tools/browser-start.js +86 -86
  124. package/skills/browser-tools/package-lock.json +2556 -2556
  125. package/skills/browser-tools/package.json +19 -19
  126. package/skills/code-review-core/SKILL.md +20 -20
  127. package/skills/codebase-scout/SKILL.md +19 -19
  128. package/skills/grill-me/SKILL.md +10 -10
  129. package/skills/loop-agent/references/README.md +67 -67
  130. package/skills/loop-agent/references/docs-converge.md +126 -126
  131. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  132. package/skills/loop-agent/references/learned/README.md +21 -21
  133. package/skills/loop-agent/references/long-running-loop.md +57 -57
  134. package/skills/loop-agent/references/model-routing.md +2 -0
  135. package/skills/loop-agent/references/one-shot-runs.md +85 -85
  136. package/skills/loop-agent/references/pi-prompt.md +23 -23
  137. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +84 -84
  138. package/skills/playwright-cli/SKILL.md +420 -420
  139. package/skills/playwright-cli/references/element-attributes.md +23 -23
  140. package/skills/playwright-cli/references/playwright-tests.md +39 -39
  141. package/skills/playwright-cli/references/request-mocking.md +87 -87
  142. package/skills/playwright-cli/references/running-code.md +241 -241
  143. package/skills/playwright-cli/references/session-management.md +225 -225
  144. package/skills/playwright-cli/references/storage-state.md +275 -275
  145. package/skills/playwright-cli/references/test-generation.md +433 -433
  146. package/skills/playwright-cli/references/tracing.md +139 -139
  147. package/skills/playwright-cli/references/video-recording.md +143 -143
  148. package/skills/requesting-code-review/SKILL.md +101 -101
  149. package/skills/requesting-code-review/code-reviewer.md +168 -168
  150. package/skills/systematic-debugging/CREATION-LOG.md +119 -119
  151. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
  152. package/skills/systematic-debugging/condition-based-waiting.md +115 -115
  153. package/skills/systematic-debugging/defense-in-depth.md +122 -122
  154. package/skills/systematic-debugging/find-polluter.sh +63 -63
  155. package/skills/systematic-debugging/root-cause-tracing.md +169 -169
  156. package/skills/systematic-debugging/test-academic.md +14 -14
  157. package/skills/systematic-debugging/test-pressure-1.md +58 -58
  158. package/skills/systematic-debugging/test-pressure-2.md +68 -68
  159. package/skills/systematic-debugging/test-pressure-3.md +69 -69
  160. package/skills/using-git-worktrees/SKILL.md +215 -215
  161. package/skills/verification-before-completion/SKILL.md +154 -154
  162. package/skills/webapp-testing/SKILL.md +19 -19
@@ -1,148 +1,148 @@
1
- /** Run step/command/artifact processing and task history rows. */
2
- import {
3
- STEP_LABELS,
4
- ARTIFACT_LABELS,
5
- STEP_ORDER,
6
- ARTIFACT_KEYS,
7
- } from "./constants.js";
8
- import { badge } from "./format.js";
9
- import { navigate } from "./router.js";
10
-
11
- export function stepDisplayLabel(label) {
12
- return STEP_LABELS[label] ?? label;
13
- }
14
-
15
- export function buildStepStates(events) {
16
- const states = new Map();
17
- for (const ev of events) {
18
- if (ev.type === "step.started") {
19
- states.set(ev.label, { status: "running", startedAt: ev.at });
20
- } else if (ev.type === "step.finished") {
21
- states.set(ev.label, {
22
- status: ev.status === "failed" ? "failed" : "succeeded",
23
- durationMs: ev.durationMs,
24
- });
25
- }
26
- }
27
-
28
- const ordered = [...STEP_ORDER];
29
- for (const label of states.keys()) {
30
- if (!ordered.includes(label)) ordered.push(label);
31
- }
32
-
33
- return ordered.map((label) => {
34
- const state = states.get(label);
35
- return {
36
- label,
37
- display: stepDisplayLabel(label),
38
- status: state?.status ?? "pending",
39
- durationMs: state?.durationMs,
40
- };
41
- });
42
- }
43
-
44
- export function stepMarker(status) {
45
- switch (status) {
46
- case "succeeded":
47
- return "✓";
48
- case "running":
49
- return "●";
50
- case "failed":
51
- return "✗";
52
- default:
53
- return "○";
54
- }
55
- }
56
-
57
- export function getCurrentCommand(events) {
58
- const active = new Map();
59
- for (const ev of events) {
60
- if (ev.type === "command.started") {
61
- active.set(ev.label, ev);
62
- } else if (ev.type === "command.finished") {
63
- active.delete(ev.label);
64
- }
65
- }
66
- let latest = null;
67
- for (const cmd of active.values()) {
68
- if (!latest || cmd.at > latest.at) latest = cmd;
69
- }
70
- if (latest?.at) {
71
- const elapsed = Date.now() - Date.parse(latest.at);
72
- latest = { ...latest, elapsedMs: Number.isFinite(elapsed) ? elapsed : 0 };
73
- }
74
- return latest;
75
- }
76
-
77
- export function getOutputTail(events, commandLabel) {
78
- if (!commandLabel) return "";
79
- const chunks = [];
80
- for (const ev of events) {
81
- if (
82
- ev.type === "command.output" &&
83
- ev.label === commandLabel &&
84
- ev.outputPreview
85
- ) {
86
- chunks.push(ev.outputPreview);
87
- }
88
- }
89
- return chunks.join("");
90
- }
91
-
92
- export function collectArtifacts(task, events) {
93
- const arts = new Map();
94
- const add = (label, artifactPath) => {
95
- if (artifactPath && !arts.has(label)) arts.set(label, artifactPath);
96
- };
97
-
98
- if (task?.artifactRefs) {
99
- for (const key of ARTIFACT_KEYS) {
100
- add(ARTIFACT_LABELS[key] ?? key, task.artifactRefs[key]);
101
- }
102
- }
103
-
104
- for (const ev of events) {
105
- if (!ev.artifactRefs) continue;
106
- for (const [key, artifactPath] of Object.entries(ev.artifactRefs)) {
107
- add(ARTIFACT_LABELS[key] ?? key, artifactPath);
108
- }
109
- }
110
-
111
- return arts;
112
- }
113
-
114
- export function findBatchRunIdForTask(snapshot, task) {
115
- if (!snapshot || !task) return null;
116
- const workerRunId = task.workerRunId;
117
- if (!workerRunId) return null;
118
- for (const batch of snapshot.batches ?? []) {
119
- for (const t of batch.tasks ?? []) {
120
- if (t.workerRunId === workerRunId) return batch.batchRunId;
121
- }
122
- }
123
- return null;
124
- }
125
-
126
- export function taskRunHistoryRow(run) {
127
- let runLink = run.workerRunId;
128
- if (run.workerRunId) {
129
- const a = document.createElement("a");
130
- a.href = `#/run/${encodeURIComponent(run.workerRunId)}`;
131
- a.textContent = run.workerRunId;
132
- a.addEventListener("click", (e) => {
133
- e.preventDefault();
134
- navigate(`#/run/${encodeURIComponent(run.workerRunId)}`);
135
- });
136
- runLink = a;
137
- }
138
- return {
139
- cells: [
140
- runLink,
141
- badge(run.status),
142
- run.recordedAt ?? run.finishedAt ?? "—",
143
- run.batchRunId ?? "—",
144
- run.retryOfWorkerRunId ?? "—",
145
- run.failureCategory ?? "—",
146
- ],
147
- };
148
- }
1
+ /** Run step/command/artifact processing and task history rows. */
2
+ import {
3
+ STEP_LABELS,
4
+ ARTIFACT_LABELS,
5
+ STEP_ORDER,
6
+ ARTIFACT_KEYS,
7
+ } from "./constants.js";
8
+ import { badge } from "./format.js";
9
+ import { navigate } from "./router.js";
10
+
11
+ export function stepDisplayLabel(label) {
12
+ return STEP_LABELS[label] ?? label;
13
+ }
14
+
15
+ export function buildStepStates(events) {
16
+ const states = new Map();
17
+ for (const ev of events) {
18
+ if (ev.type === "step.started") {
19
+ states.set(ev.label, { status: "running", startedAt: ev.at });
20
+ } else if (ev.type === "step.finished") {
21
+ states.set(ev.label, {
22
+ status: ev.status === "failed" ? "failed" : "succeeded",
23
+ durationMs: ev.durationMs,
24
+ });
25
+ }
26
+ }
27
+
28
+ const ordered = [...STEP_ORDER];
29
+ for (const label of states.keys()) {
30
+ if (!ordered.includes(label)) ordered.push(label);
31
+ }
32
+
33
+ return ordered.map((label) => {
34
+ const state = states.get(label);
35
+ return {
36
+ label,
37
+ display: stepDisplayLabel(label),
38
+ status: state?.status ?? "pending",
39
+ durationMs: state?.durationMs,
40
+ };
41
+ });
42
+ }
43
+
44
+ export function stepMarker(status) {
45
+ switch (status) {
46
+ case "succeeded":
47
+ return "✓";
48
+ case "running":
49
+ return "●";
50
+ case "failed":
51
+ return "✗";
52
+ default:
53
+ return "○";
54
+ }
55
+ }
56
+
57
+ export function getCurrentCommand(events) {
58
+ const active = new Map();
59
+ for (const ev of events) {
60
+ if (ev.type === "command.started") {
61
+ active.set(ev.label, ev);
62
+ } else if (ev.type === "command.finished") {
63
+ active.delete(ev.label);
64
+ }
65
+ }
66
+ let latest = null;
67
+ for (const cmd of active.values()) {
68
+ if (!latest || cmd.at > latest.at) latest = cmd;
69
+ }
70
+ if (latest?.at) {
71
+ const elapsed = Date.now() - Date.parse(latest.at);
72
+ latest = { ...latest, elapsedMs: Number.isFinite(elapsed) ? elapsed : 0 };
73
+ }
74
+ return latest;
75
+ }
76
+
77
+ export function getOutputTail(events, commandLabel) {
78
+ if (!commandLabel) return "";
79
+ const chunks = [];
80
+ for (const ev of events) {
81
+ if (
82
+ ev.type === "command.output" &&
83
+ ev.label === commandLabel &&
84
+ ev.outputPreview
85
+ ) {
86
+ chunks.push(ev.outputPreview);
87
+ }
88
+ }
89
+ return chunks.join("");
90
+ }
91
+
92
+ export function collectArtifacts(task, events) {
93
+ const arts = new Map();
94
+ const add = (label, artifactPath) => {
95
+ if (artifactPath && !arts.has(label)) arts.set(label, artifactPath);
96
+ };
97
+
98
+ if (task?.artifactRefs) {
99
+ for (const key of ARTIFACT_KEYS) {
100
+ add(ARTIFACT_LABELS[key] ?? key, task.artifactRefs[key]);
101
+ }
102
+ }
103
+
104
+ for (const ev of events) {
105
+ if (!ev.artifactRefs) continue;
106
+ for (const [key, artifactPath] of Object.entries(ev.artifactRefs)) {
107
+ add(ARTIFACT_LABELS[key] ?? key, artifactPath);
108
+ }
109
+ }
110
+
111
+ return arts;
112
+ }
113
+
114
+ export function findBatchRunIdForTask(snapshot, task) {
115
+ if (!snapshot || !task) return null;
116
+ const workerRunId = task.workerRunId;
117
+ if (!workerRunId) return null;
118
+ for (const batch of snapshot.batches ?? []) {
119
+ for (const t of batch.tasks ?? []) {
120
+ if (t.workerRunId === workerRunId) return batch.batchRunId;
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+
126
+ export function taskRunHistoryRow(run) {
127
+ let runLink = run.workerRunId;
128
+ if (run.workerRunId) {
129
+ const a = document.createElement("a");
130
+ a.href = `#/run/${encodeURIComponent(run.workerRunId)}`;
131
+ a.textContent = run.workerRunId;
132
+ a.addEventListener("click", (e) => {
133
+ e.preventDefault();
134
+ navigate(`#/run/${encodeURIComponent(run.workerRunId)}`);
135
+ });
136
+ runLink = a;
137
+ }
138
+ return {
139
+ cells: [
140
+ runLink,
141
+ badge(run.status),
142
+ run.recordedAt ?? run.finishedAt ?? "—",
143
+ run.batchRunId ?? "—",
144
+ run.retryOfWorkerRunId ?? "—",
145
+ run.failureCategory ?? "—",
146
+ ],
147
+ };
148
+ }
@@ -47,8 +47,16 @@
47
47
 
48
48
  html {
49
49
  background:
50
- radial-gradient(1200px 480px at 8% -10%, rgb(241 216 203 / 45%), transparent 55%),
51
- radial-gradient(900px 420px at 100% 0%, rgb(216 234 213 / 35%), transparent 50%),
50
+ radial-gradient(
51
+ 1200px 480px at 8% -10%,
52
+ rgb(241 216 203 / 45%),
53
+ transparent 55%
54
+ ),
55
+ radial-gradient(
56
+ 900px 420px at 100% 0%,
57
+ rgb(216 234 213 / 35%),
58
+ transparent 50%
59
+ ),
52
60
  var(--canvas);
53
61
  min-height: 100%;
54
62
  scroll-behavior: smooth;
@@ -62,14 +70,8 @@ body {
62
70
  color: var(--ink);
63
71
  /* Keep system-ui first for shell contract tests; Chinese fonts follow. */
64
72
  font-family:
65
- system-ui,
66
- -apple-system,
67
- "Segoe UI",
68
- "PingFang SC",
69
- "Hiragino Sans GB",
70
- "Noto Sans SC",
71
- BlinkMacSystemFont,
72
- sans-serif;
73
+ system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB",
74
+ "Noto Sans SC", BlinkMacSystemFont, sans-serif;
73
75
  font-size: 14px;
74
76
  line-height: 1.5;
75
77
  }
@@ -868,7 +870,7 @@ td:first-child,
868
870
  transition: opacity var(--transition-fast);
869
871
  }
870
872
  /* Five-column default: right two columns open inward (left) to avoid viewport overflow. */
871
- .kpi-grid:not(.pool-health-grid) > .kpi-card:nth-child(5n-1) .kpi-tip,
873
+ .kpi-grid:not(.pool-health-grid) > .kpi-card:nth-child(5n - 1) .kpi-tip,
872
874
  .kpi-grid:not(.pool-health-grid) > .kpi-card:nth-child(5n) .kpi-tip {
873
875
  left: auto;
874
876
  right: 12px;
@@ -1114,7 +1116,10 @@ td:first-child,
1114
1116
  }
1115
1117
  .feature-decision-row {
1116
1118
  display: grid;
1117
- grid-template-columns: minmax(120px, 0.9fr) minmax(88px, 0.55fr) minmax(0, 1.6fr) auto;
1119
+ grid-template-columns: minmax(120px, 0.9fr) minmax(88px, 0.55fr) minmax(
1120
+ 0,
1121
+ 1.6fr
1122
+ ) auto;
1118
1123
  align-items: center;
1119
1124
  gap: var(--space-3);
1120
1125
  padding: 12px 14px;
@@ -1254,8 +1259,8 @@ tr.clickable:focus-within {
1254
1259
  background: color-mix(in srgb, var(--red) 8%, var(--surface));
1255
1260
  }
1256
1261
  .badge-partial-failed {
1257
- color: color-mix(in srgb, var(--red) 70%, var(--ink));
1258
- background: color-mix(in srgb, var(--red) 6%, var(--surface));
1262
+ color: color-mix(in srgb, var(--amber) 80%, var(--ink));
1263
+ background: color-mix(in srgb, var(--amber) 10%, var(--surface));
1259
1264
  }
1260
1265
  .badge-running,
1261
1266
  .badge-started {
@@ -1494,7 +1499,11 @@ body.is-resizing-dag-graph {
1494
1499
  border: 1px solid var(--hairline);
1495
1500
  border-radius: var(--radius-lg);
1496
1501
  background:
1497
- radial-gradient(800px 280px at 0% 0%, rgb(241 216 203 / 28%), transparent 55%),
1502
+ radial-gradient(
1503
+ 800px 280px at 0% 0%,
1504
+ rgb(241 216 203 / 28%),
1505
+ transparent 55%
1506
+ ),
1498
1507
  var(--canvas-soft);
1499
1508
  scroll-behavior: auto;
1500
1509
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 60%);
@@ -2007,11 +2016,25 @@ body.is-resizing-dag-graph {
2007
2016
  font-weight: 700;
2008
2017
  }
2009
2018
 
2010
- .spec-evidence-section { padding-bottom: var(--space-4); border-bottom: 1px solid var(--hairline); }
2011
- .spec-evidence-section + .spec-evidence-section { margin-top: var(--space-4); }
2012
- .spec-evidence-section h4 { margin: 0 0 var(--space-2); color: var(--ink); font-size: 12px; font-weight: 700; }
2019
+ .spec-evidence-section {
2020
+ padding-bottom: var(--space-4);
2021
+ border-bottom: 1px solid var(--hairline);
2022
+ }
2023
+ .spec-evidence-section + .spec-evidence-section {
2024
+ margin-top: var(--space-4);
2025
+ }
2026
+ .spec-evidence-section h4 {
2027
+ margin: 0 0 var(--space-2);
2028
+ color: var(--ink);
2029
+ font-size: 12px;
2030
+ font-weight: 700;
2031
+ }
2013
2032
 
2014
- .node-input-root { display: flex; flex-direction: column; gap: var(--space-3); }
2033
+ .node-input-root {
2034
+ display: flex;
2035
+ flex-direction: column;
2036
+ gap: var(--space-3);
2037
+ }
2015
2038
  .node-input-semantics {
2016
2039
  margin: 0;
2017
2040
  font-size: 12px;
@@ -2084,24 +2107,141 @@ body.is-resizing-dag-graph {
2084
2107
  color: var(--danger, #b42318);
2085
2108
  font-size: 13px;
2086
2109
  }
2087
- .spec-evidence-summary { margin: var(--space-2) 0 0; color: var(--body); font-size: 12px; line-height: 1.6; }
2088
- .spec-evidence-list { display: grid; gap: 6px; margin: var(--space-2) 0 0; padding: 0; list-style: none; }
2089
- .spec-evidence-list li { display: flex; align-items: flex-start; gap: 6px; color: var(--body); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
2090
- .spec-evidence-list li > i { flex-shrink: 0; margin-top: 2px; color: var(--muted); font-size: 13px; }
2091
- .spec-evidence-list code { font-size: 11px; }
2092
- .spec-evidence-time { margin-left: auto; color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; white-space: nowrap; }
2093
- .spec-evidence-warning { display: flex; align-items: flex-start; gap: 8px; margin-top: var(--space-4); padding: 10px 12px; border: 1px solid var(--hairline); border-left: 3px solid color-mix(in srgb, var(--amber) 60%, var(--hairline)); border-radius: var(--radius-md); background: color-mix(in srgb, var(--amber) 8%, var(--surface)); color: var(--body); font-size: 12px; line-height: 1.6; }
2094
- .spec-evidence-warning > i { flex-shrink: 0; margin-top: 2px; color: var(--amber); }
2095
- .spec-evidence-file-btn { display: flex; align-items: flex-start; gap: 6px; width: 100%; padding: 6px 8px; background: none; border: none; text-align: left; cursor: pointer; color: inherit; font: inherit; line-height: 1.5; overflow-wrap: anywhere; border-radius: var(--radius-md); }
2096
- .spec-evidence-file-btn:hover, .spec-evidence-file-btn:focus-visible { background: var(--orange-soft); outline: none; }
2097
- .spec-evidence-file-btn:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--orange) 35%, transparent); }
2098
- .spec-evidence-detail { display: grid; gap: var(--space-3); }
2099
- .spec-evidence-back { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 1px solid var(--hairline); border-radius: var(--radius-pill); background: var(--surface); color: var(--ink); font-size: 12px; font-weight: 650; cursor: pointer; }
2100
- .spec-evidence-back:hover, .spec-evidence-back:focus-visible { background: var(--orange-soft); border-color: var(--orange); color: var(--orange-active); outline: none; }
2101
- .spec-evidence-detail-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 12px; color: var(--body); }
2102
- .spec-evidence-detail-content { min-height: 0; max-width: 100%; margin: 0; padding: var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--canvas-soft); overflow-wrap: anywhere; font-size: 12px; line-height: 1.6; }
2103
- .spec-evidence-detail-error { margin: 0; color: var(--red, #c00); font-size: 12px; }
2104
- .spec-evidence-detail-truncated { margin: 0; color: var(--muted); font-size: 11px; }
2110
+ .spec-evidence-summary {
2111
+ margin: var(--space-2) 0 0;
2112
+ color: var(--body);
2113
+ font-size: 12px;
2114
+ line-height: 1.6;
2115
+ }
2116
+ .spec-evidence-list {
2117
+ display: grid;
2118
+ gap: 6px;
2119
+ margin: var(--space-2) 0 0;
2120
+ padding: 0;
2121
+ list-style: none;
2122
+ }
2123
+ .spec-evidence-list li {
2124
+ display: flex;
2125
+ align-items: flex-start;
2126
+ gap: 6px;
2127
+ color: var(--body);
2128
+ font-size: 12px;
2129
+ line-height: 1.5;
2130
+ overflow-wrap: anywhere;
2131
+ }
2132
+ .spec-evidence-list li > i {
2133
+ flex-shrink: 0;
2134
+ margin-top: 2px;
2135
+ color: var(--muted);
2136
+ font-size: 13px;
2137
+ }
2138
+ .spec-evidence-list code {
2139
+ font-size: 11px;
2140
+ }
2141
+ .spec-evidence-time {
2142
+ margin-left: auto;
2143
+ color: var(--muted);
2144
+ font-size: 10px;
2145
+ font-variant-numeric: tabular-nums;
2146
+ white-space: nowrap;
2147
+ }
2148
+ .spec-evidence-warning {
2149
+ display: flex;
2150
+ align-items: flex-start;
2151
+ gap: 8px;
2152
+ margin-top: var(--space-4);
2153
+ padding: 10px 12px;
2154
+ border: 1px solid var(--hairline);
2155
+ border-left: 3px solid color-mix(in srgb, var(--amber) 60%, var(--hairline));
2156
+ border-radius: var(--radius-md);
2157
+ background: color-mix(in srgb, var(--amber) 8%, var(--surface));
2158
+ color: var(--body);
2159
+ font-size: 12px;
2160
+ line-height: 1.6;
2161
+ }
2162
+ .spec-evidence-warning > i {
2163
+ flex-shrink: 0;
2164
+ margin-top: 2px;
2165
+ color: var(--amber);
2166
+ }
2167
+ .spec-evidence-file-btn {
2168
+ display: flex;
2169
+ align-items: flex-start;
2170
+ gap: 6px;
2171
+ width: 100%;
2172
+ padding: 6px 8px;
2173
+ background: none;
2174
+ border: none;
2175
+ text-align: left;
2176
+ cursor: pointer;
2177
+ color: inherit;
2178
+ font: inherit;
2179
+ line-height: 1.5;
2180
+ overflow-wrap: anywhere;
2181
+ border-radius: var(--radius-md);
2182
+ }
2183
+ .spec-evidence-file-btn:hover,
2184
+ .spec-evidence-file-btn:focus-visible {
2185
+ background: var(--orange-soft);
2186
+ outline: none;
2187
+ }
2188
+ .spec-evidence-file-btn:focus-visible {
2189
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--orange) 35%, transparent);
2190
+ }
2191
+ .spec-evidence-detail {
2192
+ display: grid;
2193
+ gap: var(--space-3);
2194
+ }
2195
+ .spec-evidence-back {
2196
+ display: inline-flex;
2197
+ align-items: center;
2198
+ gap: 6px;
2199
+ padding: 6px 12px;
2200
+ border: 1px solid var(--hairline);
2201
+ border-radius: var(--radius-pill);
2202
+ background: var(--surface);
2203
+ color: var(--ink);
2204
+ font-size: 12px;
2205
+ font-weight: 650;
2206
+ cursor: pointer;
2207
+ }
2208
+ .spec-evidence-back:hover,
2209
+ .spec-evidence-back:focus-visible {
2210
+ background: var(--orange-soft);
2211
+ border-color: var(--orange);
2212
+ color: var(--orange-active);
2213
+ outline: none;
2214
+ }
2215
+ .spec-evidence-detail-meta {
2216
+ display: flex;
2217
+ flex-wrap: wrap;
2218
+ align-items: center;
2219
+ gap: 8px;
2220
+ font-size: 12px;
2221
+ color: var(--body);
2222
+ }
2223
+ .spec-evidence-detail-content {
2224
+ min-height: 0;
2225
+ max-width: 100%;
2226
+ margin: 0;
2227
+ padding: var(--space-3);
2228
+ border: 1px solid var(--hairline);
2229
+ border-radius: var(--radius-md);
2230
+ background: var(--canvas-soft);
2231
+ overflow-wrap: anywhere;
2232
+ font-size: 12px;
2233
+ line-height: 1.6;
2234
+ }
2235
+ .spec-evidence-detail-error {
2236
+ margin: 0;
2237
+ color: var(--red, #c00);
2238
+ font-size: 12px;
2239
+ }
2240
+ .spec-evidence-detail-truncated {
2241
+ margin: 0;
2242
+ color: var(--muted);
2243
+ font-size: 11px;
2244
+ }
2105
2245
 
2106
2246
  .run-layer-process {
2107
2247
  display: grid;
@@ -2312,10 +2452,12 @@ body.is-resizing-dag-graph {
2312
2452
  background: color-mix(in srgb, var(--green) 75%, white);
2313
2453
  }
2314
2454
  .dag-run-timeline-dot.status-failed,
2315
- .dag-run-timeline-dot.status-error,
2316
- .dag-run-timeline-dot.status-partial_failed {
2455
+ .dag-run-timeline-dot.status-error {
2317
2456
  background: color-mix(in srgb, var(--red) 75%, white);
2318
2457
  }
2458
+ .dag-run-timeline-dot.status-partial-failed {
2459
+ background: color-mix(in srgb, var(--amber) 75%, white);
2460
+ }
2319
2461
  .dag-run-timeline-dot.status-running,
2320
2462
  .dag-run-timeline-dot.status-started {
2321
2463
  background: var(--orange);
@@ -2374,7 +2516,7 @@ body.is-resizing-dag-graph {
2374
2516
  border-left: 0;
2375
2517
  }
2376
2518
  /* Three-column: reset five-column tip edges, then rightmost column opens inward. */
2377
- .kpi-grid:not(.pool-health-grid) > .kpi-card:nth-child(5n-1) .kpi-tip,
2519
+ .kpi-grid:not(.pool-health-grid) > .kpi-card:nth-child(5n - 1) .kpi-tip,
2378
2520
  .kpi-grid:not(.pool-health-grid) > .kpi-card:nth-child(5n) .kpi-tip {
2379
2521
  left: 12px;
2380
2522
  right: auto;
@@ -2662,8 +2804,6 @@ button.copy-command:focus-visible {
2662
2804
  margin: 0.15rem 0 0.35rem;
2663
2805
  }
2664
2806
 
2665
-
2666
-
2667
2807
  /* R5: unified view states + information hierarchy */
2668
2808
  .view-state {
2669
2809
  border-radius: var(--radius-lg);