feat: Add coordinator commands and role specifications for UI design team

- Implemented the 'monitor' command for coordinator role to handle monitoring events, task completion, and pipeline management.
- Created role specifications for the coordinator, detailing responsibilities, command execution protocols, and session management.
- Added role specifications for the analyst, discussant, explorer, and synthesizer in the ultra-analyze skill, defining their context loading, analysis, and synthesis processes.
This commit is contained in:
catlog22
2026-03-03 23:35:41 +08:00
parent a7ed0365f7
commit 26bda9c634
188 changed files with 9332 additions and 3512 deletions

View File

@@ -58,11 +58,9 @@ Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <session-id>, // MUST be session ID (e.g., TD-xxx-date), NOT team name. Extract from Session: field in task description.
session_id: <session-id>,
from: "assessor",
to: "coordinator",
type: <message-type>,
summary: "[assessor] <task-prefix> complete: <task-subject>",
ref: <artifact-path>
})
```
@@ -70,7 +68,7 @@ mcp__ccw-tools__team_msg({
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <session-id> --from assessor --to coordinator --type <message-type> --summary \"[assessor] ...\" --ref <artifact-path> --json")
Bash("ccw team log --session-id <session-id> --from assessor --type <message-type> --ref <artifact-path> --json")
```
---
@@ -88,13 +86,13 @@ Standard task discovery flow: TaskList -> filter by prefix `TDEVAL-*` + owner ma
| Input | Source | Required |
|-------|--------|----------|
| Session folder | task.description (regex: `session:\s*(.+)`) | Yes |
| Shared memory | `<session-folder>/shared-memory.json` | Yes |
| Debt inventory | shared-memory.debt_inventory OR `<session-folder>/scan/debt-inventory.json` | Yes |
| Shared memory | `<session-folder>/.msg/meta.json` | Yes |
| Debt inventory | meta.json:debt_inventory OR `<session-folder>/scan/debt-inventory.json` | Yes |
**Loading steps**:
1. Extract session path from task description
2. Read shared-memory.json
2. Read .msg/meta.json
3. Load debt_inventory from shared memory or fallback to debt-inventory.json file
4. If debt_inventory is empty -> report empty assessment and exit
@@ -156,7 +154,7 @@ Delegate to `commands/evaluate.md` if available, otherwise execute inline.
**Save outputs**:
1. Write `<session-folder>/assessment/priority-matrix.json`
2. Update shared-memory.json with `priority_matrix` summary and evaluated `debt_inventory`
2. Update .msg/meta.json with `priority_matrix` summary and evaluated `debt_inventory`
### Phase 5: Report to Coordinator

View File

