@walwal-harness/cli 5.9.5 → 6.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 ADDED
@@ -0,0 +1,105 @@
1
+ ---
2
+ docmeta:
3
+ id: CHANGELOG
4
+ title: walwal-harness CHANGELOG
5
+ type: output
6
+ createdAt: 2026-05-07T00:00:00Z
7
+ updatedAt: 2026-05-07T00:00:00Z
8
+ source:
9
+ producer: agent
10
+ skillId: harness-release
11
+ inputs:
12
+ - documentId: agency-mapping
13
+ uri: .harness/agency-mapping.md
14
+ relation: output-from
15
+ sections:
16
+ - sourceRange: { startLine: 41, endLine: 53 }
17
+ targetRange: { startLine: 28, endLine: 40 }
18
+ - documentId: doctrine-nexus
19
+ uri: .harness/doctrine/nexus.md
20
+ relation: output-from
21
+ sections:
22
+ - sourceRange: { startLine: 32, endLine: 60 }
23
+ targetRange: { startLine: 41, endLine: 50 }
24
+ - documentId: package
25
+ uri: package.json
26
+ relation: output-from
27
+ tags: [changelog, release-notes, v6.0.0, nexus]
28
+ ---
29
+
30
+ # Changelog
31
+
32
+ ## 6.0.0 — NEXUS-Adapted Company Metaphor (2026-05-07)
33
+
34
+ 회사 메타포로의 전면 전환. 기존 단일 dispatcher/planner/generator/evaluator 라인업을 NEXUS 도큐트린에 따라 7부서 + 14 에이전트 조직도로 재해석했습니다.
35
+
36
+ ### Added
37
+ - **CEO (Dispatcher 격상)** — Owner ↔ 회사 단일 대화 창구. GOAL 협의·escalation 보고.
38
+ - **Conductor** — 자율 실행 엔진. Gen↔Eval 무인 루프.
39
+ - **Meeting-Manager** — 동기화 엔진. 5종 회의(standup/planning/review/all-hands/phase-gate) 적응형 cadence.
40
+ - **COO (Planner)** — Sprint·AC·HR·온보딩 통합.
41
+ - **CTO (Generator 총괄)** — Gen-BE/Gen-FE/Designer/DevOps 4팀 통솔.
42
+ - **CQO (Evaluator 총괄)** — Eval-Functional/Visual/CodeQuality + 신규 Architecture/Security.
43
+ - **Service-Ops** — 운용·모니터·인시던트·자율회고.
44
+ - 신규 14개 SKILL.md (`skills/{conductor,meeting-manager,cto,cqo,service-ops,evaluator-architecture,evaluator-security,generator-designer,generator-devops,...}/SKILL.md`).
45
+ - `.harness/doctrine/nexus.md` — Foundational Principles (P1~P5) + 7 Phase Lifecycle.
46
+ - `.harness/agency-mapping.md` — agency-agents → walwal-harness 매핑 (Phase A 결과).
47
+ - `.harness/memory.md` 기반 공유 학습 시스템 (gotcha 와 분리).
48
+ - Brainstormer 스킬 (obra/superpowers 파생, MIT, Visual Companion 포함).
49
+ - 적응형 ref-docs (`.harness/ref/<role>-<stack>.md`) — 단일 에이전트가 스택별 best-practice 동적 로드.
50
+
51
+ ### Changed
52
+ - `agents` 섹션의 Flutter 변형 (`generator-frontend-flutter` / `evaluator-functional-flutter`) 제거. 단일 에이전트가 `.harness/ref/<role>-<stack>.md` 동적 로드.
53
+ - AGENTS.md IA-MAP — 부서 권한 매트릭스 25항 (이전 12항).
54
+ - progress.json 스키마 v3 — `org/goals/conductor/meetings/cto/cqo/service_ops` 슬롯 추가.
55
+ - Evaluator chain 명시화: `evaluator-code-quality → evaluator-functional → evaluator-visual` (FULLSTACK/FE-ONLY) / `code-quality → functional` (BE-ONLY).
56
+
57
+ ### Removed
58
+ - Flutter "유령 스킬" 참조 ([M-001] resolved). config.json + dispatcher SKILL.md 의 fe_stack_substitution 폐기.
59
+ - 기존 PRE-NEXUS dispatcher 단일 라인업.
60
+ - **Dispatcher 의 Solo/Team 모드 질문**. 사용자 "harness-solo / harness-team 입력하세요" 안내 패턴 제거.
61
+
62
+ ### Mode Decision — User → Conductor 이양 (Breaking)
63
+ - `progress.json.mode` 디폴트 `"solo"` → `"auto"`. version 3 → 4.
64
+ - 신규 필드 `progress.json.mode_decision = { owner, decided_at, rationale, user_override }`.
65
+ - `config.json.mode_selection` 신규 — `force_team_when`(ready≥3 + features≥6 + depth≤2) / `force_solo_when` / tie-breaker=solo.
66
+ - Conductor SKILL §7.5: Planner 의 feature-list 확정 직후 자동 결정. 결정은 progress.json + progress.log 에 rationale 명시.
67
+ - `/harness-solo`, `/harness-team` 은 사용자 override 명령으로 의미 변경. `mode_decision.user_override` 에 기록되어 현재 sprint 종료까지 유지. "auto 로 돌려" 발화로 자동결정 복귀.
68
+ - Dispatcher SKILL §"Mode 결정 위임" — 모드 질문/추천 출력 모두 폐기. 사용자 발화에서 명시적 모드 신호 감지 시만 user_override 로 기록.
69
+
70
+ ### Migration (5.9.x → 6.0.0)
71
+
72
+ 기존 walwal-harness 사용 프로젝트는 `npm install @walwal-harness/cli@latest` 후 다음 한 줄로 자동 마이그레이션 가능:
73
+
74
+ ```bash
75
+ npx walwal-harness migrate --dry-run # 변경 미리보기
76
+ npx walwal-harness migrate # 실제 적용
77
+ ```
78
+
79
+ **자동 처리되는 것**:
80
+ - `progress.json` v3 → v4 — 기존 `mode` 값 (`"solo"` 또는 `"team"`) 을 `mode_decision.user_override` 로 **그대로 보존**. 새 mode 는 `"auto"` 로 셋되지만 user_override 로 직전 sprint 의 사용자 의도 유지.
81
+ - `config.json` 의 `mode_selection` 누락 시 자동 주입 (rules: ready≥3 + features≥6 + depth≤2 → team / 그 외 → solo). 사용자 customization (`behavior`, `flow.pre_eval_gate.*`) 은 **모두 보존**.
82
+ - 변경 전 자동 백업: `.harness/archive/migration-<timestamp>/` (progress.json + config.json 원본).
83
+
84
+ **수동 처리 권장**:
85
+ 1. AGENTS.md 의 IA-MAP 권한 매트릭스 신규 25항 검토.
86
+ 2. 기존 sprint 진행 중이라면 `.harness/archive/` 로 수동 이관 후 새 dispatch 시작.
87
+ 3. `.claude/skills/` 의 신규 14개 부서 SKILL.md 가 정상 설치되었는지 확인 (`ls .claude/skills/` 에 conductor / cto / cqo / meeting-manager / service-ops / evaluator-architecture / evaluator-security 포함).
88
+ 4. Flutter 프로젝트 사용자: `pubspec.yaml` 자동 감지 + `.harness/ref/generator-frontend-flutter.md` (있을 시) 로 동작. 누락 시 Planner 가 ref 생성 권고.
89
+
90
+ **Postinstall 안내**: `npm install` 후 v3 detect 시 안내 banner 가 출력될 수 있으나 npm v9+ 의 quiet mode 에서는 누락될 수 있습니다. 의심 시 `npx walwal-harness migrate --dry-run` 으로 직접 확인하세요.
91
+
92
+ ### Reference
93
+ Phase C "Brick Office 대시보드 MVP" 가 본 v6 organization 기반 첫 풀사이클 검증 (3 sprints, 25 features, 모든 평가 PASS).
94
+
95
+ ## 5.9.6 — Queue Integrity & Lead Guard (이전)
96
+ - queue enqueue/integrity 명령 추가, dashboard orphan 경고, Lead 가드.
97
+
98
+ ## 5.9.5 — Solo/Team Mode Drift Fix
99
+ - progress.json mode drift 시 dashboard/tmux 가 SOLO 로 잘못 표시되던 버그 수정.
100
+
101
+ ## 5.9.4 — Graceful Crash Recovery
102
+ - progress.json 손상 시 dashboard crash → 안내 메시지로 graceful 처리.
103
+
104
+ ## 5.9.3 — Compressed Output Fix
105
+ - 분할 패널에서 Conventions/Memory 가 3 줄만 보이던 압축 출력 수정.
package/README.md CHANGED
@@ -69,25 +69,31 @@ npx walwal-harness team
69
69
  #### 대시보드 구성
