@walwal-harness/cli 6.1.2 → 6.1.3
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 +21 -0
- package/README.md +4 -2
- package/gotchas/README.md +40 -8
- package/gotchas/conductor.md +12 -82
- package/gotchas/coo-developer.md +21 -12
- package/gotchas/cqo.md +22 -0
- package/gotchas/cto.md +22 -0
- package/gotchas/dispatcher.md +12 -87
- package/gotchas/documentationer.md +21 -12
- package/gotchas/evaluator-architecture.md +22 -0
- package/gotchas/evaluator-code-quality.md +11 -20
- package/gotchas/evaluator-functional.md +10 -30
- package/gotchas/evaluator-security.md +22 -0
- package/gotchas/evaluator-visual.md +10 -19
- package/gotchas/generator-backend-laravel.md +11 -77
- package/gotchas/generator-backend.md +19 -2
- package/gotchas/generator-designer.md +22 -0
- package/gotchas/generator-devops.md +22 -0
- package/gotchas/generator-frontend.md +13 -22
- package/gotchas/meeting-manager.md +22 -0
- package/gotchas/planner.md +19 -2
- package/gotchas/service-ops.md +13 -18
- package/package.json +1 -1
- package/scripts/conductor-tick.sh +167 -21
- package/scripts/harness-meeting-doc.sh +146 -2
- package/scripts/harness-session-start.sh +7 -0
- package/scripts/lib/harness-progress-migrate.sh +58 -0
- package/skills/conductor/SKILL.md +1 -0
- package/skills/coo-developer/SKILL.md +35 -5
- package/skills/documentationer/SKILL.md +55 -9
- package/skills/meeting-manager/SKILL.md +114 -4
- package/skills/planner/SKILL.md +45 -0
|
@@ -21,6 +21,13 @@ ops_report=$(jq -r '.service_ops.auto_retro.last_report // empty' "$PROGRESS")
|
|
|
21
21
|
cqo_audit=$(jq -r '.cqo.audit_path // empty' "$PROGRESS")
|
|
22
22
|
cto_review=$(jq -r '.cto.review_path // empty' "$PROGRESS")
|
|
23
23
|
current_path=$(jq -r '.meetings.current_record_path // empty' "$PROGRESS")
|
|
24
|
+
# v6.2 — parallel tracks hints (set by conductor before convene). length >= 2 = fork.
|
|
25
|
+
requested_tracks=$(jq -c '.meetings.requested_tracks // []' "$PROGRESS")
|
|
26
|
+
requested_rendezvous=$(jq -c '.meetings.requested_rendezvous // null' "$PROGRESS")
|
|
27
|
+
fork_context=$(jq -c '.meetings.fork_context // null' "$PROGRESS")
|
|
28
|
+
fallback_fork_meeting_id=$(jq -r '.meetings.fork_meeting_id // .conductor.fork_meeting_id // ""' "$PROGRESS")
|
|
29
|
+
fallback_conductor_tracks=$(jq -c '.conductor.tracks // []' "$PROGRESS")
|
|
30
|
+
fallback_decision_tracks=$(jq -c '.meetings.decision.tracks // []' "$PROGRESS")
|
|
24
31
|
|
|
25
32
|
default_decision_json() {
|
|
26
33
|
local owner="planner"
|
|
@@ -35,6 +42,33 @@ default_decision_json() {
|
|
|
35
42
|
owner="planner"
|
|
36
43
|
action_type="goal-alignment"
|
|
37
44
|
fi
|
|
45
|
+
|
|
46
|
+
# v6.2 — Tracks 가 단일 진실: length >= 2 → fork-join, length == 1 → single.
|
|
47
|
+
# legacy {owner, action_type} 만 들어와도 1-element tracks[] 로 합성.
|
|
48
|
+
local tracks_json="[]"
|
|
49
|
+
local rendezvous_json="null"
|
|
50
|
+
if [ "$(jq 'length' <<<"$requested_tracks")" -gt 1 ]; then
|
|
51
|
+
tracks_json=$(jq -c '
|
|
52
|
+
[ to_entries[] | (.value + {
|
|
53
|
+
id: ((.value.id // null) // ("track-" + ((.key + 1) | tostring))),
|
|
54
|
+
deliverable: (.value.deliverable // "report"),
|
|
55
|
+
deliverable_path: (.value.deliverable_path // null),
|
|
56
|
+
status: (.value.status // "pending")
|
|
57
|
+
})
|
|
58
|
+
]
|
|
59
|
+
' <<<"$requested_tracks")
|
|
60
|
+
rendezvous_json=$(jq -c '. // {type:"followup-review", when:"next_cadence"}' <<<"$requested_rendezvous")
|
|
61
|
+
# primary owner = first track owner (편의 미러)
|
|
62
|
+
owner=$(jq -r '.[0].owner // "planner"' <<<"$tracks_json")
|
|
63
|
+
action_type=$(jq -r '.[0].action_type // "triage"' <<<"$tracks_json")
|
|
64
|
+
else
|
|
65
|
+
# single — derive a 1-element tracks[] (backward compat 도 동시에 처리)
|
|
66
|
+
tracks_json=$(jq -c -n \
|
|
67
|
+
--arg owner "$owner" \
|
|
68
|
+
--arg action_type "$action_type" \
|
|
69
|
+
'[ {id:"track-1", owner:$owner, action_type:$action_type, deliverable:"report", deliverable_path:null, status:"pending"} ]')
|
|
70
|
+
fi
|
|
71
|
+
|
|
38
72
|
jq -n \
|
|
39
73
|
--arg owner "$owner" \
|
|
40
74
|
--arg action_type "$action_type" \
|
|
@@ -42,7 +76,9 @@ default_decision_json() {
|
|
|
42
76
|
--arg drift_classification "$1" \
|
|
43
77
|
--arg ops_report "$ops_report" \
|
|
44
78
|
--arg cqo_audit "$cqo_audit" \
|
|
45
|
-
--arg cto_review "$cto_review"
|
|
79
|
+
--arg cto_review "$cto_review" \
|
|
80
|
+
--argjson tracks "$tracks_json" \
|
|
81
|
+
--argjson rendezvous "$rendezvous_json" '
|
|
46
82
|
{
|
|
47
83
|
owner: $owner,
|
|
48
84
|
action_type: $action_type,
|
|
@@ -54,26 +90,70 @@ default_decision_json() {
|
|
|
54
90
|
(if $cto_review != "" then {source:$cto_review, kind:"cto-review"} else empty end)
|
|
55
91
|
]
|
|
56
92
|
),
|
|
57
|
-
drift_classification: $drift_classification
|
|
93
|
+
drift_classification: $drift_classification,
|
|
94
|
+
tracks: $tracks,
|
|
95
|
+
rendezvous: $rendezvous
|
|
58
96
|
}'
|
|
59
97
|
}
|
|
60
98
|
|
|
99
|
+
resolve_followup_fork_context() {
|
|
100
|
+
local resolved="$fork_context"
|
|
101
|
+
if [ "$requested_type" != "followup-review" ]; then
|
|
102
|
+
echo "$resolved"
|
|
103
|
+
return
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if [ "$resolved" != "null" ] && [ -n "$resolved" ]; then
|
|
107
|
+
echo "$resolved"
|
|
108
|
+
return
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
local fallback_tracks="$fallback_conductor_tracks"
|
|
112
|
+
if [ "$(jq 'length' <<<"$fallback_tracks")" -eq 0 ] && [ "$(jq 'length' <<<"$fallback_decision_tracks")" -gt 0 ]; then
|
|
113
|
+
fallback_tracks="$fallback_decision_tracks"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [ "$(jq 'length' <<<"$fallback_tracks")" -eq 0 ]; then
|
|
117
|
+
echo "null"
|
|
118
|
+
return
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
jq -c -n \
|
|
122
|
+
--arg fork_meeting_id "$fallback_fork_meeting_id" \
|
|
123
|
+
--argjson prior_tracks "$fallback_tracks" \
|
|
124
|
+
'{fork_meeting_id:$fork_meeting_id, prior_tracks:$prior_tracks, sealed_at:(now | todate)}'
|
|
125
|
+
}
|
|
126
|
+
|
|
61
127
|
if [ "$MODE" = "prepare" ]; then
|
|
62
128
|
meeting_id="M-$(date -u +%Y%m%dT%H%M%SZ)"
|
|
63
129
|
meeting_dir="$MEETINGS_ROOT/$meeting_id"
|
|
64
130
|
mkdir -p "$meeting_dir"
|
|
65
131
|
record="$meeting_dir/meeting-$meeting_id.md"
|
|
66
132
|
|
|
133
|
+
# v6.2 — Notice surfaces tracks/rendezvous for visibility (length >= 2 = fork)
|
|
134
|
+
tracks_summary="(single owner)"
|
|
135
|
+
rendezvous_summary="-"
|
|
136
|
+
is_fork="false"
|
|
137
|
+
if [ "$(jq 'length' <<<"$requested_tracks")" -gt 1 ]; then
|
|
138
|
+
is_fork="true"
|
|
139
|
+
tracks_summary=$(jq -r '[.[] | "\(.id // "?"):\(.owner)/\(.action_type)→\(.deliverable // "report")"] | join(", ")' <<<"$requested_tracks")
|
|
140
|
+
rendezvous_summary=$(jq -r '"\(.type // "followup-review")@\(.when // "next_cadence")"' <<<"$requested_rendezvous")
|
|
141
|
+
fi
|
|
67
142
|
cat > "$meeting_dir/notice.md" <<EOF
|
|
68
143
|
# Notice — $meeting_id
|
|
69
144
|
|
|
70
145
|
- type: $requested_type
|
|
71
146
|
- reason: $requested_reason
|
|
72
147
|
- goal_adherence: $goal_adherence
|
|
148
|
+
- fork: $is_fork
|
|
149
|
+
- tracks: $tracks_summary
|
|
150
|
+
- rendezvous: $rendezvous_summary
|
|
73
151
|
|
|
74
152
|
## Request
|
|
75
153
|
"$requested_reason" 요청이 접수되었습니다. 참석자들은 각자의 전문 시각에서 사실·증거를 제출하고,
|
|
76
154
|
다음 owner와 action_type을 evidence 중심으로 결정하십시오.
|
|
155
|
+
|
|
156
|
+
> **Parallel tracks (v6.2)**: \`tracks[]\` 의 길이 ≥ 2 면 fork-join. \`rendezvous\` 시점에 followup-review 로 합쳐집니다. 단일 트랙 회의는 기존과 동일하게 동작합니다.
|
|
77
157
|
EOF
|
|
78
158
|
|
|
79
159
|
cat > "$meeting_dir/prep-dispatcher.md" <<'EOF'
|
|
@@ -108,6 +188,26 @@ EOF
|
|
|
108
188
|
EOF
|
|
109
189
|
|
|
110
190
|
decision_json="$(default_decision_json "$drift")"
|
|
191
|
+
|
|
192
|
+
# v6.2 — followup-review: surface prior_tracks + fork_meeting_id from fork_context
|
|
193
|
+
resolved_fork_context="$(resolve_followup_fork_context)"
|
|
194
|
+
|
|
195
|
+
fork_section=""
|
|
196
|
+
if [ "$requested_type" = "followup-review" ] && [ "$resolved_fork_context" != "null" ] && [ -n "$resolved_fork_context" ]; then
|
|
197
|
+
fork_id=$(jq -r '.fork_meeting_id // ""' <<<"$resolved_fork_context")
|
|
198
|
+
fork_section="
|
|
199
|
+
|
|
200
|
+
## Fork Context (v6.2)
|
|
201
|
+
- fork_meeting_id: $fork_id
|
|
202
|
+
- prior_tracks (rendezvous 입력):
|
|
203
|
+
|
|
204
|
+
\`\`\`json
|
|
205
|
+
$(jq '.prior_tracks' <<<"$resolved_fork_context")
|
|
206
|
+
\`\`\`
|
|
207
|
+
|
|
208
|
+
> 결정자(기본 CTO) 는 위 트랙별 deliverable 을 통합 검토 후 \`apply-now / backlog / more-validation\` 중 하나를 선택해 아래 Decision JSON 의 \`tracks\` 를 비우고 \`owner / action_type\` 만 채운다 (followup 에서 또 fork 금지)."
|
|
209
|
+
fi
|
|
210
|
+
|
|
111
211
|
cat > "$record" <<EOF
|
|
112
212
|
# Meeting Record — $meeting_id
|
|
113
213
|
|
|
@@ -115,6 +215,7 @@ EOF
|
|
|
115
215
|
- type: $requested_type
|
|
116
216
|
- reason: $requested_reason
|
|
117
217
|
- goal_adherence: $goal_adherence
|
|
218
|
+
$fork_section
|
|
118
219
|
|
|
119
220
|
## Decision JSON
|
|
120
221
|
\`\`\`json
|
|
@@ -135,6 +236,10 @@ EOF
|
|
|
135
236
|
jq -n --arg meeting_id "$meeting_id" --arg type "$requested_type" --arg reason "$requested_reason" --arg source_path "${record#$PROJECT_ROOT/}" --argjson decision "$decision_json" '{meeting_id:$meeting_id,type:$type,reason:$reason,decision:($decision + {source_path:$source_path})}'
|
|
136
237
|
)"))" >/dev/null
|
|
137
238
|
|
|
239
|
+
if [ "$requested_type" = "followup-review" ] && [ "$resolved_fork_context" != "null" ] && [ -n "$resolved_fork_context" ]; then
|
|
240
|
+
bash "$SCRIPT_DIR/harness-progress-set.sh" "$PROJECT_ROOT" ".meetings.fork_context = $resolved_fork_context" >/dev/null
|
|
241
|
+
fi
|
|
242
|
+
|
|
138
243
|
echo "${record#$PROJECT_ROOT/}"
|
|
139
244
|
exit 0
|
|
140
245
|
fi
|
|
@@ -150,4 +255,43 @@ if [ "$MODE" = "read-decision" ]; then
|
|
|
150
255
|
exit 0
|
|
151
256
|
fi
|
|
152
257
|
|
|
258
|
+
# v6.2 — read-tracks: emit normalized tracks[] (length>=2 = fork, length==1 = single).
|
|
259
|
+
# Legacy decisions without tracks → synthesize 1-element tracks[] from {owner, action_type}.
|
|
260
|
+
if [ "$MODE" = "read-tracks" ]; then
|
|
261
|
+
jq -c '
|
|
262
|
+
if ((.meetings.decision.tracks // []) | length) > 0 then
|
|
263
|
+
.meetings.decision.tracks
|
|
264
|
+
elif ((.meetings.fork_context.prior_tracks // []) | length) > 0 then
|
|
265
|
+
.meetings.fork_context.prior_tracks
|
|
266
|
+
elif ((.conductor.tracks // []) | length) > 0 then
|
|
267
|
+
.conductor.tracks
|
|
268
|
+
else
|
|
269
|
+
[ {
|
|
270
|
+
id: "track-1",
|
|
271
|
+
owner: (.meetings.decision.owner // "planner"),
|
|
272
|
+
action_type: (.meetings.decision.action_type // "triage"),
|
|
273
|
+
deliverable: "report",
|
|
274
|
+
deliverable_path: null,
|
|
275
|
+
status: "pending"
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
end
|
|
279
|
+
' "$PROGRESS"
|
|
280
|
+
exit 0
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# v6.2 — read-rendezvous: emit rendezvous{} or null
|
|
284
|
+
if [ "$MODE" = "read-rendezvous" ]; then
|
|
285
|
+
jq -c '.meetings.decision.rendezvous // .conductor.rendezvous // null' "$PROGRESS"
|
|
286
|
+
exit 0
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
# v6.2 — read-fork: "true" if tracks.length >= 2, else "false"
|
|
290
|
+
if [ "$MODE" = "read-fork" ]; then
|
|
291
|
+
decision="$(bash "$0" "$PROJECT_ROOT" read-decision 2>/dev/null || true)"
|
|
292
|
+
if [ -z "$decision" ]; then decision='{}'; fi
|
|
293
|
+
jq -r '((.tracks // []) | length) > 1' <<<"$decision"
|
|
294
|
+
exit 0
|
|
295
|
+
fi
|
|
296
|
+
|
|
153
297
|
exit 2
|
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
9
|
LIB="$SCRIPT_DIR/lib/harness-render-progress.sh"
|
|
10
10
|
AUDIT_LIB="$SCRIPT_DIR/lib/harness-audit.sh"
|
|
11
|
+
MIGRATE_LIB="$SCRIPT_DIR/lib/harness-progress-migrate.sh"
|
|
11
12
|
|
|
12
13
|
if [ ! -f "$LIB" ]; then exit 0; fi
|
|
13
14
|
source "$LIB"
|
|
14
15
|
[ -f "$AUDIT_LIB" ] && source "$AUDIT_LIB"
|
|
16
|
+
[ -f "$MIGRATE_LIB" ] && source "$MIGRATE_LIB"
|
|
15
17
|
command -v jq &>/dev/null || exit 0
|
|
16
18
|
|
|
17
19
|
PROJECT_ROOT="$(resolve_harness_root "." 2>/dev/null)" || exit 0
|
|
@@ -20,6 +22,11 @@ CONFIG="$PROJECT_ROOT/.harness/config.json"
|
|
|
20
22
|
HANDOFF="$PROJECT_ROOT/.harness/handoff.json"
|
|
21
23
|
[ -f "$PROGRESS" ] || exit 0
|
|
22
24
|
|
|
25
|
+
# v6.2 — idempotent schema migration (parallel tracks fields, etc.)
|
|
26
|
+
if declare -f migrate_progress_schema >/dev/null 2>&1; then
|
|
27
|
+
migrate_progress_schema "$PROGRESS" || true
|
|
28
|
+
fi
|
|
29
|
+
|
|
23
30
|
sprint_status=$(jq -r '.sprint.status // "init"' "$PROGRESS" 2>/dev/null)
|
|
24
31
|
sprint_num=$(jq -r '.sprint.number // 0' "$PROGRESS" 2>/dev/null)
|
|
25
32
|
current_agent=$(jq -r '.current_agent // "none"' "$PROGRESS" 2>/dev/null)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# harness-progress-migrate.sh — Idempotent progress.json normalizer.
|
|
3
|
+
#
|
|
4
|
+
# 목적: 새 스키마 필드를 누락하지 않도록 SessionStart 마다 안전하게 채운다.
|
|
5
|
+
# 항상 jq 의 alternative operator(`//`) 또는 `if has` 패턴으로 작성하여
|
|
6
|
+
# 기존 값을 절대 덮어쓰지 않는다.
|
|
7
|
+
#
|
|
8
|
+
# Usage (sourced):
|
|
9
|
+
# source "$SCRIPT_DIR/lib/harness-progress-migrate.sh"
|
|
10
|
+
# migrate_progress_schema "$PROGRESS"
|
|
11
|
+
#
|
|
12
|
+
# Usage (standalone):
|
|
13
|
+
# bash scripts/lib/harness-progress-migrate.sh /path/to/.harness/progress.json
|
|
14
|
+
|
|
15
|
+
migrate_progress_schema() {
|
|
16
|
+
local progress="$1"
|
|
17
|
+
[ -f "$progress" ] || return 0
|
|
18
|
+
command -v jq >/dev/null 2>&1 || return 0
|
|
19
|
+
|
|
20
|
+
# v6.2 — Parallel tracks (fork-join) fields. tracks.length >= 2 → fork.
|
|
21
|
+
# Note: there is intentionally NO `meetings.decision.mode` field — single/parallel is derived
|
|
22
|
+
# from tracks.length. Runtime progress.mode is preserved because it still governs solo/team/paused.
|
|
23
|
+
local filter='
|
|
24
|
+
.conductor.tracks = (.conductor.tracks // [])
|
|
25
|
+
| .conductor.rendezvous = (.conductor.rendezvous // null)
|
|
26
|
+
| .conductor.fork_meeting_id = (.conductor.fork_meeting_id // null)
|
|
27
|
+
|
|
28
|
+
| .meetings = (.meetings // {})
|
|
29
|
+
| .meetings.requested_tracks = (.meetings.requested_tracks // [])
|
|
30
|
+
| .meetings.requested_rendezvous = (.meetings.requested_rendezvous // null)
|
|
31
|
+
| .meetings.fork_meeting_id = (.meetings.fork_meeting_id // null)
|
|
32
|
+
|
|
33
|
+
| .meetings.decision = (.meetings.decision // {})
|
|
34
|
+
| .meetings.decision.tracks = (.meetings.decision.tracks // [])
|
|
35
|
+
| .meetings.decision.rendezvous = (.meetings.decision.rendezvous // null)
|
|
36
|
+
| del(.meetings.decision.mode)
|
|
37
|
+
| del(.meetings.requested_mode)
|
|
38
|
+
'
|
|
39
|
+
|
|
40
|
+
local tmp
|
|
41
|
+
tmp="$(mktemp)" || return 1
|
|
42
|
+
if jq "$filter" "$progress" > "$tmp" 2>/dev/null; then
|
|
43
|
+
mv "$tmp" "$progress"
|
|
44
|
+
else
|
|
45
|
+
rm -f "$tmp"
|
|
46
|
+
return 1
|
|
47
|
+
fi
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Standalone invocation
|
|
51
|
+
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
52
|
+
target="${1:-}"
|
|
53
|
+
if [ -z "$target" ]; then
|
|
54
|
+
echo "usage: $0 <path/to/.harness/progress.json>" >&2
|
|
55
|
+
exit 2
|
|
56
|
+
fi
|
|
57
|
+
migrate_progress_schema "$target"
|
|
58
|
+
fi
|
|
@@ -152,6 +152,7 @@ idle ─► running ─► (waiting_meeting | waiting_owner | running) ─► co
|
|
|
152
152
|
- 리서치·정리 중심 → `documentationer`
|
|
153
153
|
- 빠른 실험·백데이터 코드 중심 → `coo-developer`
|
|
154
154
|
- 둘 다 필요 → 같은 tick 에 2명 병렬 spawn 가능
|
|
155
|
+
- `hypothesis-verdict` 는 terminal 단계이며 완료 시 `meeting-manager` / followup-review 로 되돌린다.
|
|
155
156
|
|
|
156
157
|
### 5.1 Team mode 병렬 spawn (G-005)
|
|
157
158
|
|
|
@@ -21,12 +21,20 @@ disable-model-invocation: false
|
|
|
21
21
|
- Planner의 `requested_mode = "hypothesis"`
|
|
22
22
|
- 기존 코드베이스, 로컬 데이터, 백데이터, 샘플 CSV/JSON/DB dump
|
|
23
23
|
|
|
24
|
-
## 3. 출력
|
|
24
|
+
## 3. 출력 (산출물 경로 표준)
|
|
25
25
|
|
|
26
|
-
- 실험 코드 또는 스크립트
|
|
27
|
-
- 재현 절차
|
|
28
|
-
- 관찰 결과와 한계
|
|
29
|
-
-
|
|
26
|
+
- `.harness/actions/hypothesis/<id>/spike/` — 실험 코드 또는 스크립트
|
|
27
|
+
- `.harness/actions/hypothesis/<id>/repro.md` — 재현 절차
|
|
28
|
+
- `.harness/actions/hypothesis/<id>/observations.md` — 관찰 결과와 한계
|
|
29
|
+
- `<id>` 는 `H-YYYYMMDDTHHMMSSZ` 형식. Planner 가 fork 시점에 발급.
|
|
30
|
+
|
|
31
|
+
`progress.json` 업데이트 (완료 시):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bash scripts/harness-progress-set.sh . \
|
|
35
|
+
'.coo_developer.last_spike_path = "actions/hypothesis/<id>/spike/" |
|
|
36
|
+
.coo_developer.last_observations = "actions/hypothesis/<id>/observations.md"'
|
|
37
|
+
```
|
|
30
38
|
|
|
31
39
|
## 4. 작업 원칙
|
|
32
40
|
|
|
@@ -40,3 +48,25 @@ disable-model-invocation: false
|
|
|
40
48
|
- 실험 결과만으로 운영 가능 판정
|
|
41
49
|
- 정규 팀 평가 없이 배포 코드로 승격
|
|
42
50
|
- 근거 없는 직감성 결론
|
|
51
|
+
|
|
52
|
+
## 6. Parallel-Tracks 컨텍스트 (v6.2)
|
|
53
|
+
|
|
54
|
+
Hypothesis Cell 은 fork 회의 (결정 JSON 의 `tracks[]` 길이 ≥ 2) 에서 **track-N** 의 owner 로 지명되어 활동한다 (보통 `track-2: planner/hypothesis-validation` 의 sub-step).
|
|
55
|
+
|
|
56
|
+
- 자기 활동이 fork 회의에서 시작되었는지는 `progress.json.conductor.fork_meeting_id` 와 `progress.json.conductor.tracks[]` 에서 확인.
|
|
57
|
+
- 형제 트랙 (예: `track-1: cto/bugfix`) 의 진행은 차단 사유가 아니다 — 평행 진행.
|
|
58
|
+
- 완료 시 spike/observations 경로를 documentationer 에 인계 (Planner 가 이어 받아 followup-review 산출물 `validation-report` 로 정리).
|
|
59
|
+
- followup-review 결정 = `apply-now` 면 spike 경로의 일부가 sprint artifact 로 승격될 수 있다. 그 시점부터는 정규 Generator 가 다시 짠다 — Hypothesis Cell 코드는 SoT 가 아니다.
|
|
60
|
+
|
|
61
|
+
## 7. Session Boundary
|
|
62
|
+
|
|
63
|
+
### On Start
|
|
64
|
+
1. `.harness/progress.json` 읽기 — `conductor.fork_meeting_id` / `conductor.tracks[]` / `planner.last_brief` 확인
|
|
65
|
+
2. 자기 트랙 식별 (owner 가 `coo-developer` 또는 `planner` + brief=`hypothesis:experiment`)
|
|
66
|
+
3. `.harness/conventions/coo-developer.md`, `.harness/gotchas/coo-developer.md` 읽기
|
|
67
|
+
4. (v6.2) parallel 모드면 형제 트랙 owner 의 gotcha 도 한 번 훑기
|
|
68
|
+
|
|
69
|
+
### On Complete
|
|
70
|
+
1. `actions/hypothesis/<id>/` 산출물 경로 확정
|
|
71
|
+
2. partial update: `coo_developer.last_spike_path`, `agent_status = "completed"`
|
|
72
|
+
3. `next_agent = "documentationer"` (Planner 의 hypothesis 흐름이 활성화된 경우)
|
|
@@ -22,25 +22,71 @@ disable-model-invocation: false
|
|
|
22
22
|
- `coo-developer`의 실험 결과
|
|
23
23
|
- 필요 시 외부 리서치 소스
|
|
24
24
|
|
|
25
|
-
## 3. 출력
|
|
25
|
+
## 3. 출력 (산출물 경로 표준)
|
|
26
26
|
|
|
27
|
-
- `hypothesis-brief`
|
|
28
|
-
- `validation-report`
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
- `.harness/actions/hypothesis/<id>/brief.md` — `hypothesis-brief` (사전 리서치)
|
|
28
|
+
- `.harness/actions/hypothesis/<id>/report.md` — `validation-report` (실험 후 통합)
|
|
29
|
+
- `.harness/actions/hypothesis/<id>/evidence/` — 출처 스냅샷·캡처
|
|
30
|
+
- `.harness/actions/hypothesis/<id>/verdict.json` — 기계 판독 판정
|
|
31
|
+
|
|
32
|
+
`verdict.json` 스키마 (필수 필드):
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"id": "H-...",
|
|
37
|
+
"hypothesis": "한 줄 가설",
|
|
38
|
+
"verdict": "supported | refuted | inconclusive",
|
|
39
|
+
"confidence": 0.0,
|
|
40
|
+
"key_evidence": [
|
|
41
|
+
{"source": "actions/hypothesis/<id>/spike/run.log", "kind": "experiment"},
|
|
42
|
+
{"source": "https://...", "kind": "external-research"}
|
|
43
|
+
],
|
|
44
|
+
"next_action": "promote-to-sprint | additional-experiment | discard",
|
|
45
|
+
"rationale": "왜 이 판정인가 — evidence 와 직접 연결",
|
|
46
|
+
"open_questions": ["..."],
|
|
47
|
+
"limitations": ["..."]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`progress.json` 업데이트 (완료 시):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bash scripts/harness-progress-set.sh . \
|
|
55
|
+
'.documentationer.last_report = "actions/hypothesis/<id>/report.md" |
|
|
56
|
+
.documentationer.last_verdict = "actions/hypothesis/<id>/verdict.json"'
|
|
57
|
+
```
|
|
34
58
|
|
|
35
59
|
## 4. 보고서 규칙
|
|
36
60
|
|
|
37
61
|
- 결론 먼저, 근거 다음
|
|
38
|
-
- 주장마다 evidence 출처 명시
|
|
62
|
+
- 주장마다 evidence 출처 명시 (URI 또는 artifact path)
|
|
39
63
|
- 운영팀/CTO/CQO가 바로 이어받을 수 있게 열린 질문을 분리
|
|
40
64
|
- "왜 아직 확실하지 않은가"도 반드시 적을 것
|
|
65
|
+
- `verdict` 는 supported / refuted / inconclusive 셋 중 하나로만 — 모호한 표현 금지
|
|
41
66
|
|
|
42
67
|
## 5. 금지
|
|
43
68
|
|
|
44
69
|
- evidence 없는 유효 판정
|
|
45
70
|
- CTO/CQO 검증을 대신했다고 표현
|
|
46
71
|
- 실험 로그를 정제 없이 그대로 보고서로 제출
|
|
72
|
+
|
|
73
|
+
## 6. Parallel-Tracks 컨텍스트 (v6.2)
|
|
74
|
+
|
|
75
|
+
`validation-report` 는 followup-review 회의에서 **track deliverable** 로 사용된다.
|
|
76
|
+
|
|
77
|
+
- followup-review 의 Meeting-Manager 는 `prior_tracks[].deliverable_path` 를 통해 이 보고서를 읽는다.
|
|
78
|
+
- `verdict.json` 의 `next_action` 이 `promote-to-sprint` 면 followup 결정은 보통 `apply-now`, `additional-experiment` 면 `more-validation`, `discard` 면 `backlog` 또는 종결.
|
|
79
|
+
- 형제 트랙 (예: `track-1: cto/bugfix`) 의 결과는 별도 deliverable. 둘을 함께 보고 결정자(CTO 또는 CEO) 가 통합한다 — Documentationer 가 직접 통합 결정을 내리지 않는다.
|
|
80
|
+
|
|
81
|
+
## 7. Session Boundary
|
|
82
|
+
|
|
83
|
+
### On Start
|
|
84
|
+
1. `.harness/progress.json` 읽기 — `planner.last_brief` 확인 (`hypothesis:research` 또는 `hypothesis:report`)
|
|
85
|
+
2. brief=research 면 `brief.md` 작성, brief=report 면 `coo-developer` 의 spike 결과를 `report.md` 로 통합
|
|
86
|
+
3. `.harness/conventions/documentationer.md`, `.harness/gotchas/documentationer.md` 읽기
|
|
87
|
+
4. (v6.2) parallel 모드면 형제 트랙 owner 의 gotcha 도 한 번 훑기
|
|
88
|
+
|
|
89
|
+
### On Complete
|
|
90
|
+
1. `report.md` + `verdict.json` 작성 완료
|
|
91
|
+
2. partial update: `documentationer.last_report`, `documentationer.last_verdict`, `agent_status = "completed"`
|
|
92
|
+
3. `next_agent = "planner"` (hypothesis-verdict 종합)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: harness-meeting-manager
|
|
3
|
-
description: "부서 간 동기화 엔진. Cron(Service-Ops)·Event(부서 발신)·Manual 트리거로
|
|
3
|
+
description: "부서 간 동기화 엔진. Cron(Service-Ops)·Event(부서 발신)·Manual 트리거로 6종 회의(Standup/Sprint Review/Spec Review/Incident War Room/All-Hands/Followup Review)를 소집·집계·디스패치. parallel tracks fork-join 지원. 적응형 cadence(light 30m / normal 1h / heavy 4h). 트리거: '미팅 소집', 'meeting convene', 'standup', 'followup'."
|
|
4
4
|
disable-model-invocation: false
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ walwal-harness 의 부서 구조에 맞게 재해석함.
|
|
|
23
23
|
- **권한**: 모든 부서에 prep 양식 발신, 회의록 작성·집계, queue enqueue (v5.9.6 재사용)
|
|
24
24
|
- **금지**: 의사결정 직접 수행 (사회만 봄), Owner와 직접 대화 (escalation은 Dispatcher 경유)
|
|
25
25
|
|
|
26
|
-
## 2. 회의
|
|
26
|
+
## 2. 회의 6종 (v6.2 — Followup Review 추가)
|
|
27
27
|
|
|
28
28
|
| 종류 | 트리거 | 참석자 | 결과물 | Owner 푸시? |
|
|
29
29
|
|---|---|---|---|---|
|
|
@@ -32,6 +32,7 @@ walwal-harness 의 부서 구조에 맞게 재해석함.
|
|
|
32
32
|
| **Spec Review** | Eval "Change Request" 발신 | COO·CTO·발신 Eval | feature-list 수정·api-contract 변경 | 변경 시 ✅ |
|
|
33
33
|
| **Incident War Room** | Service-Ops red-alert | CEO·CTO·Incident-Responder·관련 Gen | 핫픽스·롤백·RCA 초안 | ✅ 즉시 |
|
|
34
34
|
| **All-Hands (Phase Gate)** | Phase 0~6 전환 이벤트 | 전 부서 + CEO·COO | Phase 진입 승인·부서 편성 변경 | ✅ 요약본 |
|
|
35
|
+
| **Followup Review** *(v6.2)* | parallel tracks 의 모든 deliverable 도착 또는 `rendezvous.when` 도달 | fork meeting 의 트랙 owner 들 + 결정자(CTO 또는 CEO) | 트랙 산출물 통합 결정 (즉시 적용 / 백로그 / 추가 검증) | 변경 시 ✅ |
|
|
35
36
|
|
|
36
37
|
## 3. 회의 라이프사이클 (5단계)
|
|
37
38
|
|
|
@@ -99,12 +100,27 @@ meeting:
|
|
|
99
100
|
vote: { agree: 0.71, override: false }
|
|
100
101
|
decision:
|
|
101
102
|
owner: planner | cto | cqo | service-ops | dispatcher
|
|
102
|
-
action_type: goal-alignment | replan | implement | re-evaluate | monitor | escalate-owner
|
|
103
|
+
action_type: goal-alignment | replan | implement | re-evaluate | monitor | escalate-owner | hypothesis-validation | bugfix
|
|
103
104
|
rationale: <fact-based why this owner must act next>
|
|
104
105
|
evidence:
|
|
105
106
|
- source: <artifact path>
|
|
106
|
-
kind: ops-report | cqo-audit | cto-review | meeting-prep
|
|
107
|
+
kind: ops-report | cqo-audit | cto-review | meeting-prep | track-deliverable
|
|
107
108
|
drift_classification: implementation_drift | planning_drift | ops_drift | goal_drift
|
|
109
|
+
# v6.2 — Parallel tracks (fork-join). tracks.length >= 2 이면 fork, 없거나 1이면 single.
|
|
110
|
+
# 별도의 mode 플래그는 두지 않음 — 단일 진실은 tracks 자체.
|
|
111
|
+
tracks:
|
|
112
|
+
- id: track-1
|
|
113
|
+
owner: cto
|
|
114
|
+
action_type: bugfix
|
|
115
|
+
deliverable: hotfix-result | validation-report | spike-result | report
|
|
116
|
+
deliverable_path: <artifact path or null>
|
|
117
|
+
status: pending | running | completed | abandoned
|
|
118
|
+
rendezvous: # tracks.length >= 2 일 때만 의미 있음
|
|
119
|
+
type: followup-review | sprint-review
|
|
120
|
+
when: next_cadence | <iso>
|
|
121
|
+
# Followup Review 전용 필드
|
|
122
|
+
fork_meeting_id: <원본 fork 회의 id, 있으면>
|
|
123
|
+
prior_tracks: [<완료된 tracks[] 스냅샷>]
|
|
108
124
|
action_items:
|
|
109
125
|
- id: AI-1
|
|
110
126
|
owner: generator-backend
|
|
@@ -140,12 +156,104 @@ meeting:
|
|
|
140
156
|
"rationale": "...",
|
|
141
157
|
"evidence": [],
|
|
142
158
|
"drift_classification": "planning_drift",
|
|
159
|
+
"tracks": [],
|
|
160
|
+
"rendezvous": null,
|
|
143
161
|
"source_path": ".harness/actions/meetings/M-.../meeting-M-....md"
|
|
144
162
|
},
|
|
163
|
+
"requested_tracks": [],
|
|
164
|
+
"requested_rendezvous": null,
|
|
165
|
+
"fork_meeting_id": null,
|
|
145
166
|
"manual_override": null
|
|
146
167
|
}
|
|
147
168
|
```
|
|
148
169
|
|
|
170
|
+
> tracks.length ≥ 2 면 fork-join, 그 외(0 또는 1)는 single. 별도 mode 플래그는 없음.
|
|
171
|
+
|
|
172
|
+
`progress.json.conductor` 에는 활성 fork 의 트랙 상태가 거울처럼 미러링 된다:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
"conductor": {
|
|
176
|
+
"tracks": [
|
|
177
|
+
{ "id": "track-1", "owner": "cto", "action_type": "bugfix",
|
|
178
|
+
"deliverable": "hotfix-result", "deliverable_path": null,
|
|
179
|
+
"status": "running", "started_at": "<iso>" }
|
|
180
|
+
],
|
|
181
|
+
"rendezvous": { "type": "followup-review", "when": "next_cadence" },
|
|
182
|
+
"fork_meeting_id": "M-..."
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 7.05 Parallel Tracks (v6.2 — Fork-Join)
|
|
187
|
+
|
|
188
|
+
회의 결론이 한 개의 owner 로 모이지 않고 둘 이상의 부서가 **독립 산출물**을 만든 뒤 **다음 회의에서 합치는** 패턴을 지원한다.
|
|
189
|
+
|
|
190
|
+
### 7.05.1 언제 parallel 을 선택하는가
|
|
191
|
+
|
|
192
|
+
다음을 **모두** 충족할 때만 parallel 로 결정한다.
|
|
193
|
+
|
|
194
|
+
1. 결론이 둘 이상의 deliverable 로 자연 분해된다 (예: "버그 핫픽스" + "가설 보고서").
|
|
195
|
+
2. 두 deliverable 사이에 직접 의존이 없다 (한쪽이 다른 쪽 결과를 기다리지 않는다).
|
|
196
|
+
3. 결정자(CTO 또는 CEO) 가 두 결과를 **함께 보고** 다음 단계를 정해야 한다.
|
|
197
|
+
|
|
198
|
+
위 셋 중 하나라도 어긋나면 single 로 가고, 후속 작업은 별도 회의에서 다룬다.
|
|
199
|
+
|
|
200
|
+
### 7.05.2 Fork 회의 결정 작성법
|
|
201
|
+
|
|
202
|
+
회의록 `## Decision JSON` 블록에 다음을 작성한다:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"decision": {
|
|
207
|
+
"owner": "cto",
|
|
208
|
+
"action_type": "bugfix",
|
|
209
|
+
"rationale": "운영 버그 + 신규 가설 두 트랙 동시 진행 — 다음 followup-review 에서 통합 결정",
|
|
210
|
+
"evidence": [...],
|
|
211
|
+
"drift_classification": "implementation_drift",
|
|
212
|
+
"tracks": [
|
|
213
|
+
{ "id": "track-1", "owner": "cto", "action_type": "bugfix", "deliverable": "hotfix-result" },
|
|
214
|
+
{ "id": "track-2", "owner": "planner", "action_type": "hypothesis-validation", "deliverable": "validation-report" }
|
|
215
|
+
],
|
|
216
|
+
"rendezvous": { "type": "followup-review", "when": "next_cadence" }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
> `tracks` 가 2개 이상 → 자동으로 fork-join. 1개 이하 → single (rendezvous 무시). 별도 mode 플래그 없음.
|
|
222
|
+
|
|
223
|
+
규칙:
|
|
224
|
+
- `tracks[0].owner` 와 `tracks[0].action_type` 는 backward-compat 으로 `decision.owner` / `decision.action_type` 와 동일해야 한다 (Conductor 의 1차 dispatch 대상).
|
|
225
|
+
- `id` 는 `track-1`, `track-2` 형식으로 1-based 순번. 두 개를 권장. 셋 이상은 fork 가 너무 무거워지므로 회의를 분리해라.
|
|
226
|
+
- `deliverable` 은 짧은 슬러그(`hotfix-result`, `validation-report`, `spike-result`, `report`).
|
|
227
|
+
- `rendezvous.when` 은 `next_cadence` (다음 정기 회의에 합류) 또는 ISO 시각 (특정 시점에 강제 소집).
|
|
228
|
+
|
|
229
|
+
### 7.05.3 Conductor 가 하는 일 (참고)
|
|
230
|
+
|
|
231
|
+
`scripts/conductor-tick.sh` 가 자동으로:
|
|
232
|
+
1. fork 회의 직후 `progress.json.conductor.tracks` 에 트랙 상태 미러링.
|
|
233
|
+
2. 첫 번째 트랙 owner 를 spawn (status=running). 그 owner 가 완료하면 트랙을 completed 처리하고 다음 pending 트랙 spawn.
|
|
234
|
+
3. 모든 트랙이 completed 되면 `meetings.requested_type=<rendezvous.type>` + `meetings.requested_reason=rendezvous` 로 followup-review 를 자동 소집.
|
|
235
|
+
4. fork 회의 id 는 `progress.json.meetings.fork_meeting_id` 로 followup 회의에 전달된다.
|
|
236
|
+
|
|
237
|
+
Meeting-Manager 는 트랙 dispatch 자체에 관여하지 않는다. fork 회의록의 decision JSON 만 정확히 작성하면 된다.
|
|
238
|
+
|
|
239
|
+
### 7.05.4 Followup Review 진행 방식
|
|
240
|
+
|
|
241
|
+
소집 직후 `notice.md` 에는 fork 회의 id 와 트랙 deliverable 경로 목록이 자동 채워진다. Meeting-Manager 는 다음 순서로 진행:
|
|
242
|
+
|
|
243
|
+
1. **트랙 산출물 수집**: `prior_tracks[]` 의 각 `deliverable_path` 를 읽어 prep 양식에 요약을 넣는다 (`prep-cto.md` 에 hotfix-result, `prep-planner.md` 에 validation-report). `fork_context` 가 비어 있어도 `conductor.tracks` 또는 `meetings.decision.tracks` 로 복구한다.
|
|
244
|
+
2. **결정자 지정**: 기본 결정자 = CTO (운영 적용 여부). 단 fork 회의가 `goal-intake` 또는 `goal-drift` 였으면 CEO(Dispatcher) 로 escalate.
|
|
245
|
+
3. **세 가지 통합 결정 중 하나**:
|
|
246
|
+
- `apply-now` — 두 산출물을 즉시 정규 sprint artifact 로 승격. 다음 owner = planner (sprint-contract 갱신).
|
|
247
|
+
- `backlog` — 백로그 등록 후 다음 sprint 에서 다룸. 다음 owner = planner (feature-list append).
|
|
248
|
+
- `more-validation` — 추가 검증 필요. 다시 parallel fork 또는 단일 spec-review.
|
|
249
|
+
4. 결정은 **single mode** 로 작성한다 (followup 자체에서 또 fork 하지 말 것 — 무한 fork 방지).
|
|
250
|
+
|
|
251
|
+
### 7.05.5 안전 가드
|
|
252
|
+
|
|
253
|
+
- **Followup 무한 fork 금지**: followup-review 의 결정 JSON 은 `tracks.length ≤ 1` 만 허용 (또는 tracks 자체를 비움). 추가 분할이 필요하면 별도 spec-review 로 회부.
|
|
254
|
+
- **Track abandon**: 트랙이 24h 이상 stuck 또는 owner 가 escalation 발신 → 해당 트랙 `status: abandoned`, 나머지 진행 + followup 에서 사유 명시.
|
|
255
|
+
- **Fork 폭주 방지**: 한 sprint 내 parallel fork 가 ≥ 3회 발생하면 다음 fork 는 single 로 강제 (회의 분해 시그널).
|
|
256
|
+
|
|
149
257
|
## 7.1 회의 진행 방식
|
|
150
258
|
|
|
151
259
|
Meeting-Manager는 단순히 "토론해 주세요"라고 말하지 않는다. 각 참석자에게 역할별 prep를 요청한다.
|
|
@@ -180,6 +288,7 @@ Meeting-Manager 자체는 cron을 돌리지 않음. Service-Ops가 매 hourly
|
|
|
180
288
|
| Planner | Phase 전환 요청 | All-Hands (Phase Gate) |
|
|
181
289
|
| Owner | `/meeting convene <type>` | 해당 타입 (manual) |
|
|
182
290
|
| Service-Ops | `goal_adherence < 0.5` 24h | Spec Review (긴급) |
|
|
291
|
+
| Conductor | parallel tracks 모두 완료 또는 `rendezvous.when` 도달 | **Followup Review** *(v6.2)* |
|
|
183
292
|
|
|
184
293
|
## 10. Action Item 디스패치
|
|
185
294
|
|
|
@@ -218,6 +327,7 @@ bash scripts/queue-enqueue.sh --owner generator-backend --feature <feature-i
|
|
|
218
327
|
5. 기본 handoff 규칙:
|
|
219
328
|
- `goal-intake` / `goal-drift` / `spec-review` / `incident-followup` → `planner(COO)`
|
|
220
329
|
- `ops-batch` / `sprint-review` / `quality-fail` → `cto`
|
|
330
|
+
- `rendezvous` (followup-review 결정 시) → 결정자 = `cto` 기본, 단 fork 회의가 `goal-intake|goal-drift` 였으면 `dispatcher` 로 escalate
|
|
221
331
|
|
|
222
332
|
### On Archived
|
|
223
333
|
1. `.harness/archive/meetings/<id>/` 로 이동
|