Files
solution-erp/.claude/workflows/hmw.js
pqhuy1987 cf908f5276 [CLAUDE] Infra: adopt AI_INFRA HMW-governance broadcast — ultra-on/off toggle + hmw.js checkpoint-gate + memory-safety (S49)
adap-apply 2026-06-03-Agent-ultracode-hmw-mem-governance (reviewer_gate PASS).
PROJECT-FIT=ADOPT tailored: SE 8-agent roster. nac=executed-file (verified-pending restart+spawn-test).

- T1/T2 toggle: .claude/commands/ultra-on.md + ultra-off.md; marker .claude/hmw-mode.on gitignored (T2 non-negotiable).
- T3: session-start BUOC 0.5 reads marker -> reports ON/OFF.
- S2/S3/S4: .claude/workflows/hmw.js P2 fan-out — checkpointApproved throw (mechanized), args JSON.parse-guard, role-whitelist fail-soft, VALID_ROLES=8 SE agents, sub-no-spawn-sub, return schema findings+memoryDelta 4-field (R1).
- M1-M5: B1 slice-inject / M2 return-delta-only / B3 single-writer append-only / B2 harvest-lien / M5 store_memory-strip re-verified intact (0 tools-grant).
- agents/README.md +HMW governance section (VALID_ROLES source-of-truth) + adap-report 5-field LOCK.

Test 181 unchanged (no .cs/.tsx). CI-skip (all .md/.js/.gitignore).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 13:15:03 +07:00

99 lines
6.0 KiB
JavaScript