70
70
 
71
71
  ```
72
- ┌────────────────────┬──────────────────────────┬───────────┐
73
- │ Dashboard │ Gotcha & Memory │ TEAM 1 │
74
- │ - pipeline/sprint │ - 활성 에이전트 gotcha │ Gen|Eval │
75
- │ - feature 진행도 │ - 나머지 에이전트 요약 ├───────────┤
76
- │ - queue 상태 │ - SHARED MEMORY │ TEAM 2 │
77
- │ │ (memory.md 최근 N) │ Gen|Eval │
78
- ├────────────────────┤ ├───────────┤
79
- │ Archive Prompt │ │ TEAM 3 │
80
- │ (완료 feature 요약)│ │ Gen|Eval │
81
- └────────────────────┴──────────────────────────┴───────────┘
72
+ ┌────────────────────┬───────────────┬───────────┐
73
+ │ Dashboard │ Gotchas │ TEAM 1 │
74
+ │ - pipeline/sprint │ (활성 에이전트)│ Gen|Eval │
75
+ │ - feature 진행도 ├───────────────┤ │
76
+ │ - queue 상태 │ Conventions ├───────────┤
77
+ │ │ (하우스 스타일)│ TEAM 2 │
78
+ ├────────────────────┤ │ Gen|Eval │
79
+ │ Archive Prompt ├───────────────┤ │
80
+ │ (완료 feature 요약)│ Memory ├───────────┤
81
+ │ │ (공유 교훈) │ TEAM 3 │
82
+ │ │ │ Gen|Eval │
83
+ └────────────────────┴───────────────┴───────────┘
82
84
  ```
83
85
 
84
86
  | 패널 | 내용 | 소스 |