@@ -102,9 +102,8 @@ const chainValid = chainTasks.length === pipeline.length
if (!chainValid) {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId, from: "coordinator", // team must be session ID (e.g., TD-xxx-date), NOT team name
to: "user", type: "error",
summary: `[coordinator] 任务链创建不完整: ${chainTasks.length}/${pipeline.length}`
operation: "log", session_id: sessionId, from: "coordinator", // team must be session ID (e.g., TD-xxx-date), NOT team name
type: "error",
})
}
```

View File

@@ -47,7 +47,7 @@ const STAGE_WORKER_MAP = {
### Step 1: Context Preparation
```javascript
const sharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
const sharedMemory = JSON.parse(Read(`${sessionFolder}/.msg/meta.json`))
let fixVerifyIteration = 0
const MAX_FIX_VERIFY_ITERATIONS = 3
@@ -76,9 +76,8 @@ for (const stageTask of pipelineTasks) {
if (!workerConfig) {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "error",
summary: `[coordinator] 未知阶段前缀: ${stagePrefix},跳过`
operation: "log", session_id: sessionId, from: "coordinator",
type: "error",
})
continue
}
@@ -87,15 +86,14 @@ for (const stageTask of pipelineTasks) {
TaskUpdate({ taskId: stageTask.id, status: 'in_progress' })
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
operation: "log", session_id: sessionId, from: "coordinator",
to: workerConfig.role, type: "task_unblocked",
summary: `[coordinator] 启动阶段: ${stageTask.subject}${workerConfig.role}`
})
// 3. 同步 spawn worker — 阻塞直到 worker 返回Stop-Wait 核心)
// Task() 本身就是等待机制,无需 sleep/poll
const workerResult = Task({
subagent_type: "general-purpose",
subagent_type: "team-worker",
description: `Spawn ${workerConfig.role} worker for ${stageTask.subject}`,
team_name: teamName,
name: workerConfig.role,
@@ -111,9 +109,8 @@ for (const stageTask of pipelineTasks) {
handleStageFailure(stageTask, taskState, workerConfig, autoYes)
} else {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "quality_gate",
summary: `[coordinator] 阶段完成: ${stageTask.subject}`
operation: "log", session_id: sessionId, from: "coordinator",
type: "quality_gate",
})
}
@@ -127,9 +124,8 @@ for (const stageTask of pipelineTasks) {
}
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "plan_approval",
summary: `[coordinator] 治理方案已生成,等待审批`
operation: "log", session_id: sessionId, from: "coordinator",
type: "plan_approval",
})
if (!autoYes) {
@@ -166,9 +162,8 @@ for (const stageTask of pipelineTasks) {
continue // 跳到下一阶段(即刚插入的修订任务)
} else if (planDecision === "终止") {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "shutdown",
summary: `[coordinator] 用户终止流水线(方案审批阶段)`
operation: "log", session_id: sessionId, from: "coordinator",
type: "shutdown",
})
break // 退出 pipeline 循环
}
@@ -189,14 +184,13 @@ for (const stageTask of pipelineTasks) {
// 存入 shared memory
sharedMemory.worktree = { path: worktreePath, branch: branchName }
Write(`${sessionFolder}/shared-memory.json`, JSON.stringify(sharedMemory, null, 2))
Write(`${sessionFolder}/.msg/meta.json`, JSON.stringify(sharedMemory, null, 2))
worktreeCreated = true
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "worktree_created",
summary: `[coordinator] Worktree 已创建: ${worktreePath} (branch: ${branchName})`
operation: "log", session_id: sessionId, from: "coordinator",
type: "worktree_created",
})
}
@@ -231,32 +225,22 @@ function buildWorkerPrompt(stageTask, workerConfig, sessionFolder, taskDescripti
- 禁止在主工作树中修改任何文件`
}
return `你是 team "${teamName}" 的 ${workerConfig.role.toUpperCase()}
return `## Role Assignment
role: ${workerConfig.role}
role_spec: .claude/skills/team-tech-debt/role-specs/${workerConfig.role}.md
session: ${sessionFolder}
session_id: ${sessionId}
team_name: ${teamName}
requirement: ${stageTask.description || taskDescription}
inner_loop: false
## ⚠️ 首要指令MUST
你的所有工作必须通过调用 Skill 获取角色定义后执行,禁止自行发挥:
Skill(skill="team-tech-debt", args="${workerConfig.skillArgs}")
此调用会加载你的角色定义role.md、可用命令commands/*.md和完整执行逻辑。
## 当前任务
- 任务 ID: ${stageTask.id}
- 任务: ${stageTask.subject}
- 描述: ${stageTask.description || taskDescription}
- Session: ${sessionFolder}
## Current Task
- Task ID: ${stageTask.id}
- Task: ${stageTask.subject}
- Task Prefix: ${stagePrefix}
${worktreeSection}
## 角色准则(强制)
- 你只能处理 ${stagePrefix}-* 前缀的任务
- 所有输出必须带 [${workerConfig.role}] 标识前缀
- 仅与 coordinator 通信,不得直接联系其他 worker
## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录。
## 工作流程(严格按顺序)
1. 调用 Skill(skill="team-tech-debt", args="${workerConfig.skillArgs}") 获取角色定义和执行逻辑
2. 按 role.md 中的 5-Phase 流程执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate({ taskId: "${stageTask.id}", status: "completed" })`
Read role_spec file to load Phase 2-4 domain instructions.
Execute built-in Phase 1 -> role-spec Phase 2-4 -> built-in Phase 5.`
}
```
@@ -266,9 +250,8 @@ ${worktreeSection}
function handleStageFailure(stageTask, taskState, workerConfig, autoYes) {
if (autoYes) {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "error",
summary: `[coordinator] [auto] 阶段 ${stageTask.subject} 未完成 (status=${taskState.status}),自动跳过`
operation: "log", session_id: sessionId, from: "coordinator",
type: "error",
})
TaskUpdate({ taskId: stageTask.id, status: 'deleted' })
return 'skip'
@@ -292,7 +275,7 @@ function handleStageFailure(stageTask, taskState, workerConfig, autoYes) {
// 重新 spawn worker递归单次
TaskUpdate({ taskId: stageTask.id, status: 'in_progress' })
const retryResult = Task({
subagent_type: "general-purpose",
subagent_type: "team-worker",
description: `Retry ${workerConfig.role} worker for ${stageTask.subject}`,
team_name: teamName,
name: workerConfig.role,
@@ -309,9 +292,8 @@ function handleStageFailure(stageTask, taskState, workerConfig, autoYes) {
return 'skip'
} else {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "shutdown",
summary: `[coordinator] 用户终止流水线,当前阶段: ${stageTask.subject}`
operation: "log", session_id: sessionId, from: "coordinator",
type: "shutdown",
})
return 'abort'
}
@@ -322,7 +304,7 @@ function handleStageFailure(stageTask, taskState, workerConfig, autoYes) {
```javascript
function evaluateValidationResult(sessionFolder) {
const latestMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
const latestMemory = JSON.parse(Read(`${sessionFolder}/.msg/meta.json`))
const debtBefore = latestMemory.debt_score_before || 0
const debtAfter = latestMemory.debt_score_after || 0
const regressions = latestMemory.validation_results?.regressions || 0
@@ -333,9 +315,8 @@ function evaluateValidationResult(sessionFolder) {
else if (!improved) status = 'CONDITIONAL'
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "quality_gate",
summary: `[coordinator] 质量门控: ${status} (债务分 ${debtBefore}${debtAfter}, 回归 ${regressions})`
operation: "log", session_id: sessionId, from: "coordinator",
type: "quality_gate",
})
return regressions > 0
@@ -346,7 +327,7 @@ function evaluateValidationResult(sessionFolder) {
```javascript
// 汇总所有结果
const finalSharedMemory = JSON.parse(Read(`${sessionFolder}/shared-memory.json`))
const finalSharedMemory = JSON.parse(Read(`${sessionFolder}/.msg/meta.json`))
const allFinalTasks = TaskList()
const workerTasks = allFinalTasks.filter(t => t.owner && t.owner !== 'coordinator')
@@ -387,18 +368,16 @@ EOF
)"`)
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "pr_created",
summary: `[coordinator] PR 已创建: branch ${branch}`
operation: "log", session_id: sessionId, from: "coordinator",
type: "pr_created",
})
// Cleanup worktree
Bash(`git worktree remove "${wtPath}" 2>/dev/null || true`)
} else if (finalSharedMemory.worktree && !finalSharedMemory.validation_results?.passed) {
mcp__ccw-tools__team_msg({
operation: "log", team: sessionId // MUST be session ID (e.g., TD-xxx-date), NOT team name, from: "coordinator",
to: "user", type: "quality_gate",
summary: `[coordinator] 验证未通过worktree 保留于 ${finalSharedMemory.worktree.path},请手动检查`
operation: "log", session_id: sessionId, from: "coordinator",
type: "quality_gate",
})
}