// hmw.js — HMW P2 (Execute) workflow cho SOLUTION_ERP. CHẠY bởi Workflow runtime (body wrap async →
// top-level await/return hợp lệ); KHÔNG node-runnable trực tiếp (`node hmw.js` sẽ lỗi await).
// Em main lo P0/P1/P3/P4 NGOÀI workflow; script này CHỈ lo P2 fan-out.
// Invoke bằng {scriptPath} (no hot-reload — restart/re-invoke sau khi sửa). Scope = repo SOLUTION_ERP ONLY (S1).
export const meta = {
name: 'hmw',
description: 'HMW P2 execute (SOLUTION_ERP) — fan-out 8-agent roster có MEMORY-PACK slice (qua args vì script không đọc file) + return findings + checklistEvidence + memoryDelta (spawn-record 4-field). DEFAULT read/analyze; write fan-out = file-disjoint + em main git-diff sau P2. taskList thoải mái (queue theo slot, không cap cứng). memoryDelta KHÔNG tự ghi — em main VERIFY + APPEND-only @P3 (no-overwrite-unverified, B3). Same-model inherit Opus. Scope = repo SOLUTION_ERP ONLY (S1 — KHÔNG fan-out repo/corpus khác).',
phases: [{ title: 'Execute', detail: 'fan-out memory-pack-injected agents, structured return' }],
}
// ─── args (em main bơm @P2 sau khi P1 chốt) ──────────────────────────────────
// args = {
// memoryPack: { 'investigator-codebase':'<slice>', 'implementer-backend':'...', reviewer:'...', ... }, // SLICE liên quan, KHÔNG full
// spec: '<acceptance-criteria / context chung>',
// checkpointApproved: true, // em main set SAU khi BÁO {số agent·vai·task} @inform (S2)
// taskList: [ { role:<VALID_ROLES|null>, label:'..', prompt:'..' }, ... ]
// }
const VALID_ROLES = [
'investigator-codebase', 'investigator-api',
'implementer-backend', 'implementer-frontend',
'test-specialist', 'reviewer', 'cicd-monitor', 'frontend-designer',
]
const SCHEMA = {
type: 'object',
required: ['findings', 'memoryDelta'],
properties: {
findings: { type: 'string', description: 'Kết quả chính. MỌI claim kèm evidence file:line. KHÔNG narrative suông.' },
checklistEvidence: { type: 'string', description: 'Bằng chứng cho acceptance-checklist P1 (số đo / PASS-FAIL / verdict).' },
memoryDelta: {
type: 'object',
description: 'Spawn-record 4-field — RETURN-only để EM MAIN harvest @P3. Agent KHÔNG tự ghi ký ức (KHÔNG file MEMORY.md, KHÔNG store_memory/RAG). Em main VERIFY + APPEND-only (KHÔNG overwrite entry cũ nếu chưa kiểm tra — B3).',
required: ['task', 'verdict', 'learned', 'surprise'],
properties: {
task: { type: 'string', description: 'việc gì (1 dòng)' },
verdict: { type: 'string', description: 'kết luận / PASS-FAIL / root-cause' },
learned: { type: 'string', description: 'pattern / anti-pattern rút ra' },
surprise: { type: 'string', description: 'edge-case / bất ngờ (chống mất discovery)' },
},
},
},
}
// S4b — args có thể tới OBJECT hoặc JSON-STRING (harness đôi khi stringify object args) → normalize defensive
const A = (typeof args === 'string') ? JSON.parse(args) : (args || {})
if (!A || !Array.isArray(A.taskList) || A.taskList.length === 0) {
throw new Error('hmw: cần args.taskList (mảng {role,label,prompt}) — em main bơm @P1. (đã thử JSON.parse nếu args bị stringify.)')
}
// S2 mechanize: checkpoint TRƯỚC P2 = gate CỨNG, không chỉ prompt. Em main BÁO {số agent·vai·task} @inform
// (KHÔNG chờ confirm) → set args.checkpointApproved=true → fan-out. Flag GIỮ = anti-accidental-fire
// (call quên-set-flag → throw, chặn 515K-class accidental).
if (A.checkpointApproved !== true) {
throw new Error('hmw: checkpointApproved chưa set — em-main BÁO {số agent·vai·task} @inform rồi set args.checkpointApproved=true (guard = anti-accidental-fire).')
}
// S4 — số task THOẢI MÁI: harness chạy theo slot, dư tự queue, KHÔNG cap cứng (soft notice only).
if (A.taskList.length > 16) {
log(`hmw: taskList=${A.taskList.length} (>16) → harness queue theo slot (thoải mái, không cap cứng).`)
}
const memoryPack = A.memoryPack || {}
const spec = A.spec || ''
phase('Execute')
log(`HMW P2: fan-out ${A.taskList.length} task (same-model inherit, memory-pack-injected, scope=SOLUTION_ERP repo only)`)
const results = await parallel(A.taskList.map((t, i) => () => {
const raw = t && t.role
const role = VALID_ROLES.includes(raw) ? raw : undefined // S4c whitelist; invalid → default subagent (fail-soft)
if (raw && !role) log(`⚠️ hmw: agentType "${raw}" ∉ VALID_ROLES → default subagent cho task #${i}`)
const mem = role && memoryPack[role] ? memoryPack[role] : ''
const prompt = [
mem ? `## MEMORY-PACK (${role}) — SLICE ký ức tích lũy của sub này, ĐỌC trước khi làm (KHÔNG phải full memory):\n${mem}\n` : '',
spec ? `## SPEC / acceptance-criteria (chung):\n${spec}\n` : '',
`## TASK:\n${(t && t.prompt) || '(thiếu prompt — lỗi taskList @P0)'}`,
[
'## OUTPUT (structured bắt buộc):',
'- findings: kết quả + evidence file:line (KHÔNG narrative suông).',
'- checklistEvidence: số đo / verdict cho acceptance-checklist.',
'- memoryDelta {task·verdict·learned·surprise}: để EM MAIN harvest @P3.',
'⚠️ KHÔNG ghi ký ức kênh nào: KHÔNG file MEMORY.md, KHÔNG store_memory/RAG-write (Qdrant). CHỈ return memoryDelta → em main VERIFY + APPEND-only @P3 (B3). KHÔNG overwrite file/chunk của sub khác.',
'⚠️ Nếu task có WRITE file: CHỈ file-disjoint được giao (em main git-diff verify sau P2). KHÔNG đụng file ngoài phạm vi. Scope = repo SOLUTION_ERP only (S1).',
].join('\n'),
].filter(Boolean).join('\n')
return agent(prompt, {
agentType: role || undefined,
schema: SCHEMA,
label: (t && t.label) || `hmw:${role || 'task'}-${i}`,
})
}))
// trả mảng kết quả (lọc null nếu agent lỗi/null — invalid-role vẫn chạy default subagent, KHÔNG skip)
// về em main → P3 VERIFY + harvest + P4 checklist
return results.filter(Boolean)