okstra 0.135.0 → 0.137.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/docs/architecture/storage-model.md +1 -1
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/project-structure-overview.md +8 -3
- package/package.json +2 -3
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/lib/okstra/interactive.sh +24 -67
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +1 -1
- package/runtime/bin/okstra-antigravity-exec.sh +10 -8
- package/runtime/bin/okstra-claude-exec.sh +10 -8
- package/runtime/bin/okstra-codex-exec.sh +10 -8
- package/runtime/bin/okstra-spawn-followups.py +4 -9
- package/runtime/prompts/lead/plan-body-verification.md +2 -2
- package/runtime/python/okstra_ctl/backfill.py +2 -1
- package/runtime/python/okstra_ctl/codex_dispatch.py +56 -331
- package/runtime/python/okstra_ctl/consumers.py +7 -5
- package/runtime/python/okstra_ctl/context_cost.py +6 -5
- package/runtime/python/okstra_ctl/dispatch_core.py +54 -175
- package/runtime/python/okstra_ctl/dispatch_state.py +231 -0
- package/runtime/python/okstra_ctl/error_log_core.py +3 -1
- package/runtime/python/okstra_ctl/error_report.py +2 -7
- package/runtime/python/okstra_ctl/handoff.py +2 -1
- package/runtime/python/okstra_ctl/implementation_outcome.py +17 -27
- package/runtime/python/okstra_ctl/implementation_stage.py +7 -2
- package/runtime/python/okstra_ctl/path_hints.py +5 -3
- package/runtime/python/okstra_ctl/paths.py +278 -4
- package/runtime/python/okstra_ctl/plan_run_root.py +4 -4
- package/runtime/python/okstra_ctl/recap.py +5 -12
- package/runtime/python/okstra_ctl/render.py +9 -15
- package/runtime/python/okstra_ctl/report_finalize.py +8 -4
- package/runtime/python/okstra_ctl/report_language.py +83 -0
- package/runtime/python/okstra_ctl/run.py +222 -239
- package/runtime/python/okstra_ctl/set_work_status.py +2 -1
- package/runtime/python/okstra_ctl/stage_targets.py +98 -55
- package/runtime/python/okstra_ctl/time_report.py +4 -9
- package/runtime/python/okstra_ctl/wizard.py +50 -50
- package/runtime/python/okstra_ctl/work_categories.py +2 -2
- package/runtime/python/okstra_ctl/worker_prompt_body.py +82 -0
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +0 -13
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +7 -0
- package/runtime/python/okstra_project/__init__.py +4 -0
- package/runtime/python/okstra_project/dirs.py +7 -0
- package/runtime/python/okstra_project/state.py +78 -8
- package/runtime/validators/validate-run.py +23 -52
- package/src/commands/inspect/stage-map.mjs +12 -19
|
@@ -236,7 +236,7 @@ Main contents:
|
|
|
236
236
|
This document is only a quick summary and is not the source of truth.
|
|
237
237
|
Always use `task-manifest.json` when checking canonical metadata.
|
|
238
238
|
|
|
239
|
-
The rendered `task-index.md` is an English-literal artifact. The headings, field labels, and `## Notes` footnote of the template (`templates/project-docs/task-index.template.md`) ship as English literals regardless of the `reportLanguage` setting, matching the okstra-schedule-gen schedule contract.
|
|
239
|
+
The rendered `task-index.md` is an English-literal artifact. The headings, field labels, and `## Notes` footnote of the template (`templates/project-docs/task-index.template.md`) ship as English literals regardless of the `reportLanguage` setting, matching the okstra-schedule-gen schedule contract. `tests/contract/test_docs_runtime_contract.py` enforces this contract.
|
|
240
240
|
|
|
241
241
|
## Run manifest contract
|
|
242
242
|
|
|
@@ -11,6 +11,6 @@ Use this matrix before changing high-risk repo contracts. Update the source file
|
|
|
11
11
|
| Add phase | `scripts/okstra_ctl/workflow.py`, `prompts/profiles/`, `validators/`, `tests/` | workflow and validation contract tests |
|
|
12
12
|
| Change worker roster | `prompts/profiles/*.md`, `scripts/okstra_ctl/workers.py`, `tests/contract/test_repo_contracts.py` | worker roster contract tests |
|
|
13
13
|
| Change report section | `schemas/final-report-v1.0.schema.json`, `templates/reports/final-report.template.md`, `scripts/okstra_ctl/render_final_report.py`, `validators/validate-run.py` | final-report schema, renderer, and validator tests |
|
|
14
|
-
|
|
|
14
|
+
| Maintain Korean review mirrors | `config/korean-sources.json`, `tools/korean-sources/`, `.agents/skills/sync-korean-sources/`, `.claude/skills/sync-korean-sources/` | `tests-js/korean-sources-*.test.mjs` |
|
|
15
15
|
|
|
16
16
|
`runtime/` is build output. Never edit it directly; change source files and rebuild the runtime payload instead.
|
|
@@ -55,6 +55,10 @@ okstra/
|
|
|
55
55
|
│ ├── lib/okstra/ Bash helpers for okstra.sh
|
|
56
56
|
│ └── lib/okstra-ctl/ Bash control-center subcommands
|
|
57
57
|
├── skills/ Claude Code skills (13); `_fragments/` holds shared marker blocks
|
|
58
|
+
├── .agents/skills/ Codex repo-local maintainer skills
|
|
59
|
+
├── .claude/skills/ Claude Code project-only mirror-sync surface
|
|
60
|
+
├── .claude/settings.json Claude Code project-only mirror-sync surface
|
|
61
|
+
├── .codex/hooks.json Codex project lifecycle hooks
|
|
58
62
|
├── agents/ lead SKILL.md + worker agent specs
|
|
59
63
|
├── prompts/ launch template, phase profiles, wizard prompt JSON
|
|
60
64
|
├── schemas/ JSON schema for final-report data.json
|
|
@@ -62,8 +66,8 @@ okstra/
|
|
|
62
66
|
├── validators/ run / brief / schedule / view validators
|
|
63
67
|
├── tools/build.mjs source → runtime sync
|
|
64
68
|
├── tools/sync-skill-fragments.mjs expand shared fragment blocks into skills/*/SKILL.md
|
|
65
|
-
├── tools/
|
|
66
|
-
├── config/
|
|
69
|
+
├── tools/korean-sources/ maintainer-only Korean mirror sync engine
|
|
70
|
+
├── config/korean-sources.json configured English Markdown source roots
|
|
67
71
|
├── runtime/ generated install payload; do not edit directly
|
|
68
72
|
├── tests/ pytest unit suite
|
|
69
73
|
├── tests-e2e/ Bash end-to-end scenarios
|
|
@@ -289,6 +293,7 @@ Important modules:
|
|
|
289
293
|
| `team_reconcile.py` | stale team-member reconciliation at run-end teardown |
|
|
290
294
|
| `worker_prompt_headers.py` | shared rendering of phase-aware worker prompt anchors (`worker_prompt_headers`): coding-preflight only for implementation and compact target identity for final-verification |
|
|
291
295
|
| `worker_prompt_body.py` | provider-neutral initial analysis body/input renderer shared by Codex and external/team dispatch paths |
|
|
296
|
+
| `report_language.py` | report-writer `**Report Language:**` resolution (`resolve_report_language`) — precedence project config → global config → task-brief inference, shared by both dispatchers so the stamped language does not depend on which dispatch path ran |
|
|
292
297
|
| `worker_prompt_policy.py` | `PromptPlan` generating SSOT — resolves functional audience, equality group, packet-only input, coding-preflight eligibility, required headers, and size limits without consulting provider/model identity |
|
|
293
298
|
| `worker_prompt_contract.py` | deterministic cross-task initial-prompt validator and normalized cross-worker equality SSOT, reused by dispatch adapters and the Phase 7 persisted-artifact validator |
|
|
294
299
|
| `convergence_engine.py` | pure `ConvergenceEngine` reducer — seeds Round 0 working state, plans roster-aware rounds, applies structured outcomes and one critic-gap batch, finalizes schema v1.3, and validates replayable state without dispatch or filesystem ownership |
|
|
@@ -558,7 +563,7 @@ When changing code, keep these docs in sync:
|
|
|
558
563
|
- New report field/section: update schema, template, report-writer worker, validator tests, this file's report model if user-visible.
|
|
559
564
|
- New phase/profile behavior: update `prompts/profiles/*`, `docs/architecture.md`, `docs/cli.md`, and `README.md` if user-facing.
|
|
560
565
|
|
|
561
|
-
|
|
566
|
+
Edit English canonical Markdown sources directly. After changing a path registered in `config/korean-sources.json`, process the local Korean mirror queue with `$sync-korean-sources` or `/sync-korean-sources`. `.project-docs/ko-sources/**` is maintainer-local only: it is neither published nor committed.
|
|
562
567
|
|
|
563
568
|
---
|
|
564
569
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "okstra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.137.0",
|
|
4
4
|
"description": "Multi-agent cross-verification orchestrator runtime + Claude Code skills.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "devonshin",
|
|
@@ -35,10 +35,9 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "node tools/build.mjs",
|
|
37
37
|
"prepack": "node tools/build.mjs",
|
|
38
|
-
"docs:validate": "python3 -m tools.docs_publication validate --repo .",
|
|
39
38
|
"test:js": "node --test tests-js/*.test.mjs",
|
|
40
39
|
"test:py": "python3 -m pytest tests/",
|
|
41
40
|
"test:workflow": "bash validators/validate-workflow.sh",
|
|
42
|
-
"check": "npm run
|
|
41
|
+
"check": "npm run build && npm run test:js && npm run test:py && npm run test:workflow"
|
|
43
42
|
}
|
|
44
43
|
}
|
package/runtime/BUILD.json
CHANGED
|
@@ -11,19 +11,6 @@ is_interactive_session() {
|
|
|
11
11
|
[[ -t 0 && -t 1 ]]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
file_mtime() {
|
|
15
|
-
# Epoch mtime; portable across GNU (stat -c) and macOS/BSD (stat -f).
|
|
16
|
-
# Validate that the output is a bare integer before accepting it: GNU
|
|
17
|
-
# `stat -f %m` (a BSD-ism) does NOT fail cleanly — it succeeds with
|
|
18
|
-
# non-numeric filesystem output, so a plain `a || b` would return that
|
|
19
|
-
# garbage and later break `-gt`/`-eq` arithmetic under `set -u`.
|
|
20
|
-
local m=""
|
|
21
|
-
m="$(stat -c %Y "$1" 2>/dev/null)"
|
|
22
|
-
[[ "$m" =~ ^[0-9]+$ ]] || m="$(stat -f %m "$1" 2>/dev/null)"
|
|
23
|
-
[[ "$m" =~ ^[0-9]+$ ]] || m="0"
|
|
24
|
-
printf '%s' "$m"
|
|
25
|
-
}
|
|
26
|
-
|
|
27
14
|
split_task_key() {
|
|
28
15
|
local raw_key=""
|
|
29
16
|
raw_key="$(trim_whitespace "${TASK_KEY_INPUT-}")"
|
|
@@ -293,74 +280,44 @@ find_latest_final_report() {
|
|
|
293
280
|
# Args: project_root task_group task_id task_type_filter(optional)
|
|
294
281
|
# Echoes: <abs path to latest final-report-*.md>\t<task-type>
|
|
295
282
|
# Returns: 1 if not found.
|
|
283
|
+
#
|
|
284
|
+
# 선택 규칙(mtime 최신, 동률이면 basename)과 산출물 위치 지식은
|
|
285
|
+
# okstra_ctl.paths.RunRef 가 정본이다. 과거 이 함수는 그 규칙을 bash 로
|
|
286
|
+
# 재구현해 python 쪽과 손으로 동기화해야 했다.
|
|
296
287
|
local project_root="$1"
|
|
297
288
|
local task_group="$2"
|
|
298
289
|
local task_id="$3"
|
|
299
290
|
local task_type_filter="$4"
|
|
300
291
|
|
|
292
|
+
# task-key 단축키 해소와 오타 진단(실제 task-key 목록 출력)은 이 resolver 가
|
|
293
|
+
# 소유한다. 최신 보고서 선택만 python 정본에 위임한다.
|
|
301
294
|
local task_root=""
|
|
302
295
|
task_root="$(resolve_task_root_for_shortcut "$project_root" "$PROJECT_ID" "$task_group" "$task_id")" || {
|
|
303
296
|
printf 'resume-clarification: unable to resolve task root for the given task-key. See diagnostics above.\n' >&2
|
|
304
297
|
return 1
|
|
305
298
|
}
|
|
306
299
|
|
|
307
|
-
local
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (( ${#search_dirs[@]} == 0 )); then
|
|
322
|
-
printf 'resume-clarification: no requirements-discovery or error-analysis reports/ directory under %s/runs/. Run that phase first before invoking --resume-clarification.\n' "$task_root" >&2
|
|
323
|
-
return 1
|
|
324
|
-
fi
|
|
325
|
-
|
|
326
|
-
# Pick the chronologically newest report (mtime first), matching the Python
|
|
327
|
-
# resume path (okstra_ctl.wizard's mtime-max). A pure basename sort conflates
|
|
328
|
-
# phases: across error-analysis/ and requirements-discovery/ dirs the filename
|
|
329
|
-
# embeds the task-type, so a lexicographic max always favors one phase
|
|
330
|
-
# regardless of which run is actually newer. Ties (same-second mtime within a
|
|
331
|
-
# phase dir) fall back to the greater basename so the highest seq/timestamp
|
|
332
|
-
# wins deterministically.
|
|
333
|
-
local best_path=""
|
|
334
|
-
local best_mtime=-1
|
|
335
|
-
local best_basename=""
|
|
336
|
-
local candidate=""
|
|
337
|
-
local candidate_mtime=""
|
|
338
|
-
local candidate_base=""
|
|
339
|
-
local d=""
|
|
340
|
-
for d in "${search_dirs[@]}"; do
|
|
341
|
-
[[ -d "$d" ]] || continue
|
|
342
|
-
while IFS= read -r candidate; do
|
|
343
|
-
candidate_mtime="$(file_mtime "$candidate")"
|
|
344
|
-
candidate_base="$(basename "$candidate")"
|
|
345
|
-
if [[ -z "$best_path" \
|
|
346
|
-
|| "$candidate_mtime" -gt "$best_mtime" \
|
|
347
|
-
|| ( "$candidate_mtime" -eq "$best_mtime" && "$candidate_base" > "$best_basename" ) ]]; then
|
|
348
|
-
best_path="$candidate"
|
|
349
|
-
best_mtime="$candidate_mtime"
|
|
350
|
-
best_basename="$candidate_base"
|
|
351
|
-
fi
|
|
352
|
-
done < <(find "$d" -maxdepth 1 -type f -name 'final-report-*.md' 2>/dev/null)
|
|
353
|
-
done
|
|
300
|
+
local found=""
|
|
301
|
+
found="$(PYTHONPATH="$WORKSPACE_ROOT/scripts:${PYTHONPATH-}" python3 - \
|
|
302
|
+
"$task_root" "$task_type_filter" <<'PY'
|
|
303
|
+
import sys
|
|
304
|
+
from okstra_ctl.paths import RunRef
|
|
305
|
+
|
|
306
|
+
task_root, task_type_filter = sys.argv[1:3]
|
|
307
|
+
types = ((task_type_filter,) if task_type_filter
|
|
308
|
+
else ("error-analysis", "requirements-discovery"))
|
|
309
|
+
ref = RunRef.latest_under(task_root, types)
|
|
310
|
+
if ref is not None:
|
|
311
|
+
sys.stdout.write(f"{ref.report}\t{ref.task_type}")
|
|
312
|
+
PY
|
|
313
|
+
)" || return 1
|
|
354
314
|
|
|
355
|
-
if [[ -z "$
|
|
356
|
-
printf 'resume-clarification: no final-report-*.md found for task %s:%s under %s\n' \
|
|
357
|
-
"$task_group" "$task_id" "$
|
|
315
|
+
if [[ -z "$found" ]]; then
|
|
316
|
+
printf 'resume-clarification: no final-report-*.md found for task %s:%s under %s/runs\n' \
|
|
317
|
+
"$task_group" "$task_id" "$task_root" >&2
|
|
358
318
|
return 1
|
|
359
319
|
fi
|
|
360
|
-
|
|
361
|
-
local resolved_type=""
|
|
362
|
-
resolved_type="$(basename "$(dirname "$(dirname "$best_path")")")"
|
|
363
|
-
printf '%s\t%s\n' "$best_path" "$resolved_type"
|
|
320
|
+
printf '%s\n' "$found"
|
|
364
321
|
}
|
|
365
322
|
|
|
366
323
|
run_resume_clarification() {
|
|
@@ -151,7 +151,7 @@ batch_reserved = {}
|
|
|
151
151
|
for original in targets:
|
|
152
152
|
row = find_row_by_run_id(home, original)
|
|
153
153
|
# implementation 은 stage 격리 task-type 이다. 한 run = 런타임에 live
|
|
154
|
-
# registry/consumers 상태로 auto-resolve 되는 단일 stage(
|
|
154
|
+
# registry/consumers 상태로 auto-resolve 되는 단일 stage(stage_targets.resolve_effective_stages)
|
|
155
155
|
# 이므로, cmd-rerun 은 spawn 전에 어느 stage-<N> 가 선택될지 알 수 없어
|
|
156
156
|
# runs/implementation/stage-<N> 경로도 per-stage run_seq 도 예측할 수 없다.
|
|
157
157
|
# OKSTRA_RUN_SEQ_OVERRIDE(run 전체에 단일 seq) 는 per-stage seq 카운터와
|
|
@@ -290,15 +290,17 @@ if (( idle_timeout_secs > 0 )); then
|
|
|
290
290
|
while kill -0 "$agy_pid" 2>/dev/null; do
|
|
291
291
|
sleep "$poll_interval"
|
|
292
292
|
kill -0 "$agy_pid" 2>/dev/null || exit 0
|
|
293
|
-
# GNU
|
|
294
|
-
#
|
|
295
|
-
#
|
|
293
|
+
# Portable mtime probe: GNU (stat -c %Y) first, macOS/BSD (stat -f %m) as
|
|
294
|
+
# the fallback, 0 as the floor. Validate each result as a bare integer
|
|
295
|
+
# before accepting it — on Linux the BSD-ism `stat -f %m` does NOT fail
|
|
296
|
+
# cleanly; it succeeds and prints non-numeric filesystem output, which
|
|
297
|
+
# would break the arithmetic below under `set -u`.
|
|
296
298
|
#
|
|
297
|
-
# `|| true`
|
|
298
|
-
# `2>/dev/null`
|
|
299
|
-
# `( ) &`
|
|
300
|
-
#
|
|
301
|
-
#
|
|
299
|
+
# `|| true` is mandatory. macOS has no GNU `stat -c`, so that call exits 1,
|
|
300
|
+
# and `2>/dev/null` suppresses stderr but not the exit code. This watchdog
|
|
301
|
+
# is an explicit `( ) &` subshell, so it inherits whatever errexit setting
|
|
302
|
+
# is in force; under `set -e` a single failed assignment kills the whole
|
|
303
|
+
# watchdog on the first poll — silently, without a log line.
|
|
302
304
|
last_mtime="$(stat -c %Y "$log_path" 2>/dev/null || true)"
|
|
303
305
|
[[ "$last_mtime" =~ ^[0-9]+$ ]] || last_mtime="$(stat -f %m "$log_path" 2>/dev/null || true)"
|
|
304
306
|
[[ "$last_mtime" =~ ^[0-9]+$ ]] || last_mtime=0
|
|
@@ -132,15 +132,17 @@ if (( idle_timeout_secs > 0 )); then
|
|
|
132
132
|
while kill -0 "$claude_pid" 2>/dev/null; do
|
|
133
133
|
sleep "$poll_interval"
|
|
134
134
|
kill -0 "$claude_pid" 2>/dev/null || exit 0
|
|
135
|
-
# GNU
|
|
136
|
-
#
|
|
137
|
-
#
|
|
135
|
+
# Portable mtime probe: GNU (stat -c %Y) first, macOS/BSD (stat -f %m) as
|
|
136
|
+
# the fallback, 0 as the floor. Validate each result as a bare integer
|
|
137
|
+
# before accepting it — on Linux the BSD-ism `stat -f %m` does NOT fail
|
|
138
|
+
# cleanly; it succeeds and prints non-numeric filesystem output, which
|
|
139
|
+
# would break the arithmetic below under `set -u`.
|
|
138
140
|
#
|
|
139
|
-
# `|| true`
|
|
140
|
-
# `2>/dev/null`
|
|
141
|
-
# `( ) &`
|
|
142
|
-
#
|
|
143
|
-
#
|
|
141
|
+
# `|| true` is mandatory. macOS has no GNU `stat -c`, so that call exits 1,
|
|
142
|
+
# and `2>/dev/null` suppresses stderr but not the exit code. This watchdog
|
|
143
|
+
# is an explicit `( ) &` subshell, so it inherits whatever errexit setting
|
|
144
|
+
# is in force; under `set -e` a single failed assignment kills the whole
|
|
145
|
+
# watchdog on the first poll — silently, without a log line.
|
|
144
146
|
last_mtime="$(stat -c %Y "$log_path" 2>/dev/null || true)"
|
|
145
147
|
[[ "$last_mtime" =~ ^[0-9]+$ ]] || last_mtime="$(stat -f %m "$log_path" 2>/dev/null || true)"
|
|
146
148
|
[[ "$last_mtime" =~ ^[0-9]+$ ]] || last_mtime=0
|
|
@@ -421,15 +421,17 @@ if (( idle_timeout_secs > 0 )); then
|
|
|
421
421
|
while kill -0 "$codex_pid" 2>/dev/null; do
|
|
422
422
|
sleep "$poll_interval"
|
|
423
423
|
kill -0 "$codex_pid" 2>/dev/null || exit 0
|
|
424
|
-
# GNU
|
|
425
|
-
#
|
|
426
|
-
#
|
|
424
|
+
# Portable mtime probe: GNU (stat -c %Y) first, macOS/BSD (stat -f %m) as
|
|
425
|
+
# the fallback, 0 as the floor. Validate each result as a bare integer
|
|
426
|
+
# before accepting it — on Linux the BSD-ism `stat -f %m` does NOT fail
|
|
427
|
+
# cleanly; it succeeds and prints non-numeric filesystem output, which
|
|
428
|
+
# would break the arithmetic below under `set -u`.
|
|
427
429
|
#
|
|
428
|
-
# `|| true`
|
|
429
|
-
# `2>/dev/null`
|
|
430
|
-
# `( ) &`
|
|
431
|
-
#
|
|
432
|
-
#
|
|
430
|
+
# `|| true` is mandatory. macOS has no GNU `stat -c`, so that call exits 1,
|
|
431
|
+
# and `2>/dev/null` suppresses stderr but not the exit code. This watchdog
|
|
432
|
+
# is an explicit `( ) &` subshell, so it inherits whatever errexit setting
|
|
433
|
+
# is in force; under `set -e` a single failed assignment kills the whole
|
|
434
|
+
# watchdog on the first poll — silently, without a log line.
|
|
433
435
|
last_mtime="$(stat -c %Y "$log_path" 2>/dev/null || true)"
|
|
434
436
|
[[ "$last_mtime" =~ ^[0-9]+$ ]] || last_mtime="$(stat -f %m "$log_path" 2>/dev/null || true)"
|
|
435
437
|
[[ "$last_mtime" =~ ^[0-9]+$ ]] || last_mtime=0
|
|
@@ -51,19 +51,14 @@ from pathlib import Path
|
|
|
51
51
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
52
52
|
|
|
53
53
|
from okstra_ctl.final_report_paths import final_report_markdown_path # noqa: E402
|
|
54
|
+
from okstra_ctl.paths import task_manifest_file # noqa: E402
|
|
55
|
+
from okstra_ctl.workflow import PHASE_SEQUENCE # noqa: E402
|
|
54
56
|
from okstra_project.dirs import tasks_root # noqa: E402
|
|
55
57
|
|
|
56
58
|
|
|
57
59
|
SLUG_RE = re.compile(r"[^a-zA-Z0-9-]+")
|
|
58
60
|
|
|
59
|
-
ALLOWED_TASK_TYPES =
|
|
60
|
-
"requirements-discovery",
|
|
61
|
-
"error-analysis",
|
|
62
|
-
"implementation-planning",
|
|
63
|
-
"implementation",
|
|
64
|
-
"final-verification",
|
|
65
|
-
"release-handoff",
|
|
66
|
-
}
|
|
61
|
+
ALLOWED_TASK_TYPES = set(PHASE_SEQUENCE)
|
|
67
62
|
ALLOWED_ORIGINS = {
|
|
68
63
|
"phase-continuation",
|
|
69
64
|
"out-of-plan",
|
|
@@ -193,7 +188,7 @@ def _spawn_one(
|
|
|
193
188
|
"routingStatus": "follow-up-spawned",
|
|
194
189
|
},
|
|
195
190
|
}
|
|
196
|
-
_write_manifest(task_root
|
|
191
|
+
_write_manifest(task_manifest_file(task_root), manifest_payload)
|
|
197
192
|
|
|
198
193
|
brief_path = task_root / "instruction-set" / "task-brief.md"
|
|
199
194
|
brief_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -244,7 +244,7 @@ Plan-body verification stays **lightweight** even under this posture — the `ve
|
|
|
244
244
|
|
|
245
245
|
Required prompt anchor headers are identical to finding convergence (see [convergence](./convergence.md) §"Required reverify-prompt anchor headers"). The prompt body changes from F-* listing to P-* listing:
|
|
246
246
|
|
|
247
|
-
|
|
247
|
+
````
|
|
248
248
|
You are <worker-role> performing plan-body verification for <task-key> (round 1).
|
|
249
249
|
|
|
250
250
|
## Instructions
|
|
@@ -342,7 +342,7 @@ rerun a free-form requirements analysis. Every DISAGREE includes Fixability.
|
|
|
342
342
|
**Fixability** (DISAGREE only): planner-fixable | needs-user-input. Fixability is not applicable for `UNVERIFIABLE`.
|
|
343
343
|
**Note**: <the falsification candidate considered and why it is excluded; required even for AGREE>
|
|
344
344
|
**Explanation**: <2-3 sentences applying the disposition-specific rule>
|
|
345
|
-
|
|
345
|
+
````
|
|
346
346
|
|
|
347
347
|
When `config.adversarial == true`, the lead prepends the adversarial framing from §"Adversarial plan-body posture" to the `## Instructions` block: the burden of proof is on the plan, the verifier opens and confirms every accessible cited path / command, and evidence that was opened but is insufficient yields the applicable `DISAGREE(<kind>)` rather than `AGREE`. Inability to inspect because of capability, credential, network, or service state yields `UNVERIFIABLE`, not DISAGREE. The verdict tokens, breakage kinds (a–f), classification, and the majority gate threshold are unchanged. This prepended framing supersedes the template's "Judge solely from plan internal consistency" instruction for the adversarial round.
|
|
348
348
|
|
|
@@ -10,6 +10,7 @@ from typing import List
|
|
|
10
10
|
from okstra_project.dirs import tasks_root
|
|
11
11
|
|
|
12
12
|
from .ids import build_run_id
|
|
13
|
+
from .paths import runs_dir_of
|
|
13
14
|
from .invocation import save_invocation
|
|
14
15
|
from .jsonl import append_jsonl, read_jsonl, rotate_recent_if_needed
|
|
15
16
|
from .project_meta import _project_meta_path
|
|
@@ -130,7 +131,7 @@ def backfill_project(home: Path, project_id: str, project_root: Path) -> int:
|
|
|
130
131
|
manifest_re = _re.compile(r"^run-manifest-(?P<tt>.+)-(?P<seq>\d+)\.json$")
|
|
131
132
|
for group_dir in sorted(p for p in base.iterdir() if p.is_dir()):
|
|
132
133
|
for task_dir in sorted(p for p in group_dir.iterdir() if p.is_dir()):
|
|
133
|
-
runs = task_dir
|
|
134
|
+
runs = runs_dir_of(task_dir)
|
|
134
135
|
if not runs.is_dir():
|
|
135
136
|
continue
|
|
136
137
|
for manifests in _iter_manifest_dirs(runs):
|