View File

@@ -29,18 +29,56 @@
---
## Command Execution Protocol
When coordinator needs to execute a command (dispatch, monitor):
1. **Read the command file**: `roles/coordinator/commands/<command-name>.md`
2. **Follow the workflow** defined in the command file (Phase 2-4 structure)
3. **Commands are inline execution guides** -- NOT separate agents or subprocesses
4. **Execute synchronously** -- complete the command workflow before proceeding
Example:
```
Phase 3 needs task dispatch
-> Read roles/coordinator/commands/dispatch.md
-> Execute Phase 2 (Context Loading)
-> Execute Phase 3 (Task Chain Creation)
-> Execute Phase 4 (Validation)
-> Continue to Phase 4
```
---
## Entry Router
When coordinator is invoked, first detect the invocation type:
When coordinator is invoked, detect invocation type:
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Worker callback | Message contains `[role-name]` tag from a known worker role | -> handleCallback: auto-advance pipeline |
| Status check | Arguments contain "check" or "status" | -> handleCheck: output execution graph, no advancement |
| Manual resume | Arguments contain "resume" or "continue" | -> handleResume: check worker states, advance pipeline |
| New session | None of the above | -> Phase 0 (Session Resume Check) |
| Worker callback | Message contains role tag [scanner], [assessor], [planner], [executor], [validator] | -> handleCallback |
| Status check | Arguments contain "check" or "status" | -> handleCheck |
| Manual resume | Arguments contain "resume" or "continue" | -> handleResume |
| Pipeline complete | All tasks have status "completed" | -> handleComplete |
| Interrupted session | Active/paused session exists | -> Phase 0 (Session Resume Check) |
| New session | None of above | -> Phase 1 |
For callback/check/resume: load `commands/monitor.md` and execute the appropriate handler, then STOP.
For callback/check/resume/complete: load `commands/monitor.md` and execute matched handler, then STOP.
### Router Implementation
1. **Load session context** (if exists):
- Scan `.workflow/.team/TD-*/.msg/meta.json` for active/paused sessions
- If found, extract session folder path, status, and pipeline mode
2. **Parse $ARGUMENTS** for detection keywords:
- Check for role name tags in message content
- Check for "check", "status", "resume", "continue" keywords
3. **Route to handler**:
- For monitor handlers: Read `commands/monitor.md`, execute matched handler, STOP
- For Phase 0: Execute Session Resume Check below
- For Phase 1: Execute Requirement Clarification below
---
@@ -86,11 +124,9 @@ Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <session-id>, // MUST be session ID (e.g., TD-xxx-date), NOT team name. Extract from Session: field in task description.
session_id: <session-id>,
from: "coordinator",
to: "user",
type: <message-type>,
summary: "[coordinator] <summary>",
ref: <artifact-path>
})
```
@@ -98,7 +134,7 @@ mcp__ccw-tools__team_msg({
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <session-id> --from coordinator --to user --type <message-type> --summary \"[coordinator] ...\" --json")
Bash("ccw team log --session-id <session-id> --from coordinator --type <message-type> --json")
```
---
@@ -188,7 +224,7 @@ Bash("ccw team log --team <session-id> --from coordinator --to user --type <mess
└── issues.md
```
3. Initialize shared-memory.json:
3. Initialize .msg/meta.json:
| Field | Initial Value |
|-------|---------------|
@@ -308,7 +344,7 @@ Session: <session-folder>
**Worktree Creation** (before TDFIX):
1. Create worktree: `git worktree add <path> -b <branch>`
2. Update shared-memory.json with worktree info
2. Update .msg/meta.json with worktree info
3. Notify user via team_msg
**Fix-Verify Loop** (when TDVAL finds regressions):

View File

@@ -61,11 +61,9 @@ Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <session-id>, // MUST be session ID (e.g., TD-xxx-date), NOT team name. Extract from Session: field in task description.
session_id: <session-id>,
from: "executor",
to: "coordinator",
type: <message-type>,
summary: "[executor] <task-prefix> complete: <task-subject>",
ref: <artifact-path>
})
```
@@ -73,7 +71,7 @@ mcp__ccw-tools__team_msg({
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <session-id> --from executor --to coordinator --type <message-type> --summary \"[executor] ...\" --ref <artifact-path> --json")
Bash("ccw team log --session-id <session-id> --from executor --type <message-type> --ref <artifact-path> --json")
```
---
@@ -91,13 +89,13 @@ Standard task discovery flow: TaskList -> filter by prefix `TDFIX-*` + owner mat
| Input | Source | Required |
|-------|--------|----------|
| Session folder | task.description (regex: `session:\s*(.+)`) | Yes |
| Shared memory | `<session-folder>/shared-memory.json` | Yes |
| Shared memory | `<session-folder>/.msg/meta.json` | Yes |
| Remediation plan | `<session-folder>/plan/remediation-plan.json` | Yes |
**Loading steps**:
1. Extract session path from task description
2. Read shared-memory.json for worktree info:
2. Read .msg/meta.json for worktree info:
| Field | Description |
|-------|-------------|
@@ -194,7 +192,7 @@ Execute tech debt cleanup for <batch-type> items.
2. Run lint check -> record PASS/FAIL
3. Update fix_results.self_validation
4. Write `<session-folder>/fixes/fix-log.json`
5. Update shared-memory.json with fix_results
5. Update .msg/meta.json with fix_results
### Phase 5: Report to Coordinator

View File

@@ -58,11 +58,9 @@ Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <session-id>, // MUST be session ID (e.g., TD-xxx-date), NOT team name. Extract from Session: field in task description.
session_id: <session-id>,
from: "planner",
to: "coordinator",
type: <message-type>,
summary: "[planner] <task-prefix> complete: <task-subject>",
ref: <artifact-path>
})
```
@@ -70,7 +68,7 @@ mcp__ccw-tools__team_msg({
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <session-id> --from planner --to coordinator --type <message-type> --summary \"[planner] ...\" --ref <artifact-path> --json")
Bash("ccw team log --session-id <session-id> --from planner --type <message-type> --ref <artifact-path> --json")
```
---
@@ -88,13 +86,13 @@ Standard task discovery flow: TaskList -> filter by prefix `TDPLAN-*` + owner ma
| Input | Source | Required |
|-------|--------|----------|
| Session folder | task.description (regex: `session:\s*(.+)`) | Yes |
| Shared memory | `<session-folder>/shared-memory.json` | Yes |
| Shared memory | `<session-folder>/.msg/meta.json` | Yes |
| Priority matrix | `<session-folder>/assessment/priority-matrix.json` | Yes |
**Loading steps**:
1. Extract session path from task description
2. Read shared-memory.json for debt_inventory
2. Read .msg/meta.json for debt_inventory
3. Read priority-matrix.json for quadrant groupings
4. Group items by priority quadrant:
@@ -157,7 +155,7 @@ Delegate to `commands/create-plan.md` if available, otherwise execute inline.
1. Write `<session-folder>/plan/remediation-plan.md` (markdown format)
2. Write `<session-folder>/plan/remediation-plan.json` (machine-readable)
3. Update shared-memory.json with `remediation_plan` summary
3. Update .msg/meta.json with `remediation_plan` summary
### Phase 5: Report to Coordinator

View File

@@ -58,11 +58,9 @@ Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <session-id>, // MUST be session ID (e.g., TD-xxx-date), NOT team name. Extract from Session: field in task description.
session_id: <session-id>,
from: "scanner",
to: "coordinator",
type: <message-type>,
summary: "[scanner] <task-prefix> complete: <task-subject>",
ref: <artifact-path>
})
```
@@ -70,7 +68,7 @@ mcp__ccw-tools__team_msg({
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <session-id> --from scanner --to coordinator --type <message-type> --summary \"[scanner] ...\" --ref <artifact-path> --json")
Bash("ccw team log --session-id <session-id> --from scanner --type <message-type> --ref <artifact-path> --json")
```
---
@@ -89,12 +87,12 @@ Standard task discovery flow: TaskList -> filter by prefix `TDSCAN-*` + owner ma
|-------|--------|----------|
| Scan scope | task.description (regex: `scope:\s*(.+)`) | No (default: `**/*`) |
| Session folder | task.description (regex: `session:\s*(.+)`) | Yes |
| Shared memory | `<session-folder>/shared-memory.json` | Yes |
| Shared memory | `<session-folder>/.msg/meta.json` | Yes |
**Loading steps**:
1. Extract session path from task description
2. Read shared-memory.json for team context
2. Read .msg/meta.json for team context
3. Detect project type and framework:
| Detection | Method |
@@ -182,7 +180,7 @@ For each finding, create entry:
**Save outputs**:
1. Update shared-memory.json with `debt_inventory` and `debt_score_before`
1. Update .msg/meta.json with `debt_inventory` and `debt_score_before`
2. Write `<session-folder>/scan/debt-inventory.json`:
| Field | Description |

View File

@@ -59,11 +59,9 @@ Before every SendMessage, log via `mcp__ccw-tools__team_msg`:
```
mcp__ccw-tools__team_msg({
operation: "log",
team: <session-id>, // MUST be session ID (e.g., TD-xxx-date), NOT team name. Extract from Session: field in task description.
session_id: <session-id>,
from: "validator",
to: "coordinator",
type: <message-type>,
summary: "[validator] <task-prefix> complete: <task-subject>",
ref: <artifact-path>
})
```
@@ -71,7 +69,7 @@ mcp__ccw-tools__team_msg({
**CLI fallback** (when MCP unavailable):
```
Bash("ccw team log --team <session-id> --from validator --to coordinator --type <message-type> --summary \"[validator] ...\" --ref <artifact-path> --json")
Bash("ccw team log --session-id <session-id> --from validator --type <message-type> --ref <artifact-path> --json")
```
---
@@ -89,13 +87,13 @@ Standard task discovery flow: TaskList -> filter by prefix `TDVAL-*` + owner mat
| Input | Source | Required |
|-------|--------|----------|
| Session folder | task.description (regex: `session:\s*(.+)`) | Yes |
| Shared memory | `<session-folder>/shared-memory.json` | Yes |
| Shared memory | `<session-folder>/.msg/meta.json` | Yes |
| Fix log | `<session-folder>/fixes/fix-log.json` | No |
**Loading steps**:
1. Extract session path from task description
2. Read shared-memory.json for:
2. Read .msg/meta.json for:
| Field | Description |
|-------|-------------|
@@ -198,7 +196,7 @@ Delegate to `commands/verify.md` if available, otherwise execute inline.
**Save outputs**:
1. Write `<session-folder>/validation/validation-report.json`
2. Update shared-memory.json with `validation_results` and `debt_score_after`
2. Update .msg/meta.json with `validation_results` and `debt_score_after`
### Phase 5: Report to Coordinator