okstra 0.60.3 → 0.62.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/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/lib/okstra/interactive.sh +62 -4
- package/runtime/prompts/wizard/prompts.ko.json +8 -0
- package/runtime/python/okstra_ctl/run_context.py +45 -1
- package/runtime/python/okstra_ctl/wizard.py +103 -23
- package/runtime/templates/reports/final-report.template.md +13 -10
- package/runtime/templates/reports/i18n/en.json +1 -2
- package/runtime/templates/reports/i18n/ko.json +1 -2
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -357,10 +357,16 @@ run_resume_clarification() {
|
|
|
357
357
|
local report_path="${lookup_result%$'\t'*}"
|
|
358
358
|
local resolved_type="${lookup_result##*$'\t'}"
|
|
359
359
|
|
|
360
|
+
# implementation-planning 도 §1 Clarification Items(plan-body 결정: 예 C-205
|
|
361
|
+
# tx-배관 step 누락)를 가지므로, 사용자가 결정란을 채운 뒤 같은 phase 를
|
|
362
|
+
# clarification-response 자동공급으로 재실행해 plan 을 재생성·gate 재판정할 수
|
|
363
|
+
# 있다. 자동검색(task_type_filter 없음)은 파일명 사전순 max 라 implementation-
|
|
364
|
+
# planning 이 requirements-discovery 에 밀리므로, 이 경로는 --task-type
|
|
365
|
+
# implementation-planning 을 명시했을 때만 해소된다.
|
|
360
366
|
case "$resolved_type" in
|
|
361
|
-
requirements-discovery|error-analysis) ;;
|
|
367
|
+
requirements-discovery|error-analysis|implementation-planning) ;;
|
|
362
368
|
*)
|
|
363
|
-
printf '%s (resolved task-type: %s)\n' '--resume-clarification only applies to requirements-discovery
|
|
369
|
+
printf '%s (resolved task-type: %s)\n' '--resume-clarification only applies to requirements-discovery, error-analysis, or implementation-planning runs' "$resolved_type" >&2
|
|
364
370
|
exit 1
|
|
365
371
|
;;
|
|
366
372
|
esac
|
|
@@ -387,11 +393,62 @@ PY
|
|
|
387
393
|
exit 1
|
|
388
394
|
fi
|
|
389
395
|
|
|
396
|
+
# 직전 run 의 워커/모델/directive/related-tasks 를 그대로 이어 실행한다 — resume 가
|
|
397
|
+
# 이 설정들을 안 넘기면 매 단계 재입력이 아니라 Python phase 기본값으로 조용히
|
|
398
|
+
# 되돌아가 버린다. run-inputs 의 위치/구조 지식은 okstra_ctl.run_context 가 SSOT.
|
|
399
|
+
local resume_extra_args=()
|
|
400
|
+
while IFS= read -r -d '' _arg; do
|
|
401
|
+
resume_extra_args+=("$_arg")
|
|
402
|
+
done < <(PYTHONPATH="$WORKSPACE_ROOT/scripts:${PYTHONPATH-}" python3 - \
|
|
403
|
+
"$PROJECT_ROOT" "$TASK_GROUP" "$TASK_ID" "$resolved_type" <<'PY'
|
|
404
|
+
import sys
|
|
405
|
+
from okstra_ctl.run_context import latest_run_inputs
|
|
406
|
+
from okstra_ctl.ids import slugify_task_segment
|
|
407
|
+
|
|
408
|
+
project_root, task_group, task_id, task_type = sys.argv[1:5]
|
|
409
|
+
inputs = latest_run_inputs(
|
|
410
|
+
project_root, task_group, task_id,
|
|
411
|
+
phase_segment=slugify_task_segment(task_type))
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def emit(flag, value):
|
|
415
|
+
if value:
|
|
416
|
+
sys.stdout.write(flag + "\0" + value + "\0")
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def model(value):
|
|
420
|
+
# 직전 run 의 모델 display 값. "default"/빈 값은 phase 기본값을 뜻하므로 넘기지
|
|
421
|
+
# 않는다(명시 플래그로 고정하면 안 됨).
|
|
422
|
+
return value if isinstance(value, str) and value not in ("", "default") else ""
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
workers = inputs.get("workers")
|
|
426
|
+
if isinstance(workers, list):
|
|
427
|
+
workers = ",".join(w for w in workers if isinstance(w, str))
|
|
428
|
+
elif not isinstance(workers, str):
|
|
429
|
+
workers = ""
|
|
430
|
+
emit("--workers", workers)
|
|
431
|
+
emit("--lead-model", model(inputs.get("leadModel")))
|
|
432
|
+
emit("--claude-model", model(inputs.get("claudeModel")))
|
|
433
|
+
emit("--codex-model", model(inputs.get("codexModel")))
|
|
434
|
+
emit("--gemini-model", model(inputs.get("geminiModel")))
|
|
435
|
+
emit("--report-writer-model", model(inputs.get("reportWriterModel")))
|
|
436
|
+
directive = inputs.get("directive")
|
|
437
|
+
emit("--directive", directive if isinstance(directive, str) else "")
|
|
438
|
+
related = inputs.get("relatedTasks")
|
|
439
|
+
emit("--related-tasks", related if isinstance(related, str) else "")
|
|
440
|
+
PY
|
|
441
|
+
)
|
|
442
|
+
|
|
390
443
|
if [[ "${OKSTRA_RESUME_CLARIFICATION_DRY_RUN:-false}" == "true" ]]; then
|
|
391
444
|
printf 'resume-clarification (dry-run):\n' >&2
|
|
392
445
|
printf ' report: %s\n' "$report_path" >&2
|
|
393
|
-
printf ' re-exec: bash %s --task-type %s --project-id %s --task-group %s --task-id %s --task-brief %s --clarification-response %s
|
|
446
|
+
printf ' re-exec: bash %s --task-type %s --project-id %s --task-group %s --task-id %s --task-brief %s --clarification-response %s' \
|
|
394
447
|
"$0" "$resolved_type" "$PROJECT_ID" "$TASK_GROUP" "$TASK_ID" "$resume_brief_rel" "$report_path" >&2
|
|
448
|
+
if (( ${#resume_extra_args[@]} > 0 )); then
|
|
449
|
+
printf ' %s' "${resume_extra_args[@]}" >&2
|
|
450
|
+
fi
|
|
451
|
+
printf '\n' >&2
|
|
395
452
|
return 0
|
|
396
453
|
fi
|
|
397
454
|
|
|
@@ -409,5 +466,6 @@ PY
|
|
|
409
466
|
--task-group "$TASK_GROUP" \
|
|
410
467
|
--task-id "$TASK_ID" \
|
|
411
468
|
--task-brief "$resume_brief_rel" \
|
|
412
|
-
--clarification-response "$report_path"
|
|
469
|
+
--clarification-response "$report_path" \
|
|
470
|
+
${resume_extra_args[@]+"${resume_extra_args[@]}"}
|
|
413
471
|
}
|
|
@@ -251,6 +251,14 @@
|
|
|
251
251
|
"provider": "{provider} critic"
|
|
252
252
|
}
|
|
253
253
|
},
|
|
254
|
+
"reuse_previous": {
|
|
255
|
+
"label": "이 task·phase 의 직전 run 설정이 남아 있습니다. 그대로 재사용할까요?\n· 예 — 직전 run 의 워커 구성·역할별 모델·directive·관련 task 를 그대로 가져오고, 가장 최근 final-report 를 clarification 입력으로 자동 선택해 바로 확인 단계로 넘어갑니다.\n· 아니오 — 모델/워커/directive 등을 단계별로 다시 입력합니다.",
|
|
256
|
+
"echo_template": "reuse-previous: {value}",
|
|
257
|
+
"options": {
|
|
258
|
+
"yes": "예 — 직전 설정 그대로 진행",
|
|
259
|
+
"no": "아니오 — 단계별로 다시 입력"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
254
262
|
"defaults_or_custom": {
|
|
255
263
|
"label": "역할별로 어떤 모델을 쓸지 정하는 단계입니다 (참여 워커 구성을 바꾸는 게 아닙니다).\n· 기본값으로 진행 — lead·실행자/워커·report-writer 를 모두 추천 모델로 두고 바로 진행합니다.\n· 커스터마이즈 — 역할별 모델을 직접 고르고, 추가 directive·관련 task 도 지정합니다.",
|
|
256
264
|
"echo_template": "customize: {value}",
|
|
@@ -23,7 +23,51 @@ from datetime import datetime, timezone
|
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Iterator, Optional
|
|
25
25
|
|
|
26
|
-
from .paths import compute_run_paths
|
|
26
|
+
from .paths import compute_run_paths, task_runs_dir
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def latest_run_inputs(
|
|
30
|
+
project_root: object,
|
|
31
|
+
task_group: str,
|
|
32
|
+
task_id: str,
|
|
33
|
+
*,
|
|
34
|
+
phase_segment: str = "",
|
|
35
|
+
) -> dict:
|
|
36
|
+
"""가장 최근 ``run-inputs-*.json`` 의 ``inputs`` dict 를 반환 (부재 시 {}).
|
|
37
|
+
|
|
38
|
+
``phase_segment`` 가 주어지면 그 phase 의 ``runs/<seg>/manifests/`` 만 스캔한다
|
|
39
|
+
(resume 는 같은 phase 를 재실행하므로 그 phase 의 직전 입력이 기준). 비어 있으면
|
|
40
|
+
task 의 모든 phase 를 통틀어 가장 최근(mtime) 파일을 고른다.
|
|
41
|
+
|
|
42
|
+
페이로드 구조는 ``{"schemaVersion", "writtenAt", "inputs": {...}}`` 이며 실제
|
|
43
|
+
입력은 top-level 이 아니라 ``inputs`` 아래에 있다. run-inputs 의 위치/구조 지식은
|
|
44
|
+
이 함수 한 곳에만 둔다(wizard·okstra.sh resume 가 공유).
|
|
45
|
+
"""
|
|
46
|
+
if not (project_root and task_group and task_id):
|
|
47
|
+
return {}
|
|
48
|
+
runs_base = task_runs_dir(Path(project_root), task_group, task_id)
|
|
49
|
+
if not runs_base.is_dir():
|
|
50
|
+
return {}
|
|
51
|
+
if phase_segment:
|
|
52
|
+
glob_iter = (runs_base / phase_segment / "manifests").glob(
|
|
53
|
+
"run-inputs-*.json")
|
|
54
|
+
else:
|
|
55
|
+
glob_iter = runs_base.glob("*/manifests/run-inputs-*.json")
|
|
56
|
+
candidates: list[tuple[float, Path]] = []
|
|
57
|
+
for inp in glob_iter:
|
|
58
|
+
try:
|
|
59
|
+
candidates.append((inp.stat().st_mtime, inp))
|
|
60
|
+
except OSError:
|
|
61
|
+
continue
|
|
62
|
+
if not candidates:
|
|
63
|
+
return {}
|
|
64
|
+
candidates.sort(key=lambda x: -x[0])
|
|
65
|
+
try:
|
|
66
|
+
data = json.loads(candidates[0][1].read_text(encoding="utf-8"))
|
|
67
|
+
except (OSError, json.JSONDecodeError):
|
|
68
|
+
return {}
|
|
69
|
+
inputs = data.get("inputs")
|
|
70
|
+
return inputs if isinstance(inputs, dict) else {}
|
|
27
71
|
|
|
28
72
|
|
|
29
73
|
def _now_iso() -> str:
|
|
@@ -57,6 +57,7 @@ from okstra_ctl.worktree import (
|
|
|
57
57
|
preview_worktree_decision,
|
|
58
58
|
)
|
|
59
59
|
from okstra_ctl.paths import task_runs_dir
|
|
60
|
+
from okstra_ctl.run_context import latest_run_inputs
|
|
60
61
|
from okstra_project.dirs import project_json_path
|
|
61
62
|
from okstra_project.state import (
|
|
62
63
|
StateError,
|
|
@@ -231,6 +232,7 @@ S_STAGE_PICK = "stage_pick"
|
|
|
231
232
|
S_EXECUTOR = "executor"
|
|
232
233
|
S_CRITIC_PICK = "critic_pick"
|
|
233
234
|
S_CRITIC_TEXT = "critic_text"
|
|
235
|
+
S_REUSE_PREVIOUS = "reuse_previous"
|
|
234
236
|
S_DEFAULTS_OR_CUSTOM = "defaults_or_custom"
|
|
235
237
|
S_WORKERS_OVERRIDE = "workers_override"
|
|
236
238
|
S_LEAD_MODEL = "lead_model"
|
|
@@ -321,6 +323,9 @@ class WizardState:
|
|
|
321
323
|
critic: str = ""
|
|
322
324
|
critic_pending_text: bool = False
|
|
323
325
|
|
|
326
|
+
# resume: 직전 run-inputs 재사용 여부 (None=미응답, True=재사용, False=재입력)
|
|
327
|
+
reuse_previous: Optional[bool] = None
|
|
328
|
+
|
|
324
329
|
# customize
|
|
325
330
|
use_defaults: Optional[bool] = None
|
|
326
331
|
workers_override: str = ""
|
|
@@ -1393,31 +1398,18 @@ def _suggest_latest_final_report(state: WizardState) -> str:
|
|
|
1393
1398
|
return str(best)
|
|
1394
1399
|
|
|
1395
1400
|
|
|
1401
|
+
def _latest_run_inputs(
|
|
1402
|
+
state: WizardState, *, phase_segment: str = ""
|
|
1403
|
+
) -> dict:
|
|
1404
|
+
"""직전 run 의 입력 스냅샷. 위치/구조 지식은 run_context.latest_run_inputs 가 SSOT."""
|
|
1405
|
+
return latest_run_inputs(
|
|
1406
|
+
state.project_root, state.task_group, state.task_id,
|
|
1407
|
+
phase_segment=phase_segment)
|
|
1408
|
+
|
|
1409
|
+
|
|
1396
1410
|
def _suggest_last_directive(state: WizardState) -> str:
|
|
1397
1411
|
"""같은 task 의 가장 최근 run-inputs-*.json 에서 directive 값을 자동 추출."""
|
|
1398
|
-
|
|
1399
|
-
return ""
|
|
1400
|
-
runs_base = task_runs_dir(state.project_root, state.task_group, state.task_id)
|
|
1401
|
-
if not runs_base.is_dir():
|
|
1402
|
-
return ""
|
|
1403
|
-
candidates: list[tuple[float, Path]] = []
|
|
1404
|
-
for phase_dir in runs_base.iterdir():
|
|
1405
|
-
if not phase_dir.is_dir():
|
|
1406
|
-
continue
|
|
1407
|
-
for run_dir in phase_dir.iterdir():
|
|
1408
|
-
for inp in run_dir.glob("run-inputs-*.json"):
|
|
1409
|
-
try:
|
|
1410
|
-
candidates.append((inp.stat().st_mtime, inp))
|
|
1411
|
-
except OSError:
|
|
1412
|
-
continue
|
|
1413
|
-
if not candidates:
|
|
1414
|
-
return ""
|
|
1415
|
-
candidates.sort(key=lambda x: -x[0])
|
|
1416
|
-
try:
|
|
1417
|
-
data = json.loads(candidates[0][1].read_text(encoding="utf-8"))
|
|
1418
|
-
except (OSError, json.JSONDecodeError):
|
|
1419
|
-
return ""
|
|
1420
|
-
val = data.get("directive") or ""
|
|
1412
|
+
val = _latest_run_inputs(state).get("directive") or ""
|
|
1421
1413
|
return val if isinstance(val, str) else ""
|
|
1422
1414
|
|
|
1423
1415
|
|
|
@@ -1697,6 +1689,81 @@ def _submit_executor(state: WizardState, value: str) -> Optional[str]:
|
|
|
1697
1689
|
return f"executor: {value}"
|
|
1698
1690
|
|
|
1699
1691
|
|
|
1692
|
+
# resume 재사용을 제안하는 phase. okstra.sh --resume-clarification 과 동일하게
|
|
1693
|
+
# §1 clarification 을 갖는 비-implementation phase 로 한정한다(implementation 은
|
|
1694
|
+
# approved-plan/stage 가 매 run 고유라 재사용 대상이 아니다).
|
|
1695
|
+
_RESUME_REUSE_PHASES = (
|
|
1696
|
+
"requirements-discovery", "error-analysis", "implementation-planning")
|
|
1697
|
+
|
|
1698
|
+
# YES 선택 시 prefill 로 충족되어 다시 묻지 않는 설정 단계들.
|
|
1699
|
+
_REUSE_FILLED_STEPS = (
|
|
1700
|
+
S_DEFAULTS_OR_CUSTOM, S_WORKERS_OVERRIDE, S_LEAD_MODEL, S_EXECUTOR_MODEL,
|
|
1701
|
+
S_CLAUDE_MODEL, S_CODEX_MODEL, S_GEMINI_MODEL, S_REPORT_WRITER_MODEL,
|
|
1702
|
+
S_DIRECTIVE_PICK, S_DIRECTIVE, S_RELATED_TASKS_PICK, S_RELATED_TASKS,
|
|
1703
|
+
S_CLARIFICATION_PICK, S_CLARIFICATION)
|
|
1704
|
+
|
|
1705
|
+
|
|
1706
|
+
def _has_prior_run_inputs(state: WizardState) -> bool:
|
|
1707
|
+
seg = slugify_task_segment(state.task_type) if state.task_type else ""
|
|
1708
|
+
return bool(_latest_run_inputs(state, phase_segment=seg))
|
|
1709
|
+
|
|
1710
|
+
|
|
1711
|
+
def _safe_model(provider: str, raw: object) -> str:
|
|
1712
|
+
"""run-inputs 의 모델 display 값을 wizard 필드로 환원. 알 수 없는 값은
|
|
1713
|
+
빈 문자열(phase 기본값)로 안전하게 떨어뜨린다."""
|
|
1714
|
+
if not isinstance(raw, str):
|
|
1715
|
+
return ""
|
|
1716
|
+
try:
|
|
1717
|
+
return _validate_model(provider, raw)
|
|
1718
|
+
except WizardError:
|
|
1719
|
+
return ""
|
|
1720
|
+
|
|
1721
|
+
|
|
1722
|
+
def _build_reuse_previous(state: WizardState) -> Prompt:
|
|
1723
|
+
t = _p(state.workspace_root, "reuse_previous")
|
|
1724
|
+
return Prompt(
|
|
1725
|
+
step=S_REUSE_PREVIOUS, kind="pick",
|
|
1726
|
+
label=t["label"],
|
|
1727
|
+
options=[_opt(k, v) for k, v in t["options"].items()],
|
|
1728
|
+
echo_template=t["echo_template"],
|
|
1729
|
+
)
|
|
1730
|
+
|
|
1731
|
+
|
|
1732
|
+
def _submit_reuse_previous(state: WizardState, value: str) -> Optional[str]:
|
|
1733
|
+
if value not in ("yes", "no"):
|
|
1734
|
+
raise WizardError(f"expected 'yes' or 'no', got: {value!r}")
|
|
1735
|
+
if value == "no":
|
|
1736
|
+
state.reuse_previous = False
|
|
1737
|
+
return "reuse-previous: no (step-by-step re-entry)"
|
|
1738
|
+
state.reuse_previous = True
|
|
1739
|
+
seg = slugify_task_segment(state.task_type)
|
|
1740
|
+
inputs = _latest_run_inputs(state, phase_segment=seg)
|
|
1741
|
+
state.use_defaults = False
|
|
1742
|
+
workers = inputs.get("workers")
|
|
1743
|
+
state.workers_override = (
|
|
1744
|
+
",".join(w for w in workers if isinstance(w, str))
|
|
1745
|
+
if isinstance(workers, list) else "")
|
|
1746
|
+
state.lead_model = _safe_model("claude", inputs.get("leadModel"))
|
|
1747
|
+
state.claude_model = _safe_model("claude", inputs.get("claudeModel"))
|
|
1748
|
+
state.codex_model = _safe_model("codex", inputs.get("codexModel"))
|
|
1749
|
+
state.gemini_model = _safe_model("gemini", inputs.get("geminiModel"))
|
|
1750
|
+
state.report_writer_model = _safe_model(
|
|
1751
|
+
"claude", inputs.get("reportWriterModel"))
|
|
1752
|
+
directive = inputs.get("directive")
|
|
1753
|
+
state.directive = directive if isinstance(directive, str) else ""
|
|
1754
|
+
related = inputs.get("relatedTasks")
|
|
1755
|
+
state.related_tasks_raw = related if isinstance(related, str) else ""
|
|
1756
|
+
# clarification 은 직전 run 의 입력이 아니라 "직전 run 의 산출물(가장 최근
|
|
1757
|
+
# final-report)" 을 재실행 입력으로 자동 선택한다 — resume-clarification 의 본질.
|
|
1758
|
+
state.clarification_response_path = _suggest_latest_final_report(state)
|
|
1759
|
+
for sid in _REUSE_FILLED_STEPS:
|
|
1760
|
+
if sid not in state.answered:
|
|
1761
|
+
state.answered.append(sid)
|
|
1762
|
+
return (f"reuse-previous: yes "
|
|
1763
|
+
f"(workers={state.workers_override or 'profile-default'}, "
|
|
1764
|
+
f"lead-model={state.lead_model or 'default'})")
|
|
1765
|
+
|
|
1766
|
+
|
|
1700
1767
|
def _build_defaults_or_custom(state: WizardState) -> Prompt:
|
|
1701
1768
|
t = _p(state.workspace_root, "defaults_or_custom")
|
|
1702
1769
|
return Prompt(
|
|
@@ -2158,6 +2225,18 @@ STEPS: list[Step] = [
|
|
|
2158
2225
|
applies=lambda s: (s.critic_pending_text and S_CRITIC_TEXT not in s.answered),
|
|
2159
2226
|
build=_build_critic_text, submit=_submit_critic_text,
|
|
2160
2227
|
owns=("critic", "critic_pending_text")),
|
|
2228
|
+
# resume: identity 가 모두 정해진 뒤(직전 run 과 같은 task/phase 가 확정),
|
|
2229
|
+
# 모델/워커/directive/related/clarification 설정 단계로 들어가기 직전에
|
|
2230
|
+
# "직전 run 설정 그대로 재사용?" 를 한 번 묻는다. YES 면 그 단계들을 prefill 로
|
|
2231
|
+
# 충족시켜 곧장 confirm 으로 직행하고, NO 면 현행대로 단계별 입력을 받는다.
|
|
2232
|
+
Step(S_REUSE_PREVIOUS,
|
|
2233
|
+
applies=lambda s: (_identity_ready(s)
|
|
2234
|
+
and s.use_defaults is None
|
|
2235
|
+
and s.reuse_previous is None
|
|
2236
|
+
and s.task_type in _RESUME_REUSE_PHASES
|
|
2237
|
+
and _has_prior_run_inputs(s)),
|
|
2238
|
+
build=_build_reuse_previous, submit=_submit_reuse_previous,
|
|
2239
|
+
owns=("reuse_previous",)),
|
|
2161
2240
|
Step(S_DEFAULTS_OR_CUSTOM,
|
|
2162
2241
|
applies=lambda s: (_identity_ready(s)
|
|
2163
2242
|
and s.use_defaults is None),
|
|
@@ -2365,6 +2444,7 @@ _FIELD_DEFAULTS: dict[str, Any] = {
|
|
|
2365
2444
|
"approved_plan_pending_text": False,
|
|
2366
2445
|
"selected_stage": "auto",
|
|
2367
2446
|
"executor": "", "critic": "", "critic_pending_text": False,
|
|
2447
|
+
"reuse_previous": None,
|
|
2368
2448
|
"use_defaults": None, "workers_override": "",
|
|
2369
2449
|
"lead_model": "", "claude_model": "", "codex_model": "",
|
|
2370
2450
|
"gemini_model": "", "report_writer_model": "", "directive": "",
|
|
@@ -35,8 +35,9 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
|
|
|
35
35
|
{% if clarificationCarryIn and clarificationCarryIn.sourceFile %}
|
|
36
36
|
## 0. Clarification Response Carried In From Previous Run
|
|
37
37
|
|
|
38
|
+
{{ t("sectionIntro.clarificationCarryIn") }}
|
|
39
|
+
|
|
38
40
|
- Source file: `{{ clarificationCarryIn.sourceFile }}`
|
|
39
|
-
- {{ t("sectionIntro.clarificationCarryIn") }}
|
|
40
41
|
|
|
41
42
|
{% endif %}
|
|
42
43
|
## Summary of the Problem or Verification Target
|
|
@@ -78,12 +79,6 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
|
|
|
78
79
|
{% for row in clarificationItems -%}
|
|
79
80
|
| **{{ row.id }}**<br>Ticket: `{{ row.ticketId }}`<br>Kind: `{{ row.kind }}`<br>Blocks: `{{ row.blocks }}`<br>Status: {{ row.status }} | {{ row.statement }} | {{ row.expectedForm }} | {{ row.userInput or '' }} |
|
|
80
81
|
{% endfor %}
|
|
81
|
-
|
|
82
|
-
{{ t("clarification.columnGuide") }}
|
|
83
|
-
|
|
84
|
-
- **`Kind`** ∈ `{material, decision, data-point}`.
|
|
85
|
-
- **`Blocks`** ∈ `{approval, next-phase, none}`.
|
|
86
|
-
- **`Status`** ∈ `{open, answered, resolved, obsolete}`.
|
|
87
82
|
{%- endif %}
|
|
88
83
|
|
|
89
84
|
## 2. Evidence and Detailed Analysis
|
|
@@ -241,11 +236,19 @@ implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
|
|
|
241
236
|
## 5.5.{{ stage.stage }} Stage {{ stage.stage }}: {{ stage.title }}
|
|
242
237
|
|
|
243
238
|
Slice value: {{ stage.sliceValue }}
|
|
239
|
+
|
|
244
240
|
Acceptance: {{ stage.acceptance }}
|
|
245
|
-
|
|
246
|
-
{%
|
|
247
|
-
|
|
241
|
+
|
|
242
|
+
{% if stage.conformanceTests %}
|
|
243
|
+
Conformance tests: stage-{{ stage.stage }} — {{ stage.conformanceTests }}
|
|
244
|
+
{% else %}
|
|
245
|
+
Conformance exemption: {{ stage.conformanceExemption }}
|
|
246
|
+
{% endif %}
|
|
247
|
+
{% if stage.tddExemption %}
|
|
248
|
+
|
|
249
|
+
TDD exemption: {{ stage.tddExemption }}
|
|
248
250
|
{% endif %}
|
|
251
|
+
|
|
249
252
|
### Carry-In
|
|
250
253
|
|
|
251
254
|
{{ stage.carryIn }}
|
|
@@ -126,8 +126,7 @@
|
|
|
126
126
|
},
|
|
127
127
|
"clarification": {
|
|
128
128
|
"fillAndRerun": "Fill in your answers then re-run the same phase:",
|
|
129
|
-
"separateTerminalLabel": "Separate terminal"
|
|
130
|
-
"columnGuide": "Record cell field values:"
|
|
129
|
+
"separateTerminalLabel": "Separate terminal"
|
|
131
130
|
},
|
|
132
131
|
"followUpTasks": {
|
|
133
132
|
"headingAside": "Follow-up Tasks"
|