85
87
  |------|------|------|
86
88
  | **Dashboard** | Pipeline · Sprint · Feature passes · Queue R:B:P · Retry | `harness-dashboard.sh` |
87
- | **Gotcha & Memory** | 활성 에이전트의 누적 실수 + 나머지 요약 + 공유 메모리 | `harness-gotcha-memory.sh` |
89
+ | **Gotchas** | 활성 에이전트의 누적 실수 (`[G-NNN]`) — v5.9.1 부터 독립 패널 | `harness-gotcha-memory.sh --mode gotcha` |
90
+ | **Conventions** | 하우스 스타일 (`[C-NNN]`) — v5.9.1 부터 독립 패널, 독립 스크롤 | `harness-gotcha-memory.sh --mode conventions` |
91
+ | **Memory** | 공유 교훈 (`memory.md`) — v5.9.1 부터 독립 패널 | `harness-gotcha-memory.sh --mode memory` |
88
92
  | **TEAM 1–3** | 각 워커의 현재 feature · phase(Gen/Eval) · 실시간 stdout | `harness-queue-manager.sh` worker loop |
89
93
  | **Archive Prompt** | 직전 완료 feature 요약 (다음 팀 컨텍스트 주입용) | archive 디렉토리 |
90
94
 
95
+ > **v5.9.1+** Rules 컬럼이 3분할(Gotchas/Conventions/Memory)되어 각각 독립 스크롤됩니다. tmux/iTerm2 모두 동일한 레이아웃을 보장합니다.
96
+
91
97
  ##### Feature 상태 아이콘 (v5.6.4+)
92
98
 
93
99
  | 아이콘 | 상태 | 의미 |
@@ -220,6 +226,16 @@ Dispatcher 자동 분류:
220
226
 
221
227
  → Dispatcher 가 `memory.md` 에 `### [M-NNN] ...` 로 기록. Planner 리뷰 후 `unverified → verified` 로 승격.
222
228
 
229
+ #### 동적 Gotcha/Convention 자동 등록 (v5.9.0+)
230
+
231
+ Worker 가 `gen-report-*.md` / `evaluation-*.md` 본문에 `gotcha_candidates` / `convention_candidates` 블록을 작성하면, Lead 가 PASS merge 직후 자동으로 dedup append:
232
+
233
+ ```bash
234
+ bash scripts/harness-gotcha-register.sh . --scan-all
235
+ ```
236
+
237
+ → 다음 worker spawn 전에 갱신된 gotchas/conventions 가 file system 에 반영. **한 sprint 안에서 발견된 실수를 같은 sprint 의 다음 worker 가 즉시 회피**할 수 있게 됨. Generator 도 mandatory — 모든 에이전트가 후보를 자기 보고서에 남기는 것을 강제합니다.
238
+
223
239
  #### 주의 — 데이터 보존
224
240
 
225
241
  `npm install` postinstall 은 **누적 엔트리(`[G-NNN]` 또는 `[C-NNN]`)가 있는 파일을 절대 덮어쓰지 않습니다**. 스캐폴드 템플릿인 경우에만 갱신됩니다. v5.5.2 이전 버전은 gotchas 에 이 버그가 있었으므로 `5.6.0+` 사용을 권장합니다.
@@ -470,6 +486,13 @@ jq '.mode = "solo"' .harness/progress.json > /tmp/p.json && mv /tmp/p.json .harn
470
486
  - v5.5.2 에서 해결 (postinstall 이 누적 엔트리를 절대 덮어쓰지 않도록 수정).
471
487
  - 반드시 `5.5.2+` 사용.
472
488
 
489
+ ### Dashboard 헤더가 SOLO 인데 실제로는 팀 모드로 돌고 있음
490
+ - v5.9.5 에서 해결. `feature-queue.json.queue.in_progress > 0` 이면 dashboard refresh / tmux 재기동 시 자동으로 `mode=team` 으로 self-heal 합니다.
491
+ - 그 이전 버전: `progress.json` 의 `mode` 만 직접 수정하거나 새 세션을 열어 SessionStart 훅의 heal 을 트리거.
492
+
493
+ ### `progress.json` 손상 시 dashboard crash
494
+ - v5.9.4 에서 해결. invalid JSON 인 경우 안내 메시지로 graceful degrade. 복구 가이드는 dashboard 본문에 inline 표시됩니다.
495
+
473
496
  ---
474
497
 
475
498
  ## License
@@ -342,6 +342,35 @@
342
342
  "auto_route_dispatcher": true,
343
343
  "auto_route_dispatcher_description": "true 이면 사용자의 모든 프롬프트가 harness-dispatcher 경유로 분류/라우팅 된다. 사용자가 'harness skip' 등을 말하면 단일 메시지 한정으로 건너뛴다."
344
344
  },
