okstra 0.159.0 → 0.160.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 +1 -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/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/codex_dispatch.py +6 -6
- package/runtime/python/okstra_ctl/convergence.py +168 -11
- package/runtime/python/okstra_ctl/dispatch_core.py +4 -2
- 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/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_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 +41 -2
- package/runtime/python/okstra_ctl/run_audit.py +477 -0
- 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_session_conformance.py +102 -32
- 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,18 +68,54 @@ _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
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
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
|
+
),
|
|
80
113
|
)
|
|
81
114
|
|
|
115
|
+
# Read 증거는 basename 으로 거른다 — 절대 경로는 레이어(repo / runtime / 설치본)
|
|
116
|
+
# 마다 다르지만 basename 은 동일하다. 목록이 갈리지 않도록 기대치에서 파생한다.
|
|
117
|
+
_ENTRY_GUARD_BASENAMES = tuple(row.basename for row in _ENTRY_GUARD_READS)
|
|
118
|
+
|
|
82
119
|
|
|
83
120
|
@dataclass
|
|
84
121
|
class SessionConformanceResult:
|
|
@@ -171,7 +208,7 @@ def _scan_one_jsonl(
|
|
|
171
208
|
progress.append((ts, m.group("phase"), line))
|
|
172
209
|
elif block.get("type") == "tool_use" and block.get("name") == "Read":
|
|
173
210
|
base = Path(str((block.get("input") or {}).get("file_path") or "")).name
|
|
174
|
-
if base in
|
|
211
|
+
if base in _ENTRY_GUARD_BASENAMES:
|
|
175
212
|
reads.setdefault(base, []).append(ts)
|
|
176
213
|
return progress, reads, agent_name
|
|
177
214
|
|
|
@@ -297,7 +334,7 @@ def _sidecar_read_from_event(event) -> tuple[str, str] | None:
|
|
|
297
334
|
if not isinstance(basename, str) or not basename:
|
|
298
335
|
raw_path = details.get("path") or details.get("filePath")
|
|
299
336
|
basename = Path(str(raw_path or "")).name
|
|
300
|
-
if basename not in
|
|
337
|
+
if basename not in _ENTRY_GUARD_BASENAMES:
|
|
301
338
|
return None
|
|
302
339
|
return (basename, event.timestamp)
|
|
303
340
|
|
|
@@ -696,36 +733,65 @@ def _check_worker_liveness(
|
|
|
696
733
|
errors.append(f"registered wrapper status sidecar unreadable: {path}")
|
|
697
734
|
|
|
698
735
|
|
|
699
|
-
def
|
|
736
|
+
def _instruction_set_dir(run_dir: Path, suffix: str | None, project_root: Path) -> Path | None:
|
|
737
|
+
"""이 run 의 instruction-set 디렉터리. 해소 불가면 None (경로를 모르면 스테이징
|
|
738
|
+
여부도 판정할 수 없고, 모르는 것을 근거로 run 을 떨어뜨리지 않는다)."""
|
|
739
|
+
if not suffix:
|
|
740
|
+
return None
|
|
741
|
+
manifest = run_dir / "manifests" / f"run-manifest-{suffix}.json"
|
|
742
|
+
try:
|
|
743
|
+
data = json.loads(manifest.read_text(encoding="utf-8"))
|
|
744
|
+
except (OSError, json.JSONDecodeError, UnicodeDecodeError):
|
|
745
|
+
return None
|
|
746
|
+
raw = data.get("instructionSetPath") if isinstance(data, dict) else None
|
|
747
|
+
if not isinstance(raw, str) or not raw:
|
|
748
|
+
return None
|
|
749
|
+
path = Path(raw)
|
|
750
|
+
if not path.is_absolute():
|
|
751
|
+
path = project_root / path
|
|
752
|
+
return path if path.is_dir() else None
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
def _check_implementation_entry_guard(
|
|
756
|
+
evidence: _LeadEvidence, errors: list[str], instruction_set: Path | None
|
|
757
|
+
) -> None:
|
|
700
758
|
"""검사 3 — entry guard. fresh-read 규칙(이전 run 기억으로 갈음 불가)은 run
|
|
701
|
-
윈도우 스코핑이 보장한다: 이번 윈도우 안의 Read 만 증거로 인정된다.
|
|
759
|
+
윈도우 스코핑이 보장한다: 이번 윈도우 안의 Read 만 증거로 인정된다.
|
|
760
|
+
|
|
761
|
+
anchor 가 있는 행은 존재 + 순서를, anchor 가 `None` 인 행은 존재만 본다.
|
|
762
|
+
`staged_per_run` 행은 이 run 의 instruction-set 에 실제로 있을 때만 요구한다."""
|
|
702
763
|
anchors: dict[str, str] = {}
|
|
703
764
|
for ts, phase, _line in evidence.progress: # progress 는 ts 정렬 — 첫 항목이 최초 발생
|
|
704
765
|
if phase in ("phase-6-synthesis", "phase-7-persist") and ts:
|
|
705
766
|
anchors.setdefault(phase, ts)
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
ts_list = evidence.sidecar_reads.get(basename) or []
|
|
767
|
+
for row in _ENTRY_GUARD_READS:
|
|
768
|
+
if row.staged_per_run and not (
|
|
769
|
+
instruction_set and (instruction_set / row.basename).is_file()
|
|
770
|
+
):
|
|
771
|
+
continue
|
|
772
|
+
ts_list = evidence.sidecar_reads.get(row.basename) or []
|
|
713
773
|
if not ts_list:
|
|
774
|
+
demand = (
|
|
775
|
+
f"it MUST be read fresh {row.anchor[1]} of every implementation run"
|
|
776
|
+
if row.anchor
|
|
777
|
+
else "the staged copy MUST be read at least once inside that window"
|
|
778
|
+
)
|
|
714
779
|
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)')."
|
|
780
|
+
f"implementation entry guard: no `Read` of `{row.basename}` found in "
|
|
781
|
+
f"the selected adapter evidence source within this run's window — "
|
|
782
|
+
f"{demand} ({row.cite})."
|
|
720
783
|
)
|
|
721
784
|
continue
|
|
785
|
+
if not row.anchor:
|
|
786
|
+
continue
|
|
787
|
+
anchor_phase, when = row.anchor
|
|
722
788
|
anchor_ts = anchors.get(anchor_phase)
|
|
723
789
|
if anchor_ts and min(ts_list) >= anchor_ts:
|
|
724
790
|
errors.append(
|
|
725
|
-
f"implementation entry guard: `{basename}` was first Read at "
|
|
791
|
+
f"implementation entry guard: `{row.basename}` was first Read at "
|
|
726
792
|
f"{min(ts_list)}, not before the first `PROGRESS: {anchor_phase}` "
|
|
727
|
-
f"line ({anchor_ts}) — it must be loaded
|
|
728
|
-
"that checkpoint (
|
|
793
|
+
f"line ({anchor_ts}) — it must be loaded {when}, before "
|
|
794
|
+
f"that checkpoint ({row.cite})."
|
|
729
795
|
)
|
|
730
796
|
|
|
731
797
|
|
|
@@ -772,5 +838,9 @@ def validate_session_conformance(
|
|
|
772
838
|
return result
|
|
773
839
|
_check_progress_checkpoints(evidence, team_state, run_dir, suffix, result.errors)
|
|
774
840
|
if task_type == "implementation":
|
|
775
|
-
|
|
841
|
+
_check_implementation_entry_guard(
|
|
842
|
+
evidence,
|
|
843
|
+
result.errors,
|
|
844
|
+
_instruction_set_dir(run_dir, suffix, project_root),
|
|
845
|
+
)
|
|
776
846
|
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
|
+
}
|