okstra 0.159.0 → 0.161.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/README.md +1 -1
- package/docs/architecture/storage-model.md +2 -0
- package/docs/architecture.md +2 -1
- package/docs/cli.md +8 -3
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-inspect.md +3 -0
- package/docs/for-ai/skills/okstra-run.md +2 -1
- package/docs/for-ai/skills/okstra-user-response.md +5 -5
- package/docs/project-structure-overview.md +5 -1
- package/docs/task-process/implementation.md +28 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/okstra-claude-exec.sh +4 -1
- package/runtime/prompts/host-orchestration/README.md +18 -0
- package/runtime/prompts/host-orchestration/implementation.md +57 -0
- package/runtime/prompts/launch.template.md +10 -1
- package/runtime/prompts/lead/adapters/claude-code.md +1 -1
- package/runtime/prompts/lead/adapters/cmux.md +67 -0
- package/runtime/prompts/lead/context-loader.md +5 -2
- package/runtime/prompts/lead/convergence.md +3 -1
- package/runtime/prompts/lead/plan-body-verification.md +21 -2
- package/runtime/prompts/lead/team-contract.md +2 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +11 -1
- package/runtime/prompts/profiles/_common-contract.md +3 -1
- package/runtime/prompts/profiles/implementation-planning.md +2 -0
- package/runtime/prompts/profiles/requirements-discovery.md +1 -1
- package/runtime/prompts/wizard/prompts.ko.json +3 -0
- package/runtime/python/okstra_ctl/clarification_items.py +9 -0
- package/runtime/python/okstra_ctl/cmux.py +531 -0
- package/runtime/python/okstra_ctl/codex_dispatch.py +6 -6
- package/runtime/python/okstra_ctl/convergence.py +168 -11
- package/runtime/python/okstra_ctl/dispatch_core.py +76 -7
- package/runtime/python/okstra_ctl/dispatch_state.py +16 -0
- package/runtime/python/okstra_ctl/error_issue.py +640 -0
- package/runtime/python/okstra_ctl/error_report.py +56 -0
- package/runtime/python/okstra_ctl/error_zip.py +23 -10
- package/runtime/python/okstra_ctl/incremental_scope.py +159 -19
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +18 -5
- package/runtime/python/okstra_ctl/issue_signals.py +186 -0
- package/runtime/python/okstra_ctl/lead_runtime.py +30 -2
- package/runtime/python/okstra_ctl/paths.py +38 -0
- package/runtime/python/okstra_ctl/plan_items_cli.py +167 -3
- package/runtime/python/okstra_ctl/profile_show.py +134 -0
- package/runtime/python/okstra_ctl/recap.py +63 -0
- package/runtime/python/okstra_ctl/render.py +7 -2
- package/runtime/python/okstra_ctl/render_final_report.py +7 -22
- package/runtime/python/okstra_ctl/report_translation.py +4 -0
- package/runtime/python/okstra_ctl/report_views.py +7 -3
- package/runtime/python/okstra_ctl/run.py +54 -3
- package/runtime/python/okstra_ctl/run_audit.py +477 -0
- package/runtime/python/okstra_ctl/team.py +50 -11
- package/runtime/python/okstra_ctl/user_response.py +25 -10
- package/runtime/python/okstra_ctl/verdict_blocks.py +183 -0
- package/runtime/python/okstra_ctl/wizard.py +64 -10
- package/runtime/python/okstra_ctl/worker_audit_check.py +44 -0
- package/runtime/python/okstra_ctl/worker_audit_ledger.py +207 -0
- package/runtime/python/okstra_ctl/worker_heartbeat.py +9 -3
- package/runtime/python/okstra_ctl/worker_liveness.py +81 -9
- package/runtime/schemas/final-report-v1.0.schema.json +14 -0
- package/runtime/schemas/final-report-v2.0.schema.json +51 -1
- package/runtime/skills/okstra-inspect/SKILL.md +3 -1
- package/runtime/skills/okstra-inspect/facets/error-issue.md +77 -0
- package/runtime/skills/okstra-inspect/facets/run-audit.md +34 -0
- package/runtime/skills/okstra-run/SKILL.md +28 -10
- package/runtime/skills/okstra-user-response/SKILL.md +18 -18
- package/runtime/templates/reports/final-report.template.md +4 -0
- package/runtime/templates/reports/html/i18n/en.json +5 -1
- package/runtime/templates/reports/html/i18n/ko.json +5 -1
- package/runtime/templates/reports/html/macros/forms.html +15 -0
- package/runtime/templates/reports/html/tasks/implementation-planning.template.html +1 -0
- package/runtime/templates/reports/i18n/en.json +2 -0
- package/runtime/validators/validate-run.py +267 -208
- package/runtime/validators/validate-workflow.sh +6 -0
- package/runtime/validators/validate_session_conformance.py +135 -31
- package/src/cli-registry.mjs +34 -0
- package/src/commands/execute/incremental-scope.mjs +10 -0
- package/src/commands/execute/worker-audit-check.mjs +35 -0
- package/src/commands/inspect/error-issue.mjs +27 -0
- package/src/commands/inspect/profile-show.mjs +29 -0
- package/src/commands/inspect/run-audit.mjs +26 -0
|
@@ -6,7 +6,7 @@ Design: docs/superpowers/specs/2026-06-10-blocking-contract-posthoc-conformance-
|
|
|
6
6
|
|-------|----------|----------|
|
|
7
7
|
| 1. lead PROGRESS checkpoints | prompts/lead/okstra-lead-contract.md "Progress reporting (BLOCKING)" | selected adapter evidence source |
|
|
8
8
|
| 2. worker-provider heartbeat | worker provider contract | audit sidecar `- PROGRESS: <stage> <ISO>` lines |
|
|
9
|
-
| 3. implementation
|
|
9
|
+
| 3. implementation entry guard | prompts/lead/okstra-lead-contract.md "Entry guard (BLOCKING)" + prompts/launch.template.md "Host Orchestration Rules" (only when the run staged the rules file) | selected adapter evidence source |
|
|
10
10
|
|
|
11
11
|
Evidence rules prevent false passes:
|
|
12
12
|
- `claude-jsonl` accepts only assistant text and Read tool-use records, excluding
|
|
@@ -25,7 +25,7 @@ import sys
|
|
|
25
25
|
from dataclasses import dataclass, field
|
|
26
26
|
from datetime import datetime
|
|
27
27
|
from pathlib import Path
|
|
28
|
-
from typing import Any, Mapping
|
|
28
|
+
from typing import Any, Mapping, NamedTuple
|
|
29
29
|
|
|
30
30
|
# scripts/ (repo) and python/ (installed under ~/.okstra/lib) are not packages;
|
|
31
31
|
# insert whichever exists so okstra_ctl is importable directly.
|
|
@@ -36,6 +36,7 @@ for _ssot_dir in (_VALIDATORS_DIR.parent / "scripts", _VALIDATORS_DIR.parent / "
|
|
|
36
36
|
|
|
37
37
|
from okstra_ctl.worker_heartbeat import ( # noqa: E402
|
|
38
38
|
HEARTBEAT_LINE_RE,
|
|
39
|
+
IN_STAGE_PREFIX,
|
|
39
40
|
max_gap_seconds_after,
|
|
40
41
|
)
|
|
41
42
|
from okstra_ctl.lead_runtime import ARTIFACT_ONLY_LEAD_RUNTIMES # noqa: E402
|
|
@@ -67,16 +68,62 @@ _PROGRESS_LINE_RE = re.compile(
|
|
|
67
68
|
# heartbeat 라인 shape 과 cadence 예산은 okstra_ctl.worker_heartbeat 정본을 쓴다 —
|
|
68
69
|
# `okstra worker-liveness` 가 run 도중 같은 판정을 내리므로 정의가 갈리면 안 된다.
|
|
69
70
|
_HEARTBEAT_LINE_RE = HEARTBEAT_LINE_RE
|
|
71
|
+
_IN_STAGE_PREFIX = IN_STAGE_PREFIX
|
|
72
|
+
|
|
73
|
+
_LEAD_CONTRACT_CITE = "prompts/lead/okstra-lead-contract.md 'Entry guard (BLOCKING)'"
|
|
74
|
+
_HOST_RULES_CITE = "prompts/launch.template.md 'Host Orchestration Rules'"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _EntryGuardRead(NamedTuple):
|
|
78
|
+
"""implementation entry guard 가 Read 를 요구하는 파일 한 건."""
|
|
79
|
+
|
|
80
|
+
basename: str
|
|
81
|
+
# (이 Read 가 앞서야 할 PROGRESS 체크포인트, 실패 메시지에 쓸 시점 표현).
|
|
82
|
+
# None 이면 순서 제약이 없고 run 윈도우 안의 존재만 검사한다.
|
|
83
|
+
anchor: tuple[str, str] | None
|
|
84
|
+
cite: str
|
|
85
|
+
# True 면 run 이 이 파일을 instruction-set 에 스테이징했을 때만 요구한다.
|
|
86
|
+
staged_per_run: bool = False
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
_ENTRY_GUARD_READS = (
|
|
90
|
+
_EntryGuardRead(
|
|
91
|
+
"_implementation-executor.md", ("phase-6-synthesis", "at Phase 5"), _LEAD_CONTRACT_CITE
|
|
92
|
+
),
|
|
93
|
+
_EntryGuardRead(
|
|
94
|
+
"_implementation-verifier.md", ("phase-6-synthesis", "at Phase 5"), _LEAD_CONTRACT_CITE
|
|
95
|
+
),
|
|
96
|
+
_EntryGuardRead(
|
|
97
|
+
"_implementation-deliverable.md", ("phase-7-persist", "at Phase 6"), _LEAD_CONTRACT_CITE
|
|
98
|
+
),
|
|
99
|
+
# lead 프로파일 sidecar 가 아니라, run 이 instruction-set 에 스테이징한 host
|
|
100
|
+
# orchestration 규칙이다. 세 가지가 sidecar 와 다르다.
|
|
101
|
+
#
|
|
102
|
+
# anchor 없음: 이 파일은 `render-bundle` 이 만든다(run.py `_write_instruction_set_sources`).
|
|
103
|
+
# 그 앞에서 발화하는 gate(Step 5.1 waiver 제안)에는 아직 파일이 없고, 뒤에
|
|
104
|
+
# 오는 gate 는 run 의 PROGRESS 체크포인트와 시간 관계가 고정돼 있지 않다.
|
|
105
|
+
# 증거가 뒷받침하는 주장은 "run 윈도우 안에 Read 가 최소 한 번" 뿐이다.
|
|
106
|
+
# staged_per_run: 파일이 없는 번들 — 이 변경 전에 렌더된 run, 또는 payload 에
|
|
107
|
+
# prompts/host-orchestration/<task-type>.md 가 없는 설치본 — 은 읽을 수 없는
|
|
108
|
+
# 파일 때문에 막히면 안 된다. 규칙이 없는 task-type 에 conformance 가 규칙을
|
|
109
|
+
# 요구하지 않는다는 원칙과 같은 판단이다.
|
|
110
|
+
_EntryGuardRead(
|
|
111
|
+
"host-orchestration-rules.md", None, _HOST_RULES_CITE, staged_per_run=True
|
|
112
|
+
),
|
|
113
|
+
)
|
|
70
114
|
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
115
|
+
# 환경으로 선택되는 어댑터라 lead 의 런타임이 이 파일을 가르쳐 주지 않는다.
|
|
116
|
+
# 읽지 않은 lead 는 자기 런타임이 아는 방식 — cmux 경로에서는 okstra 가 소유한
|
|
117
|
+
# 디스패치를 host 네이티브로 가로채는 방식 — 으로 되돌아간다.
|
|
118
|
+
CMUX_ADAPTER_BASENAME = "cmux.md"
|
|
119
|
+
CMUX_ADAPTER_NAME = "cmux"
|
|
120
|
+
_CMUX_ADAPTER_CITE = "prompts/lead/adapters/cmux.md"
|
|
121
|
+
|
|
122
|
+
# Read 증거는 basename 으로 거른다 — 절대 경로는 레이어(repo / runtime / 설치본)
|
|
123
|
+
# 마다 다르지만 basename 은 동일하다. 목록이 갈리지 않도록 기대치에서 파생한다.
|
|
124
|
+
_TRACKED_READ_BASENAMES = (
|
|
125
|
+
*(row.basename for row in _ENTRY_GUARD_READS),
|
|
126
|
+
CMUX_ADAPTER_BASENAME,
|
|
80
127
|
)
|
|
81
128
|
|
|
82
129
|
|
|
@@ -171,7 +218,7 @@ def _scan_one_jsonl(
|
|
|
171
218
|
progress.append((ts, m.group("phase"), line))
|
|
172
219
|
elif block.get("type") == "tool_use" and block.get("name") == "Read":
|
|
173
220
|
base = Path(str((block.get("input") or {}).get("file_path") or "")).name
|
|
174
|
-
if base in
|
|
221
|
+
if base in _TRACKED_READ_BASENAMES:
|
|
175
222
|
reads.setdefault(base, []).append(ts)
|
|
176
223
|
return progress, reads, agent_name
|
|
177
224
|
|
|
@@ -297,7 +344,7 @@ def _sidecar_read_from_event(event) -> tuple[str, str] | None:
|
|
|
297
344
|
if not isinstance(basename, str) or not basename:
|
|
298
345
|
raw_path = details.get("path") or details.get("filePath")
|
|
299
346
|
basename = Path(str(raw_path or "")).name
|
|
300
|
-
if basename not in
|
|
347
|
+
if basename not in _TRACKED_READ_BASENAMES:
|
|
301
348
|
return None
|
|
302
349
|
return (basename, event.timestamp)
|
|
303
350
|
|
|
@@ -696,36 +743,88 @@ def _check_worker_liveness(
|
|
|
696
743
|
errors.append(f"registered wrapper status sidecar unreadable: {path}")
|
|
697
744
|
|
|
698
745
|
|
|
699
|
-
def
|
|
746
|
+
def _instruction_set_dir(run_dir: Path, suffix: str | None, project_root: Path) -> Path | None:
|
|
747
|
+
"""이 run 의 instruction-set 디렉터리. 해소 불가면 None (경로를 모르면 스테이징
|
|
748
|
+
여부도 판정할 수 없고, 모르는 것을 근거로 run 을 떨어뜨리지 않는다)."""
|
|
749
|
+
if not suffix:
|
|
750
|
+
return None
|
|
751
|
+
manifest = run_dir / "manifests" / f"run-manifest-{suffix}.json"
|
|
752
|
+
try:
|
|
753
|
+
data = json.loads(manifest.read_text(encoding="utf-8"))
|
|
754
|
+
except (OSError, json.JSONDecodeError, UnicodeDecodeError):
|
|
755
|
+
return None
|
|
756
|
+
raw = data.get("instructionSetPath") if isinstance(data, dict) else None
|
|
757
|
+
if not isinstance(raw, str) or not raw:
|
|
758
|
+
return None
|
|
759
|
+
path = Path(raw)
|
|
760
|
+
if not path.is_absolute():
|
|
761
|
+
path = project_root / path
|
|
762
|
+
return path if path.is_dir() else None
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
def _check_cmux_adapter_read(
|
|
766
|
+
evidence: _LeadEvidence, team_state: dict, errors: list[str]
|
|
767
|
+
) -> None:
|
|
768
|
+
"""검사 4 — cmux 어댑터 읽음. 모든 task-type 에 적용된다.
|
|
769
|
+
|
|
770
|
+
다른 어댑터는 lead 의 런타임이 고르지만 이것은 환경이 고른다. 그래서 읽지
|
|
771
|
+
않은 lead 에게는 이 경로가 존재한다는 사실 자체가 닿지 않고, 자기 런타임이
|
|
772
|
+
아는 host 네이티브 디스패치로 되돌아간다 — cmux 경로에서 okstra 가 소유한
|
|
773
|
+
바로 그 일이다."""
|
|
774
|
+
adapter = team_state.get("leadAdapter")
|
|
775
|
+
name = str(adapter.get("name", "")).strip() if isinstance(adapter, dict) else ""
|
|
776
|
+
if name != CMUX_ADAPTER_NAME:
|
|
777
|
+
return
|
|
778
|
+
if evidence.sidecar_reads.get(CMUX_ADAPTER_BASENAME):
|
|
779
|
+
return
|
|
780
|
+
errors.append(
|
|
781
|
+
f"cmux adapter: no `Read` of `{CMUX_ADAPTER_BASENAME}` found in the "
|
|
782
|
+
"selected adapter evidence source within this run's window — the cmux "
|
|
783
|
+
"adapter is selected by environment, not by lead runtime, so it MUST be "
|
|
784
|
+
f"read before dispatch ({_CMUX_ADAPTER_CITE})."
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
def _check_implementation_entry_guard(
|
|
789
|
+
evidence: _LeadEvidence, errors: list[str], instruction_set: Path | None
|
|
790
|
+
) -> None:
|
|
700
791
|
"""검사 3 — entry guard. fresh-read 규칙(이전 run 기억으로 갈음 불가)은 run
|
|
701
|
-
윈도우 스코핑이 보장한다: 이번 윈도우 안의 Read 만 증거로 인정된다.
|
|
792
|
+
윈도우 스코핑이 보장한다: 이번 윈도우 안의 Read 만 증거로 인정된다.
|
|
793
|
+
|
|
794
|
+
anchor 가 있는 행은 존재 + 순서를, anchor 가 `None` 인 행은 존재만 본다.
|
|
795
|
+
`staged_per_run` 행은 이 run 의 instruction-set 에 실제로 있을 때만 요구한다."""
|
|
702
796
|
anchors: dict[str, str] = {}
|
|
703
797
|
for ts, phase, _line in evidence.progress: # progress 는 ts 정렬 — 첫 항목이 최초 발생
|
|
704
798
|
if phase in ("phase-6-synthesis", "phase-7-persist") and ts:
|
|
705
799
|
anchors.setdefault(phase, ts)
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
ts_list = evidence.sidecar_reads.get(basename) or []
|
|
800
|
+
for row in _ENTRY_GUARD_READS:
|
|
801
|
+
if row.staged_per_run and not (
|
|
802
|
+
instruction_set and (instruction_set / row.basename).is_file()
|
|
803
|
+
):
|
|
804
|
+
continue
|
|
805
|
+
ts_list = evidence.sidecar_reads.get(row.basename) or []
|
|
713
806
|
if not ts_list:
|
|
807
|
+
demand = (
|
|
808
|
+
f"it MUST be read fresh {row.anchor[1]} of every implementation run"
|
|
809
|
+
if row.anchor
|
|
810
|
+
else "the staged copy MUST be read at least once inside that window"
|
|
811
|
+
)
|
|
714
812
|
errors.append(
|
|
715
|
-
f"implementation entry guard: no `Read` of `{basename}` found in "
|
|
716
|
-
"the selected adapter evidence source within this run's window — "
|
|
717
|
-
"
|
|
718
|
-
f"MUST be read fresh at {read_at} every implementation run "
|
|
719
|
-
"(prompts/lead/okstra-lead-contract.md 'Entry guard (BLOCKING)')."
|
|
813
|
+
f"implementation entry guard: no `Read` of `{row.basename}` found in "
|
|
814
|
+
f"the selected adapter evidence source within this run's window — "
|
|
815
|
+
f"{demand} ({row.cite})."
|
|
720
816
|
)
|
|
721
817
|
continue
|
|
818
|
+
if not row.anchor:
|
|
819
|
+
continue
|
|
820
|
+
anchor_phase, when = row.anchor
|
|
722
821
|
anchor_ts = anchors.get(anchor_phase)
|
|
723
822
|
if anchor_ts and min(ts_list) >= anchor_ts:
|
|
724
823
|
errors.append(
|
|
725
|
-
f"implementation entry guard: `{basename}` was first Read at "
|
|
824
|
+
f"implementation entry guard: `{row.basename}` was first Read at "
|
|
726
825
|
f"{min(ts_list)}, not before the first `PROGRESS: {anchor_phase}` "
|
|
727
|
-
f"line ({anchor_ts}) — it must be loaded
|
|
728
|
-
"that checkpoint (
|
|
826
|
+
f"line ({anchor_ts}) — it must be loaded {when}, before "
|
|
827
|
+
f"that checkpoint ({row.cite})."
|
|
729
828
|
)
|
|
730
829
|
|
|
731
830
|
|
|
@@ -771,6 +870,11 @@ def validate_session_conformance(
|
|
|
771
870
|
result.errors.append(error)
|
|
772
871
|
return result
|
|
773
872
|
_check_progress_checkpoints(evidence, team_state, run_dir, suffix, result.errors)
|
|
873
|
+
_check_cmux_adapter_read(evidence, team_state, result.errors)
|
|
774
874
|
if task_type == "implementation":
|
|
775
|
-
|
|
875
|
+
_check_implementation_entry_guard(
|
|
876
|
+
evidence,
|
|
877
|
+
result.errors,
|
|
878
|
+
_instruction_set_dir(run_dir, suffix, project_root),
|
|
879
|
+
)
|
|
776
880
|
return result
|
package/src/cli-registry.mjs
CHANGED
|
@@ -87,6 +87,16 @@ export const COMMAND_REGISTRY = [
|
|
|
87
87
|
category: "admin",
|
|
88
88
|
summary: ["Score the §5.5.9 plan-body gate for one self-fix round"],
|
|
89
89
|
},
|
|
90
|
+
{
|
|
91
|
+
name: "worker-audit-check",
|
|
92
|
+
module: "./commands/execute/worker-audit-check.mjs",
|
|
93
|
+
export: "run",
|
|
94
|
+
category: "admin",
|
|
95
|
+
summary: [
|
|
96
|
+
"Check a run's worker audit sidecars while the workers",
|
|
97
|
+
"are still alive (the Phase 7 rules, run early)",
|
|
98
|
+
],
|
|
99
|
+
},
|
|
90
100
|
{
|
|
91
101
|
name: "git-reconcile",
|
|
92
102
|
module: "./commands/execute/git-reconcile.mjs",
|
|
@@ -208,6 +218,20 @@ export const COMMAND_REGISTRY = [
|
|
|
208
218
|
category: "introspection",
|
|
209
219
|
summary: ["Bundle cross-project okstra error logs into a zip"],
|
|
210
220
|
},
|
|
221
|
+
{
|
|
222
|
+
name: "error-issue",
|
|
223
|
+
module: "./commands/inspect/error-issue.mjs",
|
|
224
|
+
export: "run",
|
|
225
|
+
category: "introspection",
|
|
226
|
+
summary: ["Turn okstra run anomalies into GitHub issue candidates"],
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: "run-audit",
|
|
230
|
+
module: "./commands/inspect/run-audit.mjs",
|
|
231
|
+
export: "run",
|
|
232
|
+
category: "introspection",
|
|
233
|
+
summary: ["Check okstra run artifacts against progress invariants"],
|
|
234
|
+
},
|
|
211
235
|
{
|
|
212
236
|
name: "recap",
|
|
213
237
|
module: "./commands/inspect/recap.mjs",
|
|
@@ -274,6 +298,16 @@ export const COMMAND_REGISTRY = [
|
|
|
274
298
|
"python3 -m okstra_ctl.run --render-only)",
|
|
275
299
|
],
|
|
276
300
|
},
|
|
301
|
+
{
|
|
302
|
+
name: "profile",
|
|
303
|
+
module: "./commands/inspect/profile-show.mjs",
|
|
304
|
+
export: "run",
|
|
305
|
+
category: "introspection",
|
|
306
|
+
summary: [
|
|
307
|
+
"Print a phase profile with {{INCLUDE:}} expanded and its",
|
|
308
|
+
"lazy-read sidecars appended (read-only)",
|
|
309
|
+
],
|
|
310
|
+
},
|
|
277
311
|
{
|
|
278
312
|
name: "run",
|
|
279
313
|
module: "./commands/execute/run.mjs",
|
|
@@ -10,8 +10,18 @@ instead of emitting a \`python3 "$HOME/..."\` invocation (which breaks
|
|
|
10
10
|
Usage:
|
|
11
11
|
okstra incremental-scope --prev-data <path> --cur-base-sha <sha> \\
|
|
12
12
|
--prev-base-sha <sha> [--impacted <csv>] [--option <name>]
|
|
13
|
+
okstra incremental-scope --preview --prev-data <path> \\
|
|
14
|
+
--answered-clarifications <csv>
|
|
13
15
|
|
|
14
16
|
Prints a JSON decision {mode, reverify_stages, carry_stages, reason} to stdout.
|
|
17
|
+
|
|
18
|
+
\`--preview\` prints {wouldForceFull, unlinkedIds, reason} instead and needs no
|
|
19
|
+
base SHA. It answers only the link half — whether the answered ids trace to a
|
|
20
|
+
stage in the prior report — so it can run before \`render-bundle\` fixes a
|
|
21
|
+
worktree base commit, while the decision to start is still reversible.
|
|
22
|
+
\`wouldForceFull: false\` is not a promise of \`incremental\`: the base-ref check
|
|
23
|
+
still runs at decision time.
|
|
24
|
+
|
|
15
25
|
All arguments are forwarded verbatim to the python helper.
|
|
16
26
|
`;
|
|
17
27
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { runPythonModule } from "../../lib/python-helper.mjs";
|
|
2
|
+
|
|
3
|
+
const USAGE = `okstra worker-audit-check — check one run's worker audit sidecars
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
okstra worker-audit-check --run-dir <runs/<task-type>/> --task-type <type> \\
|
|
7
|
+
--seq <nnn> [--worker <id>]
|
|
8
|
+
|
|
9
|
+
--run-dir the run directory; worker-results/ and prompts/ hang off it
|
|
10
|
+
--worker check only this worker (default: every worker in the run)
|
|
11
|
+
|
|
12
|
+
Emits one JSON object — \`{ok, failures[]}\` — and exits 2 when failures[] is
|
|
13
|
+
non-empty, 0 otherwise.
|
|
14
|
+
|
|
15
|
+
Runs the Phase 7 audit-sidecar rules now, while the worker session is still
|
|
16
|
+
alive: that every result file carries no \`## 0. Reading Confirmation\` heading,
|
|
17
|
+
that its audit sidecar exists, and that every backticked \`path:line\` citation
|
|
18
|
+
has a matching Evidence read row in that sidecar.
|
|
19
|
+
|
|
20
|
+
Call it right after collecting a worker result. The same failure at Phase 7
|
|
21
|
+
leaves only a retroactive edit — which breaks the audit chain — or a failed run.
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
export async function run(args) {
|
|
25
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
26
|
+
process.stdout.write(USAGE);
|
|
27
|
+
return args.length === 0 ? 2 : 0;
|
|
28
|
+
}
|
|
29
|
+
const result = await runPythonModule({
|
|
30
|
+
module: "okstra_ctl.worker_audit_check",
|
|
31
|
+
args,
|
|
32
|
+
stdio: "inherit-stdout",
|
|
33
|
+
});
|
|
34
|
+
return result.code;
|
|
35
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { runPythonModule } from "../../lib/python-helper.mjs";
|
|
2
|
+
|
|
3
|
+
const USAGE = `okstra error-issue — turn okstra run anomalies into GitHub issue candidates
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
okstra error-issue plan --out <path>
|
|
7
|
+
okstra error-issue submit --plan <path>
|
|
8
|
+
|
|
9
|
+
'plan' walks the global run-index, gates clusters by occurrence and recency,
|
|
10
|
+
computes classification signals from the raw records, checks GitHub for an
|
|
11
|
+
existing issue carrying the same fingerprint, and writes plan.json.
|
|
12
|
+
'submit' reads that file only, re-validates every candidate, and files or
|
|
13
|
+
comments via gh. A candidate that fails validation is never sent.
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
export async function run(args) {
|
|
17
|
+
if (args.includes("--help") || args.includes("-h") || args.length === 0) {
|
|
18
|
+
process.stdout.write(USAGE);
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
const result = await runPythonModule({
|
|
22
|
+
module: "okstra_ctl.error_issue",
|
|
23
|
+
args,
|
|
24
|
+
stdio: "inherit-stdout",
|
|
25
|
+
});
|
|
26
|
+
return result.code;
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { runPythonModule } from "../../lib/python-helper.mjs";
|
|
2
|
+
|
|
3
|
+
const USAGE = `okstra profile show — print a phase profile, fully resolved
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
okstra profile show <task-type> [--resolved]
|
|
7
|
+
|
|
8
|
+
--resolved expand {{INCLUDE:}} targets and append the lazy-read sidecars
|
|
9
|
+
|
|
10
|
+
A profile is assembled from the top-level body, its {{INCLUDE:}} targets, and
|
|
11
|
+
the sidecars its own table names — so grepping the top-level file and finding
|
|
12
|
+
nothing does not mean the rule is absent. This prints all of it, so one grep
|
|
13
|
+
answers "does this task-type cover X".
|
|
14
|
+
|
|
15
|
+
Read-only: writes no manifest and registers no run. That is what separates it
|
|
16
|
+
from 'okstra render-bundle', which answers the same question with side effects.
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export async function run(args) {
|
|
20
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
21
|
+
process.stdout.write(USAGE);
|
|
22
|
+
return args.length === 0 ? 2 : 0;
|
|
23
|
+
}
|
|
24
|
+
const { code } = await runPythonModule({
|
|
25
|
+
module: "okstra_ctl.profile_show",
|
|
26
|
+
args,
|
|
27
|
+
});
|
|
28
|
+
return code ?? 1;
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { runPythonModule } from "../../lib/python-helper.mjs";
|
|
2
|
+
|
|
3
|
+
const USAGE = `okstra run-audit — check okstra run artifacts against progress invariants
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
okstra run-audit
|
|
7
|
+
|
|
8
|
+
Walks the global run-index and checks each run's artifacts (run-manifest,
|
|
9
|
+
final-report data, worker results) against invariants that no error log
|
|
10
|
+
would catch: verification rounds that never ran, reports that never
|
|
11
|
+
appeared, rosters that came up short, approvals waiting past the window.
|
|
12
|
+
Read-only. Prints a JSON summary to stdout.
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
export async function run(args) {
|
|
16
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
17
|
+
process.stdout.write(USAGE);
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
const result = await runPythonModule({
|
|
21
|
+
module: "okstra_ctl.run_audit",
|
|
22
|
+
args,
|
|
23
|
+
stdio: "inherit-stdout",
|
|
24
|
+
});
|
|
25
|
+
return result.code;
|
|
26
|
+
}
|