345
+ "mode_selection": {
346
+ "comment": "v6.0 — Solo/Team 모드를 사용자가 아닌 Conductor 가 결정. progress.json.mode='auto' 일 때 Conductor 가 feature-list 의 ready_count + 의존성 깊이 + sprint feature 수를 보고 룰을 적용. 사용자는 /harness-solo 또는 /harness-team 으로 override 가능하며 그 결정은 progress.json.mode_decision.user_override 에 기록된다.",
347
+ "default_mode": "auto",
348
+ "owner": "conductor",
349
+ "rules": {
350
+ "force_team_when": {
351
+ "ready_at_start_gte": 3,
352
+ "feature_count_gte": 6,
353
+ "critical_path_depth_lte": 2,
354
+ "rationale": "ready≥3 + 작은 critical path = 3팀 동시 가동의 P4 Parallel Workstreams 효과 충족 (NEXUS 40~60% 단축)"
355
+ },
356
+ "force_solo_when": {
357
+ "ready_at_start_lte": 2,
358
+ "or_feature_count_lte": 3,
359
+ "or_critical_path_depth_gte": 4,
360
+ "rationale": "직렬 의존 우세 → Team 으로 띄워도 2팀이 유휴. tmux 운영 비용·토큰 3x 정당화 안 됨."
361
+ },
362
+ "tie_breaker": "solo",
363
+ "tie_breaker_rationale": "동률 시 비용 안전한 Solo 선호. 사용자가 명시적으로 team 선택 시만 force."
364
+ },
365
+ "user_override": {
366
+ "comment": "사용자가 명시적으로 모드 강제하면 Conductor 결정 무시. progress.json.mode_decision.user_override 에 기록.",
367
+ "channels": [
368
+ "/harness-solo (force solo)",
369
+ "/harness-team (force team)",
370
+ "사용자 발화: 'solo 로', 'team 으로', 'auto 다시' (auto 복귀)"
371
+ ]
372
+ }
373
+ },
345
374
  "paths": {
346
375
  "actions": ".harness/actions",
347
376
  "archive": ".harness/archive",
@@ -1,6 +1,12 @@
1
1
  {
2
- "version": 3,
3
- "mode": "solo",
2
+ "version": 4,
3
+ "mode": "auto",
4
+ "mode_decision": {
5
+ "owner": "conductor",
6
+ "decided_at": null,
7
+ "rationale": null,
8
+ "user_override": null
9
+ },
4
10
  "project_name": "",
5
11
  "pipeline": null,
6
12
  "dispatch": {
package/bin/init.js CHANGED
@@ -904,16 +904,19 @@ function showHelp() {
904
904
  ╚══════════════════════════════════════╝
905
905
 
906
906
  Usage:
907
- npx walwal-harness Initialize project for harness engineering
908
- npx walwal-harness --force Re-initialize (overwrites existing files)
909
- npx walwal-harness team Launch Team Mode (tmux studio + auto teams)
910
- npx walwal-harness team --kill Kill Team Mode tmux session
911
- npx walwal-harness --help Show this help
912
-
913
- Modes (use inside claude/codex session):
914
- /harness-solo Solo mode — prompting-based sequential pipeline
915
- /harness-team Team mode — auto parallel Gen-Eval loop (3 teams)
907
+ npx walwal-harness Initialize project for harness engineering
908
+ npx walwal-harness --force Re-initialize (overwrites existing files)
909
+ npx walwal-harness team Launch Team Mode (tmux studio + auto teams)
910
+ npx walwal-harness team --kill Kill Team Mode tmux session
911
+ npx walwal-harness migrate Apply v3 → v4 migration (mode→auto + Conductor)
912
+ npx walwal-harness migrate --dry-run Preview migration changes without applying
913
+ npx walwal-harness --help Show this help
914
+
915
+ Modes (v6.0+ — Conductor 자동 결정, 사용자 override 가능):
916
+ /harness-solo Solo Override — Conductor 결정을 Solo 로 강제
917
+ /harness-team Team Override — Conductor 결정을 Team 으로 강제 (tmux 부팅)
916
918
  /harness-stop Stop Team mode (preserves queue state)
919
+ 발화 "auto 로 돌려" → Conductor 자동결정 복귀
917
920
 
918
921
  What it does:
919
922
  1. Scaffolds .harness/ directory (actions, archive, gotchas, config)
@@ -965,6 +968,120 @@ function runTeamStudio() {
965
968
  execSync(cmd, { stdio: 'inherit' });
966
969
  }
967
970
 
971
+ // ─────────────────────────────────────────
972
+ // Migration — v3 → v4 (mode auto + Conductor ownership)
973
+ // ─────────────────────────────────────────
974
+ const TARGET_PROGRESS_VERSION = 4;
975
+
976
+ function detectMigrationNeeded() {
977
+ const progressPath = path.join(HARNESS_DIR, 'progress.json');
978
+ const configPath = path.join(HARNESS_DIR, 'config.json');
979
+ const flags = { progressV3toV4: false, configMissingModeSelection: false };
980
+ if (fs.existsSync(progressPath)) {
981
+ try {
982
+ const p = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
983
+ if ((p.version ?? 0) < TARGET_PROGRESS_VERSION) flags.progressV3toV4 = true;
984
+ } catch {}
985
+ }
986
+ if (fs.existsSync(configPath)) {
987
+ try {
988
+ const c = JSON.parse(fs.readFileSync(configPath, 'utf8'));
989
+ if (!c.mode_selection) flags.configMissingModeSelection = true;
990
+ } catch {}
991
+ }
992
+ return flags;
993
+ }
994
+
995
+ function showMigrationProposal(flags) {
996
+ console.log('');
997
+ console.log('╔══════════════════════════════════════════════════════════╗');
998
+ console.log('║ walwal-harness v6 — 자동 마이그레이션 사용 가능 ║');
999
+ console.log('╚══════════════════════════════════════════════════════════╝');
1000
+ if (flags.progressV3toV4) {
1001
+ console.log(' • progress.json: v3 → v4 (mode → "auto" + mode_decision 추가)');
1002
+ console.log(' 기존 mode 값은 user_override 로 보존됩니다.');
1003
+ }
1004
+ if (flags.configMissingModeSelection) {
1005
+ console.log(' • config.json: mode_selection 섹션 누락 — 자동 주입 가능');
1006
+ console.log(' Conductor 가 ready≥3 + features≥6 + depth≤2 로 자동 모드 결정.');
1007
+ }
1008
+ console.log('');
1009
+ console.log(' 적용: npx walwal-harness migrate');
1010
+ console.log(' 미리보기: npx walwal-harness migrate --dry-run');
1011
+ console.log('');
1012
+ console.log(' ※ 자동 강제 X — 사용자가 명령을 실행할 때만 변경됩니다.');
1013
+ console.log(' ※ 변경 전 .harness/archive/migration-<ts>/ 에 자동 백업.');
1014
+ console.log('');
1015
+ }
1016
+
1017
+ function runMigrate(opts = {}) {
1018
+ const dryRun = opts.dryRun || false;
1019
+ const flags = detectMigrationNeeded();
1020
+ if (!flags.progressV3toV4 && !flags.configMissingModeSelection) {
1021
+ console.log('');
1022
+ log('이미 최신 버전입니다 (progress.json v' + TARGET_PROGRESS_VERSION + ' + config.json mode_selection 존재).');
1023
+ return;
1024
+ }
1025
+
1026
+ console.log('');
1027
+ log(dryRun ? '=== DRY RUN — 실제 변경 없음 ===' : '=== Migration 적용 ===');
1028
+
1029
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
1030
+ const backupDir = path.join(HARNESS_DIR, 'archive', `migration-${ts}`);
1031
+ if (!dryRun) ensureDir(backupDir);
1032
+
1033
+ // 1. progress.json
1034
+ const progressPath = path.join(HARNESS_DIR, 'progress.json');
1035
+ if (flags.progressV3toV4 && fs.existsSync(progressPath)) {
1036
+ const original = fs.readFileSync(progressPath, 'utf8');
1037
+ const p = JSON.parse(original);
1038
+ const oldMode = p.mode ?? 'solo';
1039
+ const newP = {
1040
+ ...p,
1041
+ version: TARGET_PROGRESS_VERSION,
1042
+ mode: 'auto',
1043
+ mode_decision: {
1044
+ owner: 'conductor',
1045
+ decided_at: null,
1046
+ rationale: `migration v3→v4 — 기존 mode="${oldMode}" 를 user_override 로 보존`,
1047
+ user_override: oldMode === 'team' || oldMode === 'solo' ? oldMode : null,
1048
+ },
1049
+ };
1050
+ log(` progress.json: version 3 → ${TARGET_PROGRESS_VERSION}, mode "${oldMode}" → "auto" (user_override="${newP.mode_decision.user_override}")`);
1051
+ if (!dryRun) {
1052
+ fs.writeFileSync(path.join(backupDir, 'progress.json'), original);
1053
+ fs.writeFileSync(progressPath, JSON.stringify(newP, null, 2) + '\n');
1054
+ }
1055
+ }
1056
+
1057
+ // 2. config.json — inject mode_selection from template if missing
1058
+ const configPath = path.join(HARNESS_DIR, 'config.json');
1059
+ const tplPath = path.join(PKG_ROOT, 'assets', 'templates', 'config.json');
1060
+ if (flags.configMissingModeSelection && fs.existsSync(configPath) && fs.existsSync(tplPath)) {
1061
+ const original = fs.readFileSync(configPath, 'utf8');
1062
+ const c = JSON.parse(original);
1063
+ const tpl = JSON.parse(fs.readFileSync(tplPath, 'utf8'));
1064
+ if (tpl.mode_selection) {
1065
+ c.mode_selection = tpl.mode_selection;
1066
+ log(' config.json: mode_selection 섹션 주입 (default_mode=auto, owner=conductor, force_team_when ready≥3+features≥6+depth≤2, tie_breaker=solo)');
1067
+ if (!dryRun) {
1068
+ fs.writeFileSync(path.join(backupDir, 'config.json'), original);
1069
+ fs.writeFileSync(configPath, JSON.stringify(c, null, 2) + '\n');
1070
+ }
1071
+ }
1072
+ }
1073
+
1074
+ console.log('');
1075
+ if (dryRun) {
1076
+ log('Dry-run 완료 — 실제 변경 적용하려면 `npx walwal-harness migrate` 실행');
1077
+ } else {
1078
+ log(`Migration 완료. 백업: ${backupDir}`);
1079
+ log('Conductor 가 다음 sprint 시작 시 자동으로 모드 결정합니다.');
1080
+ log('자동 결정 무시하려면 /harness-solo 또는 /harness-team override.');
1081
+ }
1082
+ console.log('');
1083
+ }
1084
+
968
1085
  function main() {
969
1086
  if (isHelp) {
970
1087
  showHelp();
@@ -976,6 +1093,11 @@ function main() {
976
1093
  return;
977
1094
  }
978
1095
 
1096
+ if (subcommand === 'migrate') {
1097
+ runMigrate({ dryRun: args.includes('--dry-run') });
1098
+ return;
1099
+ }
1100
+
979
1101
  // Legacy subcommands — redirect to new equivalents
980
1102
  if (subcommand === 'studio' || subcommand === 'studio-v4' || subcommand === 'v4') {
981
1103
  log('NOTE: "studio" and "v4" subcommands are replaced by "team".');
@@ -1006,6 +1128,22 @@ function main() {
1006
1128
  checkPlaywrightMcp();
1007
1129
  checkRecommendedSkills();
1008
1130
 
1131
+ // v6.0 — propose migration if existing project is on v3
1132
+ const migFlags = detectMigrationNeeded();
1133
+ if (migFlags.progressV3toV4 || migFlags.configMissingModeSelection) {
1134
+ showMigrationProposal(migFlags);
1135
+ }
1136
+
1137
+ // v6.0 — Brick Office dashboard one-liner
1138
+ console.log('');
1139
+ console.log('╔══════════════════════════════════════════════════════════╗');
1140
+ console.log('║ Brick Office — 라이브 운영 대시보드 (선택) ║');
1141
+ console.log('╚══════════════════════════════════════════════════════════╝');
1142
+ console.log(' bash scripts/harness-dashboard-up.sh');
1143
+ console.log(' → http://localhost:3001 에서 .harness/ 상태 실시간 시각화');
1144
+ console.log(' → 첫 실행 시 git sparse-checkout 으로 ~5MB 만 가져옵니다.');
1145
+ console.log('');
1146
+
1009
1147
  console.log('');
1010
1148
  log('═══ Initialization Complete ═══');
1011
1149
  log('');
@@ -32,7 +32,9 @@ bash scripts/harness-next.sh .
32
32
  - 에스컬레이션 체크 (3회 실패 시 → Planner)
33
33
  - 마지막 에이전트면 자동 archive 실행
34
34
 
35
- ### Step 2: handoff.json 읽고 다음 에이전트 호출
35
+ ### Step 2: handoff.json 읽고 다음 에이전트 **즉시 호출** (필수)
36
+
37
+ > **중요**: Step 1 완료 후 사용자에게 "다음 단계를 실행하시겠습니까?" 같은 추가 확인을 받지 마세요. 사용자가 이미 `/harness-next`를 호출한 시점에 다음 단계 실행에 동의한 것으로 간주합니다. 곧바로 Skill 도구로 `to` 필드의 스킬을 호출하세요.
36
38
 
37
39
  ```bash
38
40
  cat .harness/handoff.json | jq '{from, to, sprint, prompt, model, thinking_mode, failure_context}'
@@ -4,15 +4,31 @@ docmeta:
4
4
  title: /harness-solo — Solo Mode 시작/전환
5
5
  type: input
6
6
  createdAt: 2026-04-20T00:00:00Z
7
- updatedAt: 2026-04-27T00:00:00Z
7
+ updatedAt: 2026-05-07T00:00:00Z
8
8
  source:
9
9
  producer: user
10
10
  skillId: harness
11
- inputs: []
12
- tags: [harness, solo-mode, command]
11
+ inputs:
12
+ - documentId: skill-conductor
13
+ uri: ../skills/conductor/SKILL.md
14
+ relation: output-from
15
+ sections:
16
+ - sourceRange: { startLine: 115, endLine: 145 } # §7.5 모드 결정 위임 룰 + user_override 채널
17
+ targetRange: { startLine: 17, endLine: 22 } # 본 명령의 v6.0 override 안내 블록
18
+ - documentId: config-template
19
+ uri: ../assets/templates/config.json
20
+ relation: output-from
21
+ sections:
22
+ - sourceRange: { startLine: 345, endLine: 372 } # mode_selection 룰 (force_solo_when 등)
23
+ targetRange: { startLine: 17, endLine: 22 }
24
+ tags: [harness, solo-mode, command, override, v6]
13
25
  ---
14
26
 
15
- # /harness-solo — Solo Mode 시작/전환
27
+ # /harness-solo — Solo Mode 사용자 Override (v6.0+)
28
+
29
+ > v6.0 부터 모드 결정은 **Conductor 가 자동**으로 합니다 (config.json `mode_selection.rules`). 본 명령은 Conductor 의 자동 결정을 사용자가 강제로 덮어쓰는 **override** 입니다.
30
+ >
31
+ > **효과**: `progress.json.mode = "solo"` 강제 + `mode_decision.user_override = "solo"` 기록. 현재 sprint 끝까지 유지. 다음 sprint 진입 시 Conductor 가 재자동결정. **Auto 복귀**: 사용자 발화 "auto 로 돌려" 또는 "Conductor 결정으로".
16
32
 
17
33
  프롬프트 기반으로 하네스 파이프라인을 순차 진행합니다.
18
34
  Team 모드에서 전환 시, 진행 중이던 피처의 상태를 보존하고 Solo로 이어갑니다.
@@ -1,18 +1,34 @@
1
1
  ---
2
2
  docmeta:
3
3
  id: harness-team
4
- title: /harness-team — Team Mode 시작/재개
4
+ title: /harness-team — Team Mode 사용자 Override (v6.0+)
5
5
  type: input
6
6
  createdAt: 2026-04-20T00:00:00Z
7
- updatedAt: 2026-04-20T00:00:00Z
7
+ updatedAt: 2026-05-07T00:00:00Z
8
8
  source:
9
9
  producer: user
10
10
  skillId: harness
11
- inputs: []
12
- tags: [harness, team-mode, tmux, command]
11
+ inputs:
12
+ - documentId: skill-conductor
13
+ uri: ../skills/conductor/SKILL.md
14
+ relation: output-from
15
+ sections:
16
+ - sourceRange: { startLine: 115, endLine: 145 } # §7.5 모드 결정 + user_override
17
+ targetRange: { startLine: 17, endLine: 22 }
18
+ - documentId: config-template
19
+ uri: ../assets/templates/config.json
20
+ relation: output-from
21
+ sections:
22
+ - sourceRange: { startLine: 345, endLine: 372 } # mode_selection.rules.force_team_when
23
+ targetRange: { startLine: 17, endLine: 22 }
24
+ tags: [harness, team-mode, tmux, command, override, v6]
13
25
  ---
14
26
 
15
- # /harness-team — Team Mode 시작/재개
27
+ # /harness-team — Team Mode 사용자 Override (v6.0+)
28
+
29
+ > v6.0 부터 모드 결정은 **Conductor 가 자동**으로 합니다 (config.json `mode_selection.rules.force_team_when`: ready≥3 + features≥6 + critical_path_depth≤2). 본 명령은 Conductor 의 자동 결정을 사용자가 강제로 덮어쓰는 **override** 입니다.
30
+ >
31
+ > **효과**: `progress.json.mode = "team"` 강제 + `mode_decision.user_override = "team"` 기록 + tmux 세션 부팅. 현재 sprint 끝까지 유지. 다음 sprint 진입 시 Conductor 가 재자동결정. **Auto 복귀**: 사용자 발화 "auto 로 돌려" 또는 "Conductor 결정으로".
16
32
 
17
33
  Planner가 완료한 feature-list.json의 피처들을 최대 3개 팀이 병렬로 Gen→Eval 사이클을 수행합니다.
18
34
 
@@ -447,6 +463,46 @@ Lead에게 반환 **첫 줄에 반드시 `RATE_LIMIT` 태그 포함**:
447
463
 
448
464
  ---
449
465
 
466
+ ## Ad-hoc Feature 추가 — Canonical Path (필수)
467
+
468
+ Lead 가 sprint 진행 중 핫픽스 / 새 sprint feature 를 추가해야 할 때 **`feature-queue.json` 을 jq 로 직접 편집하면 안 된다**. feature-list.json 과 큐가 갈라져서 dashboard 가 누락 표시하고, Planner/Evaluator 가 AC 를 찾지 못한다.
469
+
470
+ **금지**:
471
+ ```bash
472
+ # ❌ 절대 금지 — feature-list 우회
473
+ jq '.queue.ready += ["F-XXX"]' .harness/actions/feature-queue.json > /tmp/q.json && mv /tmp/q.json .harness/actions/feature-queue.json
474
+ ```
475
+
476
+ **Canonical**:
477
+ ```bash
478
+ # ✅ 옵션 1 — 새 sprint 의 정식 feature 들이면 Planner 재호출
479
+ # Planner 가 feature-list.json 에 sprint=N 으로 append → next-sprint 가 큐 채움.
480
+
481
+ # ✅ 옵션 2 — 단발 핫픽스면 enqueue 명령 사용 (feature-list append + 큐 insert 원자적)
482
+ cat > /tmp/feat.json <<EOF
483
+ {
484
+ "id": "F-XXX",
485
+ "title": "auth refresh token lifecycle hotfix",
486
+ "sprint": 8,
487
+ "depends_on": [],
488
+ "layer": "fe",
489
+ "service": "frontend",
490
+ "acceptance_criteria": [{"id":"AC-1","description":"...","type":"manual","verify":{"tool":"grep","steps":["..."]}}]
491
+ }
492
+ EOF
493
+ bash scripts/harness-queue-manager.sh enqueue /tmp/feat.json
494
+ ```
495
+
496
+ **무결성 체크** (Lead 루프 진입 직전 권장):
497
+ ```bash
498
+ bash scripts/harness-queue-manager.sh integrity
499
+ # 종료 코드 0 = OK, 1 = orphan feature 발견 (feature-list 에 없는 queue 항목)
500
+ ```
501
+
502
+ 이 룰을 위반한 사례: Sprint 8 (2026-04-29) 에 F-716, F-800~F-806 이 jq 직접 편집으로 큐에만 등록되어 dashboard Features 패널에서 800 번대가 모두 누락된 적 있음. **dashboard 는 v5.9.6+ 에서 union 렌더 + orphan 경고로 가시화하지만, 가시화는 차단이 아님 — Lead 가 위 canonical path 만 쓸 것**.
503
+
504
+ ---
505
+
450
506
  ## 핵심 원칙
451
507
 
452
508
  ### Worker = 1 Feature Only
@@ -0,0 +1,85 @@
1
+ ---
2
+ docmeta:
3
+ id: gotchas-generator-backend-laravel
4
+ title: Generator-Backend Gotchas — Laravel/Livewire/Filament
5
+ type: output
6
+ createdAt: 2026-05-07T00:00:00Z
7
+ updatedAt: 2026-05-07T00:00:00Z
8
+ source:
9
+ producer: agent
10
+ skillId: harness-planner
11
+ inputs:
12
+ - documentId: agency-agents-engineering
13
+ uri: https://github.com/msitarzewski/agency-agents
14
+ relation: output-from
15
+ sections:
16
+ - sourceRange: { startLine: 1, endLine: 1 }
17
+ targetRange: { startLine: 1, endLine: 999 }
18
+ tags: [gotcha, generator-backend, laravel, livewire, filament, phase-b]
19
+ ---
20
+
21
+ <!-- Source: https://github.com/msitarzewski/agency-agents (MIT) -->
22
+
23
+ # Generator-Backend Gotchas — Laravel/Livewire/Filament
24
+
25
+ > 스택별 가드. 공통 가드는 `gotchas/generator-backend.md` 참조.
26
+ > 모든 항목은 `unverified` 상태로 시작, Planner 리뷰 후 `verified` 승격.
27
+
28
+ ## verified
29
+
30
+ (없음 — 첫 리비전)
31
+
32
+ ## unverified
33
+
34
+ ### G-LV-001 — Livewire 컴포넌트가 Eloquent 모델을 prop으로 받을 때 직렬화 충돌
35
+ - **언제**: 부모 컴포넌트 → 자식 컴포넌트로 모델을 직접 props 전달
36
+ - **증상**: 새 요청마다 모델 hydrate 실패, lazy load 시 fresh 로드되어 데이터 불일치
37
+ - **회피**: ID만 전달 + 자식이 자기 책임으로 fetch, 또는 `serializeable=true` 명시 + 변경 위험 인지
38
+
39
+ ### G-LV-002 — `wire:model.live` 무차별 사용으로 N+1 트래픽 폭발
40
+ - **증상**: 입력 1자마다 서버 왕복, 운영에서 큐 폭주
41
+ - **회피**: 폼 입력 default `wire:model.live.debounce.500ms` 또는 `wire:model.lazy`
42
+
43
+ ### G-FL-001 — Filament Resource `eagerLoad()` 누락
44
+ - **증상**: 인덱스 페이지 1회 로드에 컬럼 수 × 행 수 만큼 쿼리 (N+1)
45
+ - **회피**: Resource에 `protected $eagerLoadRelations = ['user', 'category']` 명시. Eval-Architecture가 검출.
46
+
47
+ ### G-FL-002 — Filament Tenancy panel에서 Global scope 누락
48
+ - **증상**: 한 테넌트 사용자가 다른 테넌트 데이터 노출
49
+ - **회피**: `getEloquentQuery()` 오버라이드 시 `parent::getEloquentQuery()` 후 scope 추가. Eval-Security 적발.
50
+
51
+ ### G-EL-001 — `whereHas` 다단 사용으로 인덱스 미사용 쿼리
52
+ - **증상**: relation 깊이 ≥ 2 + 결과 set 크면 secs 단위
53
+ - **회피**: subquery 또는 `whereIn(select 1 column)` 패턴, EXPLAIN 첨부
54
+
55
+ ### G-EL-002 — Mass assignment 누락 → 권한 우회
56
+ - **증상**: 사용자가 `is_admin` 같은 컬럼을 요청 본문에 끼워 권한 상승
57
+ - **회피**: 모든 모델 `$fillable` 또는 `$guarded = []` 의도 명시. Eval-Security CRITICAL.
58
+
59
+ ### G-MIG-001 — 인덱스 없는 외래키 컬럼
60
+ - **증상**: parent delete 시 child scan 풀스캔
61
+ - **회피**: 마이그레이션에서 `foreignId(...)->index()` 명시
62
+
63
+ ### G-JOB-001 — Job 안에서 retry 비대응 외부 호출
64
+ - **증상**: Stripe·외부 API 호출이 retry 시 중복 결제·중복 메시지
65
+ - **회피**: idempotency_key 또는 `ShouldBeUnique`. Eval-Security 검토.
66
+
67
+ ### G-CACHE-001 — `Cache::tags()` on file driver
68
+ - **증상**: 운영에서 silent fail (tag 무시)
69
+ - **회피**: prod cache driver는 redis 강제. config/cache.php boot 시 검증.
70
+
71
+ ### G-AUTH-001 — Sanctum 토큰 회전 정책 부재
72
+ - **증상**: 토큰 영구 유효 → 누출 시 영향 무한대
73
+ - **회피**: TTL + 사용 흐름별 ability 분리, 회전 명령 정의 (DevOps와 연계)
74
+
75
+ ### G-OBS-001 — observer chain → 부작용 폭발
76
+ - **증상**: User saving → Profile observer → Account observer → 무한 루프 또는 dead-lock
77
+ - **회피**: observer 안에서 다른 모델 save 금지 룰. 명시적 Action 호출로 대체.
78
+
79
+ ### G-FORM-001 — `$request->validate()` 인라인 사용
80
+ - **증상**: 검증 룰 재사용·테스트·문서화 모두 어려움
81
+ - **회피**: FormRequest 클래스 강제. Eval-CodeQuality lint 룰.
82
+
83
+ ### G-PERF-001 — Telescope prod 활성
84
+ - **증상**: 모든 쿼리·요청 적재 → DB 비대 + 보안 노출
85
+ - **회피**: env 분리, prod에서 `TelescopeServiceProvider` 등록 차단. Eval-Security 적발.