okstra 0.196.0 → 0.197.1
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/dist/cli-registry.mjs +6 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/docs/cli.md +14 -1
- package/docs/project-structure-overview.md +1 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/host-orchestration/implementation-planning.md +56 -0
- package/runtime/prompts/lead/plan-body-verification.md +21 -3
- package/runtime/prompts/profiles/implementation-planning.md +3 -2
- package/runtime/prompts/wizard/prompts.ko.json +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +15 -0
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +15 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +15 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +12 -10
- package/runtime/python/okstra_ctl/blocking_checks.py +19 -0
- package/runtime/python/okstra_ctl/conformance.py +36 -5
- package/runtime/python/okstra_ctl/dispatch_core.py +11 -6
- package/runtime/python/okstra_ctl/dispatch_state.py +11 -7
- package/runtime/python/okstra_ctl/domain/worker_stream.py +4 -5
- package/runtime/python/okstra_ctl/final_report_schema.py +62 -1
- package/runtime/python/okstra_ctl/group_context.py +96 -3
- package/runtime/python/okstra_ctl/plan_items.py +14 -0
- package/runtime/python/okstra_ctl/plan_items_cli.py +45 -3
- package/runtime/python/okstra_ctl/run.py +77 -0
- package/runtime/python/okstra_ctl/session_transcript.py +4 -4
- package/runtime/python/okstra_ctl/set_work_status.py +30 -1
- package/runtime/python/okstra_ctl/stage_close.py +244 -0
- package/runtime/python/okstra_ctl/tdd_bypass.py +131 -0
- package/runtime/python/okstra_ctl/wizard/engine.py +27 -24
- package/runtime/python/okstra_ctl/wizard/picker_navigation.py +37 -14
- package/runtime/python/okstra_ctl/wizard/roles.py +16 -11
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +15 -1
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +45 -2
- package/runtime/skills/okstra-brief-gen/SKILL.md +24 -7
- package/runtime/skills/okstra-inspect/facets/recap.md +17 -1
- package/runtime/skills/okstra-run/SKILL.md +63 -4
- package/runtime/templates/reports/group-context.template.md +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +109 -23
- package/runtime/validators/validate-run.py +63 -8
|
@@ -41,6 +41,7 @@ from okstra_project.dirs import tasks_root as _okstra_tasks_root # noqa: E402
|
|
|
41
41
|
from okstra_project.resolver import resolve_architecture # noqa: E402
|
|
42
42
|
|
|
43
43
|
from okstra_ctl.conformance import ( # noqa: E402
|
|
44
|
+
conformance_result_file,
|
|
44
45
|
detect_surfaces,
|
|
45
46
|
exempt_stage_surface_conflicts,
|
|
46
47
|
evaluate_conformance,
|
|
@@ -56,6 +57,10 @@ from okstra_ctl.dispatch_state import ( # noqa: E402
|
|
|
56
57
|
v2_worker_state_key,
|
|
57
58
|
)
|
|
58
59
|
from okstra_ctl.paths import RunRef, okstra_home, project_rel # noqa: E402
|
|
60
|
+
from okstra_ctl.tdd_bypass import ( # noqa: E402
|
|
61
|
+
bypass_file as tdd_bypass_file,
|
|
62
|
+
granted_stages,
|
|
63
|
+
)
|
|
59
64
|
from okstra_ctl.reconcile import settle_run_row # noqa: E402
|
|
60
65
|
from okstra_ctl.report_contract import CURRENT_REPORT_SCHEMA_VERSION # noqa: E402
|
|
61
66
|
from okstra_ctl.release_gate import ( # noqa: E402
|
|
@@ -1700,7 +1705,7 @@ def _load_conformance_results(qa_dir: Path, manifest: dict) -> dict:
|
|
|
1700
1705
|
key = entry.get("stageKey") if isinstance(entry, dict) else None
|
|
1701
1706
|
if not isinstance(key, str) or not key:
|
|
1702
1707
|
continue
|
|
1703
|
-
sidecar = qa_dir
|
|
1708
|
+
sidecar = conformance_result_file(qa_dir, key)
|
|
1704
1709
|
if not sidecar.is_file():
|
|
1705
1710
|
continue
|
|
1706
1711
|
try:
|
|
@@ -1997,10 +2002,32 @@ def _approved_plan_conformance_manifest(
|
|
|
1997
2002
|
}
|
|
1998
2003
|
|
|
1999
2004
|
|
|
2005
|
+
def _conformance_script_matches(actual: str, declared: str) -> bool:
|
|
2006
|
+
"""두 script 표기가 같은 파일을 가리키는지 판정한다.
|
|
2007
|
+
|
|
2008
|
+
1순위는 task-root 상대형끼리의 일치다. task_root 아래로 접히지 않는
|
|
2009
|
+
절대경로(예: 워크트리 경로로 적힌 선언)가 남으면, 남은 쪽이 다른 쪽을
|
|
2010
|
+
경로 경계에서 후행 일치하는지까지 본다 — `/…/wt/qa/scripts/s.ts` 와
|
|
2011
|
+
`qa/scripts/s.ts` 는 같은 파일이다. 후행 일치는 경계(`/`)를 요구하므로
|
|
2012
|
+
`renamed-stage-1.ts` 같은 다른 파일은 걸리지 않는다.
|
|
2013
|
+
"""
|
|
2014
|
+
if actual == declared:
|
|
2015
|
+
return True
|
|
2016
|
+
if not actual or not declared:
|
|
2017
|
+
return False
|
|
2018
|
+
if actual.startswith("/") != declared.startswith("/"):
|
|
2019
|
+
longer, shorter = (
|
|
2020
|
+
(actual, declared) if actual.startswith("/") else (declared, actual)
|
|
2021
|
+
)
|
|
2022
|
+
return longer.endswith("/" + shorter)
|
|
2023
|
+
return False
|
|
2024
|
+
|
|
2025
|
+
|
|
2000
2026
|
def _declared_conformance_errors(
|
|
2001
2027
|
declared_manifest: dict,
|
|
2002
2028
|
actual_manifest: dict,
|
|
2003
2029
|
stage_name: str | None,
|
|
2030
|
+
task_root: Path,
|
|
2004
2031
|
) -> list[str]:
|
|
2005
2032
|
"""Compare scoped plan declarations with their one actual manifest entry."""
|
|
2006
2033
|
declared = _scope_manifest_entries(declared_manifest, stage_name).get("entries", [])
|
|
@@ -2025,8 +2052,15 @@ def _declared_conformance_errors(
|
|
|
2025
2052
|
errors.append(f"stage {stage_number} has multiple matching entries")
|
|
2026
2053
|
continue
|
|
2027
2054
|
actual_entry = matches[0]
|
|
2028
|
-
|
|
2029
|
-
|
|
2055
|
+
# 양쪽을 같은 task-root 상대형으로 접은 뒤 대조한다 — 계획이 절대경로를,
|
|
2056
|
+
# 실행자가 상대형을 쓰면 같은 파일이 문자열로는 영영 안 맞는다.
|
|
2057
|
+
actual_script = _normalize_conformance_script(
|
|
2058
|
+
str(actual_entry.get("script") or ""), task_root
|
|
2059
|
+
)
|
|
2060
|
+
declared_script = _normalize_conformance_script(
|
|
2061
|
+
str(declaration.get("script") or ""), task_root
|
|
2062
|
+
)
|
|
2063
|
+
if not _conformance_script_matches(actual_script, declared_script):
|
|
2030
2064
|
errors.append(f"stage {stage_number} script mismatch")
|
|
2031
2065
|
actual_requires = actual_entry.get("requires")
|
|
2032
2066
|
actual_capabilities = (
|
|
@@ -2226,6 +2260,7 @@ def _validate_conformance(
|
|
|
2226
2260
|
declared_manifest,
|
|
2227
2261
|
empty_scoped_manifest,
|
|
2228
2262
|
stage_name,
|
|
2263
|
+
task_root,
|
|
2229
2264
|
):
|
|
2230
2265
|
failures.append(
|
|
2231
2266
|
f"conformance gate BLOCKING: approved plan {error}; "
|
|
@@ -2252,6 +2287,7 @@ def _validate_conformance(
|
|
|
2252
2287
|
declared_manifest,
|
|
2253
2288
|
manifest,
|
|
2254
2289
|
stage_name,
|
|
2290
|
+
task_root,
|
|
2255
2291
|
):
|
|
2256
2292
|
failures.append(
|
|
2257
2293
|
f"conformance gate BLOCKING: approved plan {error} "
|
|
@@ -6352,9 +6388,14 @@ def _plan_verify_dispatched_results(
|
|
|
6352
6388
|
# critic 동수 라운드는 `kind: "critic"` 으로 나간다 — 결과 파일명은
|
|
6353
6389
|
# 같은 `-plan-verify-r<N>-` 꼴이다. reverify 계열만 세면 동수가 있던
|
|
6354
6390
|
# run 마다 critic 표가 "디스패치 기록 없음" 으로 오탐된다(2026-09-09,
|
|
6355
|
-
# fontsninja-v3-site dev-10627 planning 002).
|
|
6391
|
+
# fontsninja-v3-site dev-10627 planning 002). 계획 본문 라운드 자신의
|
|
6392
|
+
# kind 인 `plan-verify-r<N>` 도 같은 이유로 센다.
|
|
6356
6393
|
kind = str(row.get("kind") or "")
|
|
6357
|
-
if not (
|
|
6394
|
+
if not (
|
|
6395
|
+
kind.startswith("reverify-r")
|
|
6396
|
+
or kind.startswith("plan-verify-r")
|
|
6397
|
+
or kind == "critic"
|
|
6398
|
+
):
|
|
6358
6399
|
continue
|
|
6359
6400
|
name = Path(str(row.get("workerResultPath") or "")).name
|
|
6360
6401
|
if "-plan-verify-r" not in name:
|
|
@@ -8003,13 +8044,19 @@ def _load_stage_validator():
|
|
|
8003
8044
|
return mod
|
|
8004
8045
|
|
|
8005
8046
|
|
|
8006
|
-
def _append_stage_data_failures(
|
|
8047
|
+
def _append_stage_data_failures(
|
|
8048
|
+
data: Mapping[str, Any], failures: list[str], task_root: Path | None = None,
|
|
8049
|
+
) -> None:
|
|
8007
8050
|
"""Run the stage relationship checks that schema v2 cannot express.
|
|
8008
8051
|
|
|
8009
8052
|
The depends-on DAG, parallel-stage file safety, RED→GREEN ordering, and
|
|
8010
8053
|
the TDD-exemption vocabulary are relationships between stages, which a
|
|
8011
8054
|
JSON Schema cannot state. They are enforced here, against the data.json,
|
|
8012
8055
|
by the same validator that owns the rule vocabulary.
|
|
8056
|
+
|
|
8057
|
+
`tddExemption: user-bypass` is the one reason the plan cannot assert by
|
|
8058
|
+
itself, so the user's grants are read from the task's own bypass ledger
|
|
8059
|
+
and passed in; without the task root no stage counts as granted.
|
|
8013
8060
|
"""
|
|
8014
8061
|
if (data or {}).get("schemaVersion") != CURRENT_REPORT_SCHEMA_VERSION:
|
|
8015
8062
|
return # Schema validation already rejected an unknown version.
|
|
@@ -8020,7 +8067,11 @@ def _append_stage_data_failures(data: Mapping[str, Any], failures: list[str]) ->
|
|
|
8020
8067
|
if mod is None: # pragma: no cover — repo/runtime always ship the file
|
|
8021
8068
|
failures.append(f"cannot load Stage Map validator at {_STAGE_VALIDATOR_PATH}")
|
|
8022
8069
|
return
|
|
8023
|
-
|
|
8070
|
+
granted = (
|
|
8071
|
+
frozenset(granted_stages(tdd_bypass_file(task_root)))
|
|
8072
|
+
if task_root is not None else frozenset()
|
|
8073
|
+
)
|
|
8074
|
+
for e in mod.collect_data_validation_errors(dict(planning), granted):
|
|
8024
8075
|
failures.append(
|
|
8025
8076
|
f"implementation-planning stage contract invalid "
|
|
8026
8077
|
f"[{e.code} stage={e.stage}]: {e.message}"
|
|
@@ -9485,7 +9536,11 @@ def main() -> int:
|
|
|
9485
9536
|
)
|
|
9486
9537
|
_validate_stage_has_requirement(validation_data, failures)
|
|
9487
9538
|
if task_type == "implementation-planning":
|
|
9488
|
-
_append_stage_data_failures(
|
|
9539
|
+
_append_stage_data_failures(
|
|
9540
|
+
validation_data,
|
|
9541
|
+
failures,
|
|
9542
|
+
_task_root_from_run_dir(report_path.parent.parent),
|
|
9543
|
+
)
|
|
9489
9544
|
if task_type == "improvement-discovery":
|
|
9490
9545
|
run_dir = report_path.parent.parent
|
|
9491
9546
|
_validate_improvement_discovery(report_path, run_dir, brief_path, failures)
|