okstra 0.82.1 → 0.84.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.kr.md +7 -6
- package/README.md +6 -6
- package/docs/kr/architecture.md +8 -7
- package/docs/kr/cli.md +2 -2
- package/docs/kr/performance-improvement-plan-v2.md +14 -14
- package/docs/project-structure-overview.md +7 -8
- package/docs/superpowers/plans/2026-06-15-coding-preflight-pack-dispatch-path.md +504 -0
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-final-fixups.md +342 -0
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-fixups.md +258 -0
- package/docs/superpowers/plans/2026-06-15-internal-skill-migration-remaining-fixups.md +387 -0
- package/docs/superpowers/plans/2026-06-15-internal-skill-resource-migration.md +749 -0
- package/docs/superpowers/plans/2026-06-15-worker-prompt-anchor-final-fixups.md +828 -0
- package/docs/superpowers/plans/2026-06-15-worker-prompt-header-error-contract.md +490 -0
- package/docs/task-process/README.md +1 -1
- package/docs/task-process/error-analysis.md +1 -1
- package/docs/task-process/final-verification.md +1 -1
- package/docs/task-process/implementation-planning.md +1 -1
- package/docs/task-process/implementation.md +1 -1
- package/docs/task-process/release-handoff.md +1 -1
- package/docs/task-process/requirements-discovery.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/TODO.md +2 -0
- package/runtime/agents/workers/claude-worker.md +8 -8
- package/runtime/agents/workers/codex-worker.md +8 -8
- package/runtime/agents/workers/gemini-worker.md +8 -8
- package/runtime/agents/workers/report-writer-worker.md +2 -2
- package/runtime/bin/lib/okstra/globals.sh +0 -1
- package/runtime/bin/okstra-wrapper-status.py +1 -1
- package/runtime/prompts/launch.template.md +5 -3
- package/runtime/{skills/okstra-context-loader/SKILL.md → prompts/lead/context-loader.md} +7 -14
- package/runtime/{skills/okstra-convergence/SKILL.md → prompts/lead/convergence.md} +12 -19
- package/runtime/{agents/SKILL.md → prompts/lead/okstra-lead-contract.md} +53 -59
- package/runtime/{skills/okstra-report-writer/SKILL.md → prompts/lead/report-writer.md} +12 -19
- package/runtime/{skills/okstra-team-contract/SKILL.md → prompts/lead/team-contract.md} +13 -19
- package/runtime/{skills → prompts}/okstra-coding-preflight/languages/python.md +2 -2
- package/runtime/{skills → prompts}/okstra-coding-preflight/languages/rust.md +1 -1
- package/runtime/{skills/okstra-coding-preflight/SKILL.md → prompts/okstra-coding-preflight/overview.md} +27 -38
- package/runtime/prompts/okstra-coding-preflight/scripts/preedit-check.sh +79 -0
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +2 -2
- package/runtime/prompts/profiles/_common-contract.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +2 -2
- package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
- package/runtime/prompts/profiles/error-analysis.md +2 -2
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +4 -4
- package/runtime/prompts/profiles/requirements-discovery.md +2 -2
- package/runtime/python/okstra_ctl/codex_dispatch.py +12 -61
- package/runtime/python/okstra_ctl/context_cost.py +14 -11
- package/runtime/python/okstra_ctl/dispatch_core.py +36 -13
- package/runtime/python/okstra_ctl/paths.py +27 -1
- package/runtime/python/okstra_ctl/render.py +62 -8
- package/runtime/python/okstra_ctl/run.py +8 -6
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +126 -0
- package/runtime/python/okstra_token_usage/claude.py +1 -1
- package/runtime/python/okstra_token_usage/collect.py +1 -1
- package/runtime/skills/okstra-brief/SKILL.md +65 -11
- package/runtime/skills/okstra-inspect/SKILL.md +1 -1
- package/runtime/skills/okstra-schedule/SKILL.md +4 -4
- package/runtime/skills/okstra-setup/SKILL.md +2 -2
- package/runtime/templates/reports/settings.template.json +14 -123
- package/runtime/templates/reports/task-brief.template.md +2 -2
- package/runtime/templates/worker-prompt-preamble.md +2 -2
- package/runtime/validators/lib/validate-assets.sh +12 -4
- package/runtime/validators/validate-brief.py +99 -16
- package/runtime/validators/validate-run.py +3 -3
- package/runtime/validators/validate_session_conformance.py +11 -11
- package/src/install.mjs +95 -81
- package/src/skill-catalog.mjs +35 -0
- package/src/uninstall.mjs +5 -0
- /package/runtime/{skills/okstra-coding-preflight/architecture → prompts/okstra-coding-preflight/architectures}/hexagonal.md +0 -0
- /package/runtime/{skills → prompts}/okstra-coding-preflight/clean-code.md +0 -0
- /package/runtime/{skills/okstra-coding-preflight/languages/nodejs.md → prompts/okstra-coding-preflight/frameworks/node-server.md} +0 -0
- /package/runtime/{skills → prompts}/okstra-coding-preflight/languages/java.md +0 -0
- /package/runtime/{skills → prompts}/okstra-coding-preflight/languages/javascript-typescript.md +0 -0
- /package/runtime/{skills → prompts}/okstra-coding-preflight/languages/kotlin.md +0 -0
- /package/runtime/{skills → prompts}/okstra-coding-preflight/languages/sql.md +0 -0
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
name: okstra-coding-preflight
|
|
3
|
-
description: Provides language-specific coding conventions, idioms, and test-writing guidance for Java, Kotlin, JavaScript, TypeScript, Node.js, Python, SQL, and Rust. okstra lead/workers MUST consult this skill before writing, editing, refactoring, or testing code in any of these languages — including any new file, function, or test — even when the task seems simple enough to handle directly. Detect the target language from the file extension, project config (package.json/Cargo.toml/pyproject.toml/pom.xml/build.gradle), or task brief, and apply the matching conventions.
|
|
4
|
-
user-invocable: false
|
|
5
|
-
hide: true
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# okstra Code Preflight
|
|
1
|
+
# Okstra Coding Preflight
|
|
9
2
|
|
|
10
3
|
## These apply to every worker writing or editing project code (executor and verifiers alike). Enforcement is self-check: the agent runs each rule's check immediately before reporting "done"; skipping a check is itself a contract violation.
|
|
11
4
|
|
|
@@ -16,42 +9,38 @@ hide: true
|
|
|
16
9
|
5. **Function length cap — 50 lines** — A single function/method body must stay within 50 lines, counting only effective code (exclude blank lines, comments, and pure data declarations such as large enums, lookup tables, or constant maps). Crossing the cap is an extraction signal, not a style nit. *Self-check: for any function newly added or substantially edited, count effective body lines; if over 50, split before declaring complete, or surface the violation and confirm with the user.*
|
|
17
10
|
|
|
18
11
|
|
|
19
|
-
##
|
|
12
|
+
## Routed resource selection
|
|
20
13
|
|
|
21
|
-
|
|
14
|
+
Read `clean-code.md` for the language-agnostic principles, then select language, framework, and architecture resources in three ordered stages. Each stage is a list of rules; a rule has one or more conditions; if ANY condition matches, include that rule's resource. Iterate EVERY rule in a stage — do not stop at the first match, because one change set can touch multiple languages, frameworks, or architectures. De-duplicate the final set, then state in one sentence which resources you applied (e.g., *"Applying TS + Node server + hexagonal; domain at src/domain/."*).
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
2. Read the matching language reference from `languages/`.
|
|
25
|
-
3. Read [clean-code.md](clean-code.md) for the language-agnostic principles.
|
|
26
|
-
4. **Check for architecture overlays.** If the project uses ports-and-adapters (signals: `domain/` + `ports/` + `adapters/` folders, `*.port.*` files, NestJS hex split), also read [architecture/hexagonal.md](architecture/hexagonal.md). Record the detected layout in one line so later edits don't re-discover it.
|
|
27
|
-
5. In **one short sentence** to the user, state which conventions you will apply (e.g., *"Applying Kotlin conventions + hexagonal overlay; domain at `src/domain/`."*).
|
|
28
|
-
6. Then write code.
|
|
16
|
+
### Stage 1 — Language (iterate all rules)
|
|
29
17
|
|
|
30
|
-
|
|
18
|
+
| Resource | Include when any condition matches |
|
|
19
|
+
|---|---|
|
|
20
|
+
| [languages/javascript-typescript.md](languages/javascript-typescript.md) | a touched file is `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`; or a JS package manifest (`package.json`) implies JS/TS work |
|
|
21
|
+
| [languages/python.md](languages/python.md) | a touched file is `.py`; or manifests include `pyproject.toml`, `requirements.txt`, `setup.py`, `setup.cfg` |
|
|
22
|
+
| [languages/rust.md](languages/rust.md) | a touched file is `.rs`; or `Cargo.toml` is in scope |
|
|
23
|
+
| [languages/java.md](languages/java.md) | a touched file is `.java`; or manifests include `pom.xml` / `build.gradle` |
|
|
24
|
+
| [languages/kotlin.md](languages/kotlin.md) | a touched file is `.kt` / `.kts`; or manifests include `build.gradle.kts` |
|
|
25
|
+
| [languages/sql.md](languages/sql.md) | a touched file is `.sql`; migration directories are touched; `prisma/schema.prisma` is touched; or embedded query strings / ORM query builders change |
|
|
31
26
|
|
|
32
|
-
|
|
27
|
+
### Stage 2 — Framework / runtime (iterate all rules)
|
|
33
28
|
|
|
34
|
-
|
|
|
35
|
-
|
|
36
|
-
|
|
|
37
|
-
| Kotlin | [languages/kotlin.md](languages/kotlin.md) | `.kt`, `.kts`, `build.gradle.kts` |
|
|
38
|
-
| JavaScript / TypeScript | [languages/javascript-typescript.md](languages/javascript-typescript.md) | `.js`, `.ts`, `.tsx`, `.jsx` |
|
|
39
|
-
| Node.js (server) | [languages/nodejs.md](languages/nodejs.md) | `package.json` with server entry, `express`, `fastify`, `nestjs` |
|
|
40
|
-
| Python | [languages/python.md](languages/python.md) | `.py`, `pyproject.toml`, `requirements.txt`, `setup.py`, `setup.cfg` |
|
|
41
|
-
| SQL | [languages/sql.md](languages/sql.md) | `.sql`, migration directories, `prisma/schema.prisma`, raw queries embedded in code |
|
|
42
|
-
| Rust | [languages/rust.md](languages/rust.md) | `.rs`, `Cargo.toml` |
|
|
29
|
+
| Resource | Include when any condition matches |
|
|
30
|
+
|---|---|
|
|
31
|
+
| [frameworks/node-server.md](frameworks/node-server.md) | `package.json` or its dependencies/scripts show server-side Node work (`express`, `fastify`, `nestjs`, server entrypoints, API routes, CLI services); or a touched file is a Node runtime module |
|
|
43
32
|
|
|
44
|
-
|
|
33
|
+
Node.js server work also matches Stage 1's JavaScript/TypeScript rule — load both `languages/javascript-typescript.md` and `frameworks/node-server.md`.
|
|
45
34
|
|
|
46
|
-
|
|
35
|
+
### Stage 3 — Architecture (iterate all rules)
|
|
47
36
|
|
|
48
|
-
|
|
37
|
+
| Resource | Include when any condition matches |
|
|
38
|
+
|---|---|
|
|
39
|
+
| [architectures/hexagonal.md](architectures/hexagonal.md) | ports-and-adapters / hexagonal signals: `domain/` + `ports/` + `adapters/` (or `core/` + `infrastructure/` + `application/`), `*.port.*` files, NestJS hex split, or `abstract class` files at a domain boundary |
|
|
49
40
|
|
|
50
|
-
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| Hexagonal (ports & adapters) | [architecture/hexagonal.md](architecture/hexagonal.md) | Project has `domain/` + `ports/` + `adapters/` (or equivalent: `core/`, `infrastructure/`, `application/`), `*.port.*` files, or `abstract class` files at a domain boundary. Confirm once with the user if ambiguous. |
|
|
41
|
+
If a layout looks hexagonal but is non-standard, ask one question — *"does this project follow ports-and-adapters? where is the domain?"* — and record the answer. Architecture overlays default to none when no rule matches.
|
|
53
42
|
|
|
54
|
-
If
|
|
43
|
+
If no Stage 1 language rule matches (an unlisted language), stop and ask the user for the canonical style guide before writing code — do not invent a default.
|
|
55
44
|
|
|
56
45
|
## Mandatory pre-write checks (every language)
|
|
57
46
|
|
|
@@ -61,7 +50,7 @@ If you suspect an overlay applies but the layout is non-standard, ask one questi
|
|
|
61
50
|
- [ ] **Testing discipline:** the test does not stub/spy methods on the SUT itself (collaborators are fine), and assertions are on outcomes (return values, state, events, boundary calls) — not on which internal helper was called.
|
|
62
51
|
- [ ] **Hexagonal overlay (if loaded):** no business logic inside any port body, adapter methods are I/O only (no post-fetch JS filtering on domain state, no `findValid*`/`findActive*` adapter names hiding rules), all domain objects declared under `domain/`.
|
|
63
52
|
- [ ] Existing code searched: `grep` for the symbol / file / identifier you are about to add. Do not duplicate.
|
|
64
|
-
- [ ] Project conventions checked: `.editorconfig`, `CONTRIBUTING.md`, formatter config (`.prettierrc`, `rustfmt.toml`, `ktlint`, `google-java-format`, etc.). **Project rules override this
|
|
53
|
+
- [ ] Project conventions checked: `.editorconfig`, `CONTRIBUTING.md`, formatter config (`.prettierrc`, `rustfmt.toml`, `ktlint`, `google-java-format`, etc.). **Project rules override this resource pack on conflict.**
|
|
65
54
|
|
|
66
55
|
## Completion sweep (before declaring a multi-file change done)
|
|
67
56
|
|
|
@@ -73,6 +62,6 @@ Per-file checks miss cross-cutting issues; each commit can be individually clean
|
|
|
73
62
|
|
|
74
63
|
## Boundaries
|
|
75
64
|
|
|
76
|
-
- This
|
|
77
|
-
- This
|
|
78
|
-
- This
|
|
65
|
+
- This preflight does **not** auto-format. Run the project's formatter yourself.
|
|
66
|
+
- This preflight does **not** replace repo-local rules. Repo rules win on conflict.
|
|
67
|
+
- This preflight does **not** cover every language. If the target language is missing, stop and ask.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse hook for okstra-coding-preflight.
|
|
3
|
+
#
|
|
4
|
+
# Inspects the target file path of a Write/Edit/MultiEdit/NotebookEdit
|
|
5
|
+
# call. If the extension matches a language covered by this skill,
|
|
6
|
+
# emits a `hookSpecificOutput.additionalContext` JSON payload that
|
|
7
|
+
# reminds the agent to invoke the skill before writing.
|
|
8
|
+
#
|
|
9
|
+
# Fires at most once per session per language (marker file).
|
|
10
|
+
# Exits 0 in every case — never blocks the tool call.
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
input="$(cat)"
|
|
15
|
+
|
|
16
|
+
tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
|
|
17
|
+
case "$tool_name" in
|
|
18
|
+
Write|Edit|MultiEdit|NotebookEdit) ;;
|
|
19
|
+
*) exit 0 ;;
|
|
20
|
+
esac
|
|
21
|
+
|
|
22
|
+
file_path="$(printf '%s' "$input" \
|
|
23
|
+
| jq -r '.tool_input.file_path // .tool_input.notebook_path // empty')"
|
|
24
|
+
[[ -z "$file_path" ]] && exit 0
|
|
25
|
+
|
|
26
|
+
lang=""
|
|
27
|
+
ref=""
|
|
28
|
+
extra_hint=""
|
|
29
|
+
case "$file_path" in
|
|
30
|
+
*.java)
|
|
31
|
+
lang="Java"
|
|
32
|
+
ref="languages/java.md"
|
|
33
|
+
;;
|
|
34
|
+
*.kt|*.kts)
|
|
35
|
+
lang="Kotlin"
|
|
36
|
+
ref="languages/kotlin.md"
|
|
37
|
+
;;
|
|
38
|
+
*.ts|*.tsx|*.js|*.jsx|*.mjs|*.cjs)
|
|
39
|
+
lang="JavaScript-TypeScript"
|
|
40
|
+
ref="languages/javascript-typescript.md"
|
|
41
|
+
extra_hint=" If this file is part of a Node.js server (Express/Fastify/Nest/etc.), also read languages/nodejs.md."
|
|
42
|
+
;;
|
|
43
|
+
*.py)
|
|
44
|
+
lang="Python"
|
|
45
|
+
ref="languages/python.md"
|
|
46
|
+
;;
|
|
47
|
+
*.sql)
|
|
48
|
+
lang="SQL"
|
|
49
|
+
ref="languages/sql.md"
|
|
50
|
+
;;
|
|
51
|
+
*.rs)
|
|
52
|
+
lang="Rust"
|
|
53
|
+
ref="languages/rust.md"
|
|
54
|
+
;;
|
|
55
|
+
*)
|
|
56
|
+
exit 0
|
|
57
|
+
;;
|
|
58
|
+
esac
|
|
59
|
+
|
|
60
|
+
session_id="$(printf '%s' "$input" | jq -r '.session_id // "no-session"')"
|
|
61
|
+
marker_dir="${TMPDIR:-/tmp}/mcbsc"
|
|
62
|
+
mkdir -p "$marker_dir"
|
|
63
|
+
marker="${marker_dir}/${session_id}_${lang}"
|
|
64
|
+
|
|
65
|
+
if [[ -f "$marker" ]]; then
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
: > "$marker"
|
|
70
|
+
|
|
71
|
+
skill_root="$HOME/.okstra/prompts/okstra-coding-preflight"
|
|
72
|
+
msg="[okstra-coding-preflight] About to edit a ${lang} file (${file_path}). Before writing, you MUST Read ${skill_root}/${ref} plus ${skill_root}/clean-code.md (the skill is user-invocable:false — read the files directly).${extra_hint} If the project uses ports-and-adapters (domain/ + ports/ + adapters/, *.port.* files), also Read ${skill_root}/architecture/hexagonal.md. (Fires once per session per language.)"
|
|
73
|
+
|
|
74
|
+
jq -nc \
|
|
75
|
+
--arg event "PreToolUse" \
|
|
76
|
+
--arg ctx "$msg" \
|
|
77
|
+
'{hookSpecificOutput: {hookEventName: $event, additionalContext: $ctx}}'
|
|
78
|
+
|
|
79
|
+
exit 0
|
|
@@ -15,7 +15,7 @@ prompt (agents/workers/_cli-wrapper-template.md → Prompt Composition).
|
|
|
15
15
|
|
|
16
16
|
Load the applicable coding conventions for every language the diff will touch, then state in ONE line which conventions apply (e.g. `Applying TS + hexagonal overlay; domain at src/domains/*/domain/`). Lint/test green is necessary but NOT sufficient — self-mocked tests, interaction-only assertions, and untruthful names all pass a green pipeline; this gate is what keeps them out of the diff.
|
|
17
17
|
|
|
18
|
-
- **
|
|
18
|
+
- **Resource selection — read the routed pack, never inline it here.** Use this worker prompt's `**Coding preflight pack:**` anchor header as the absolute path to the installed routed pack. Detect each touched file's language and framework (extension / project manifest: `package.json`, `Cargo.toml`, `pyproject.toml`, `pom.xml`, `build.gradle*`, `prisma/schema.prisma`) and read resources from that pack via the Read tool by absolute path. Always read `overview.md` (the router) + `clean-code.md`, then select per the router's three ordered stages — Stage 1 language → `languages/<lang>.md`, Stage 2 framework → `frameworks/<fw>.md` (e.g. `frameworks/node-server.md` for server-side Node), Stage 3 architecture → `architectures/<arch>.md` (e.g. `architectures/hexagonal.md` for ports-and-adapters / NestJS-hex). Each stage is a list of rules; include EVERY matching resource (a change set can touch multiple languages/frameworks/architectures) — do not stop at the first match. These files are runtime resources, not Skill-tool skills, so always read them by path.
|
|
19
19
|
- **Project review rule packs:** also look for project-local review skills in `<PROJECT_ROOT>/skills/*review*`, `<PROJECT_ROOT>/.claude/skills/*review*`, and up to two parent directories' `skills/*review*/SKILL.md`. Read the relevant `SKILL.md` plus referenced `references/*.md` files and apply their rules during implementation. This is a prevention pass, not a PR-comment generation workflow: do not dispatch reviewer subagents from the executor. For Fonts Ninja-style PR review packs, the executor must avoid newly introduced duplicate helper stacks, tautological tests that merely re-call the delegated helper, self-mocking, domain rules in adapters/ports, domain objects outside `domain/`, dead APIs, weak public names, and functions that fail the plain-English read.
|
|
20
20
|
- **Language-agnostic principles that ALWAYS bind (the TDD loop MUST satisfy them):** (1) no self-mocking of the SUT — stub/spy only injected collaborators, never the subject's own methods; (2) behavioral assertions on outcomes (return value, state, persisted rows, events, boundary calls) — never `toHaveBeenCalled*` on an internal helper as the only/primary assertion; (3) truthful names — a `get*` / `find*` that writes/inserts, or a name encoding the caller's use-case (`*ForInit`) or hiding a domain rule (`findValid*`), is a defect; (4) single-purpose functions ≤50 effective lines, plain-English readability.
|
|
21
|
-
- **Graceful degradation (codex / gemini executor runtimes, or any runtime where the
|
|
21
|
+
- **Graceful degradation (codex / gemini executor runtimes, or any runtime where the resolved coding-preflight pack files are absent or unreadable):** do NOT skip the gate — apply the agnostic principles above plus the project's own `CLAUDE.md` / `CONTRIBUTING` / formatter+lint config, and record `coding-conventions: resource-unavailable → applied <project rules + agnostic principles>` in the final report. Never claim a resource read that did not happen.
|
|
@@ -7,14 +7,14 @@ profile document.
|
|
|
7
7
|
-->
|
|
8
8
|
- Team contract (shared):
|
|
9
9
|
- `Claude lead` is synthesis-only and stays distinct from `Claude worker` (or, in `implementation`, the `Executor` and verifiers).
|
|
10
|
-
- `Report writer worker` is the **author** of the final-report file; `Claude lead` reviews and approves the produced draft and does NOT write the file itself (see `
|
|
10
|
+
- `Report writer worker` is the **author** of the final-report file; `Claude lead` reviews and approves the produced draft and does NOT write the file itself (see `team-contract` and `report-writer` for the authoritative contract).
|
|
11
11
|
- default model assignments are resolved from centralised defaults; the fallback values are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.5`, `Gemini worker`=`auto`. Phase-specific overrides (e.g. `implementation`'s executor binding) live in the per-profile document.
|
|
12
12
|
- every required worker listed in the per-profile `Required workers:` block must be attempted; the final verdict waits until each has either a result or an explicit terminal status (`timeout`, `error`, `not-run`).
|
|
13
13
|
- unnamed generic parallel workers must not replace the required role roster, and no additional sub-agent dispatch is allowed beyond this roster.
|
|
14
14
|
- Worker interaction model (shared — read before inferring behaviour from the roster):
|
|
15
15
|
- the per-profile `Required workers:` block is a **roster**, not a behaviour contract. Each role's interaction mode changes across operating phases of the same run.
|
|
16
16
|
- **Phase 4 / 5 (independent analysis)**: analyser workers (`claude`, `codex`, `gemini` when opted in) produce findings independently and have no access to one another's outputs. `report-writer` does not analyse.
|
|
17
|
-
- **Phase 5.5 (convergence — peer review by workers)**: the lead replays each analyser's findings to the *other* analysers and collects `AGREE` / `DISAGREE` / `SUPPLEMENT` verdicts across up to `effectiveMaxRounds` rounds. Workers act as peer reviewers of each other's findings in this phase; the lead mediates but does not vote. See `
|
|
17
|
+
- **Phase 5.5 (convergence — peer review by workers)**: the lead replays each analyser's findings to the *other* analysers and collects `AGREE` / `DISAGREE` / `SUPPLEMENT` verdicts across up to `effectiveMaxRounds` rounds. Workers act as peer reviewers of each other's findings in this phase; the lead mediates but does not vote. See `prompts/lead/convergence.md` for the round protocol, queue invariants, and final classification (`full-consensus` / `partial-consensus` / `contested` / `worker-unique`). For `requirements-discovery`, `error-analysis`, and `implementation-planning` this phase runs in **adversarial mode** (`convergence.adversarial=true`): verifiers try to refute each finding against its cited evidence and the burden of proof sits on the claim — see that skill's §"Adversarial Verification Mode".
|
|
18
18
|
- Do NOT conclude "no peer review happens" from the roster alone — every profile that lists ≥2 analyser workers runs convergence by default (`convergence.enabled=true` in `task-manifest.json`).
|
|
19
19
|
- Tooling — read-only MCP availability (shared):
|
|
20
20
|
- MCP is not implicit okstra context. Query an MCP server only when the task brief explicitly lists it as source material for this run. Any MCP-derived finding MUST cite server, table, and the SELECT used. MCP MUST NEVER be used as a write path — schema/data mutations go through repository migration files reviewed by humans.
|
|
@@ -11,7 +11,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
|
|
|
11
11
|
|
|
12
12
|
## Executor role binding (carried over from the thin core)
|
|
13
13
|
|
|
14
|
-
- **Executor dispatch labelling.** When Lead dispatches the Executor it MUST set the Agent `name` to `<provider>-executor` (e.g. `codex-executor`, `claude-executor`) — NOT the generic `<provider>-worker` — so the FleetView teammate pill names the job; see `
|
|
14
|
+
- **Executor dispatch labelling.** When Lead dispatches the Executor it MUST set the Agent `name` to `<provider>-executor` (e.g. `codex-executor`, `claude-executor`) — NOT the generic `<provider>-worker` — so the FleetView teammate pill names the job; see `prompts/lead/okstra-lead-contract.md` Phase 4 "Agent `name` on dispatch". For a `codex` / `gemini` Executor, Lead MUST additionally inject a `**Pane role:** executor` line into the dispatched prompt body so the CLI wrapper titles its tmux trace pane `<cli>-executor-<pid>` (the wrapper reads that line per `agents/workers/_cli-wrapper-template.md`). Token attribution is unaffected — the collector matches any `agentName` beginning `<provider>-`.
|
|
15
15
|
- The `Executor` (bound in `implementation.md` thin core) is the **only worker permitted to use Edit / Write / state-mutating Bash commands** on project files. All other workers run read-only. When the executor provider is `codex` or `gemini`, the actual file mutation happens inside the executor CLI's own auto-edit mode (e.g. `codex exec --sandbox workspace-write`, gemini's equivalent) — not through Claude-side Edit/Write tools — but the safety rules in this sidecar still apply identically.
|
|
16
16
|
- Worktree cwd handling — when the thin core's Task worktree block resolves status to `created` or `reused`, the Executor MUST run every Edit / Write / build / test / commit command with the worktree path as cwd. Treat it as `project_root` for the duration of this run. Do NOT mutate the caller's original checkout. Do NOT `cd` out of the worktree to reach files; if a file outside the worktree is needed, the dependency is a planning gap — record it in `Out-of-plan edits` and continue.
|
|
17
17
|
- **How to set cwd per Bash call**: the Claude Bash tool inherits its cwd from the lead session, which is NOT the worktree. To put cwd-sensitive toolchains (`cargo`, `npm`, `pnpm`, `bun`, `pytest`, `make`, `go`) into the worktree, prefix the command with `cd {{EXECUTOR_WORKTREE_PATH}} && ` inside the same Bash invocation — e.g. `cd {{EXECUTOR_WORKTREE_PATH}} && cargo test -p foo`. **Never wrap in `bash -lc "..."` or `bash -c "..."`** — the wrapper hides the leading `cd` token from Claude Code's permission auto-allow layer (causing prompts on every call) without any safety benefit. For tools that accept an explicit working-directory flag (`git -C <path>`, `cargo --manifest-path`, `pytest --rootdir`), prefer that form over the `cd && ` chain. Edit / Write / Read tool calls already use absolute paths and need no cwd handling. The codex / gemini executor CLI wrappers (`okstra-codex-exec.sh -C`, `okstra-gemini-exec.sh --include-directories`) already inject worktree cwd at the CLI layer, so this rule applies primarily to the Claude executor.
|
|
@@ -19,7 +19,7 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
|
|
|
19
19
|
|
|
20
20
|
## Pre-implementation context exploration (executor before first edit)
|
|
21
21
|
|
|
22
|
-
- **Coding-conventions preflight (BLOCKING — runs before the first `Edit` / `Write`, and binds the TDD loop below).** The gate body is a single source at `prompts/profiles/_coding-conventions-preflight.md` (sibling of this sidecar):
|
|
22
|
+
- **Coding-conventions preflight (BLOCKING — runs before the first `Edit` / `Write`, and binds the TDD loop below).** The gate body is a single source at `prompts/profiles/_coding-conventions-preflight.md` (sibling of this sidecar): resolved `Coding preflight pack:` runtime-resource path usage, project review rule packs, the always-binding language-agnostic principles, and graceful degradation. Do NOT re-type that content from memory — deliver it by file so it cannot drift or be dropped:
|
|
23
23
|
- **Claude executor:** Read `_coding-conventions-preflight.md` end-to-end before the first `Edit` / `Write`, then state in ONE line which conventions apply (e.g. `Applying TS + hexagonal overlay; domain at src/domains/*/domain/`).
|
|
24
24
|
- **CLI executor (BLOCKING when the executor provider is `codex` or `gemini`):** the executor CLI process does NOT share the lead's context, and it cannot Read this sidecar's directory — that path sits outside the CLI sandbox and the CLI only sees its stdin prompt, so a file reference never reaches it. The lead MUST physically append the **body** of `_coding-conventions-preflight.md` into the persisted executor prompt at dispatch time: Read the file from the same absolute directory you read this sidecar from, then `Write`/`cat` its body into the persisted prompt. Never hand-retype it. Enforcement: the CLI wrapper agents refuse an implementation-Executor dispatch whose persisted prompt lacks the literal heading `Coding-conventions preflight`, returning `<SENTINEL_PREFIX>_PREFLIGHT_MISSING` (see `agents/workers/_cli-wrapper-template.md` → Prompt Composition).
|
|
25
25
|
- **Stage discipline transcription (when a preceding stage is `done`):** the lead MUST transcribe the `Stage discipline` rule (from this run's rendered profile — the INCLUDEd `_stage-discipline.md` body) verbatim into the dispatched CLI executor prompt, so a codex/gemini executor honors the prior-stage behavior-freeze. Declaration-level — no wrapper sentinel.
|
|
@@ -9,7 +9,7 @@ at Phase 5, BEFORE constructing the verifier worker dispatch prompts.
|
|
|
9
9
|
|
|
10
10
|
## Verifier roles (resolved at run-prep time)
|
|
11
11
|
|
|
12
|
-
- **Verifier dispatch labelling.** When Lead dispatches a verifier (here, and identically in `final-verification`) it MUST set the Agent `name` to `<provider>-verifier` (e.g. `claude-verifier`, `codex-verifier`) — NOT the generic `<provider>-worker` — so the FleetView teammate pill names the job; see `
|
|
12
|
+
- **Verifier dispatch labelling.** When Lead dispatches a verifier (here, and identically in `final-verification`) it MUST set the Agent `name` to `<provider>-verifier` (e.g. `claude-verifier`, `codex-verifier`) — NOT the generic `<provider>-worker` — so the FleetView teammate pill names the job; see `prompts/lead/okstra-lead-contract.md` Phase 4 "Agent `name` on dispatch". For a `codex` / `gemini` verifier, Lead MUST additionally inject a `**Pane role:** verifier` line into the dispatched prompt body so the CLI wrapper titles its tmux trace pane `<cli>-verifier-<pid>` (the wrapper reads that line per `agents/workers/_cli-wrapper-template.md`). Token attribution is unaffected — the collector matches any `agentName` beginning `<provider>-`.
|
|
13
13
|
- The verifier slots are `Claude verifier` and `Codex verifier`, plus `Gemini verifier` **only when `gemini` is in the resolved `--workers` roster**. Every verifier in the resolved roster is dispatched regardless of which provider holds the executor role; the executor's own provider is run *separately* as a verifier (a fresh CLI session with no shared context) so that no verdict is produced from the same session that wrote the diff. Verifiers MUST NOT call Edit, Write, or any Bash command that mutates files outside the run's artifact directories. If a verifier wants a fix, it records the recommendation in its worker result; it does not apply the fix itself.
|
|
14
14
|
- Session isolation — not model-variant divergence — is the primary self-review safeguard: each verifier is a separate CLI invocation with its own context window, so reusing the same model variant for executor and same-provider verifier is acceptable. Different model variants (e.g. executor=opus / Claude verifier=sonnet) remain recommended when available.
|
|
15
15
|
- Phase-specific model defaults override the shared defaults: `Claude verifier`=`opus`, `Codex verifier`=`gpt-5.5`, `Gemini verifier`=`auto` (only when present in the roster). The `Executor`'s model is taken from the provider-specific worker model corresponding to `--executor`: claude→`--claude-model` (default `opus`), codex→`--codex-model` (default `gpt-5.5`), gemini→`--gemini-model` (default `auto`).
|
|
@@ -88,7 +88,7 @@ The final report keeps both — executor's `Validation evidence` AND each verifi
|
|
|
88
88
|
Re-running commands proves the diff *builds and passes*; it does NOT prove the diff is *well-designed*. Lint/test green is necessary but not sufficient — self-mocked tests, interaction-only assertions, and untruthful names all survive a green pipeline. This gate is the filter for exactly those defects, so the executor's design errors are caught here instead of in post-merge PR review. It is a real gate, not a checklist: it enumerates the full diff and a blocking hit forces `FAIL`.
|
|
89
89
|
|
|
90
90
|
- **Scope (no silent sampling).** Enumerate every changed source/test file via `git diff --name-only <base>...HEAD` and review each one. Skipping a changed file silently is a `contract-violated` outcome. If a file's language has no reference and is not covered by the agnostic checks below, record `design-review skipped: <file> (language=<x> no reference)` — never pass it silently.
|
|
91
|
-
- **Load the same conventions the executor used
|
|
91
|
+
- **Load the same conventions the executor used via the routed pack.** Use this worker prompt's `**Coding preflight pack:**` anchor header as the absolute path to the installed routed pack. Read `overview.md` first, then `clean-code.md`, then apply the router's three ordered stages: language, framework, architecture. In each stage, iterate every rule, treat a rule as matched when any listed condition is true, and accumulate every matching resource — including `frameworks/node-server.md` for server-side Node work and `architectures/hexagonal.md` for ports-and-adapters / NestJS-hex layouts. Degrade to the agnostic checks below when the resolved pack is unreadable, and record either `coding-conventions: resources=<...>` or `coding-conventions: resource-unavailable → applied <project rules + agnostic principles>`. The verifier does NOT inline language rules — it loads the same situation-specific resources as the executor preflight.
|
|
92
92
|
- **Load project review rule packs when present.** Search the project root, `.claude/skills`, and up to two parent `skills/` directories for `*review*/SKILL.md` rule packs. Read their referenced `references/*.md` files and apply them as an overlay on this static review. If a premium review skill exists, use its coverage philosophy (recall-first enumeration followed by verify-only confirmation) as the verifier's mental model, but do NOT dispatch extra reviewer agents unless the task explicitly configured them. Record `project-review-rules: <paths read>` or `project-review-rules: none found` in the worker result.
|
|
93
93
|
- **Blocking checks (any hit → verdict `FAIL`, cited `path:line` + rule name, recommended fix recorded — the verifier does NOT apply it):**
|
|
94
94
|
- **New duplication / DRY:** two or more newly added or meaningfully modified blocks implement the same helper stack, transform, or domain rule. Literal copy-paste is always blocking; semantically equivalent transforms across services are blocking unless the approved plan explicitly justified keeping them separate. Recommend the shared module location.
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
- **Codebase-first ambiguity resolution (defect rule)**: any ambiguity about repro, file behavior, or symbol semantics that can be answered by `Read` / `Grep` / log inspection MUST be resolved that way and recorded with file:line (or log-line) evidence. Writing a clarification row for something the codebase or shipped logs already answer is a defect of this phase.
|
|
38
38
|
- **Evidence note required inside `Statement`**: every clarification row includes `Evidence checked: <path:line>` or `Evidence checked: none — <reporter-only reason>` in the `Statement` cell. `none` is allowed ONLY when the row's nature is "only the reporter can answer this" (reporter-side data, business priority, environment they observed). A row with `none` that *could* have been answered by code or logs is a defect.
|
|
39
39
|
- Cross-verification mode:
|
|
40
|
-
- Phase 5.5 convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each root-cause / reproduction claim by directly re-inspecting the cited code, logs, or config; the burden of proof sits on the claim. See `
|
|
41
|
-
- **Coverage critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker critic pass is dispatched concurrently with the first convergence reverify round to surface missed findings; its gaps are merged only after a 1-round adversarial reverify that follows convergence. See `
|
|
40
|
+
- Phase 5.5 convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each root-cause / reproduction claim by directly re-inspecting the cited code, logs, or config; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode". A single evidence-backed refutation prevents a finding from reaching consensus.
|
|
41
|
+
- **Coverage critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker critic pass is dispatched concurrently with the first convergence reverify round to surface missed findings; its gaps are merged only after a 1-round adversarial reverify that follows convergence. See `prompts/lead/convergence.md` "Coverage critic pass".
|
|
42
42
|
- Non-goals:
|
|
43
43
|
- implementation details unless they are necessary to validate the cause
|
|
44
44
|
- **source code edits, builds, migrations, or deployments** — this run produces evidence and cause analysis only; the fix belongs to a later `implementation-planning` run followed by an `implementation` run
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
4. **Verifier dissent preserved** — if workers reach different verdicts, the disagreement is visible in section 1.2; synthesis hides nothing.
|
|
49
49
|
5. **No source-mutation audit** — scan the run's session transcripts for Edit / Write or state-mutating Bash commands that touch paths OUTSIDE `<PROJECT_ROOT>/.okstra/**` and outside the assigned run-artifact paths. Writes to worker prompts, audit sidecars, team-state, the final-report `data.json`, and rendered reports under the run directory are allowed okstra artifacts. Any source/schema/deployment mutation means the run has crossed into implementation and MUST be re-routed; do NOT silently strip the evidence.
|
|
50
50
|
- Cross-verification mode:
|
|
51
|
-
- **Acceptance critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker **acceptance devil's-advocate** pass is dispatched concurrently with the first convergence reverify round to surface candidate acceptance blockers the verifiers may have missed; candidates are verified only after convergence completes. Each candidate is verified **confirm-or-downgrade**: confirmed → an `Acceptance Blockers` row (which, since `accepted` requires zero blockers, moves the verdict to `conditional-accept` / `blocked`); unconfirmed → a `Residual Risk` row (never dropped). See `
|
|
51
|
+
- **Acceptance critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker **acceptance devil's-advocate** pass is dispatched concurrently with the first convergence reverify round to surface candidate acceptance blockers the verifiers may have missed; candidates are verified only after convergence completes. Each candidate is verified **confirm-or-downgrade**: confirmed → an `Acceptance Blockers` row (which, since `accepted` requires zero blockers, moves the verdict to `conditional-accept` / `blocked`); unconfirmed → a `Residual Risk` row (never dropped). See `prompts/lead/convergence.md` "Acceptance critic pass (final-verification)".
|
|
52
52
|
- Non-goals:
|
|
53
53
|
- proposing unrelated refactors beyond the delivered scope
|
|
54
54
|
- **source code edits, follow-up bug fixes, or scope expansion** — this run renders a verdict only; defects detected here become inputs to a new `error-analysis` or `implementation-planning` run
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
- Approval gate (phase-specific addendum to shared authority rule):
|
|
41
41
|
- The YAML frontmatter `approved: true|false` field is the only authorised approval gate. report-writer always emits `approved: false`. The user clears it either by (a) editing the frontmatter line to `approved: true` directly, or (b) invoking the next phase with `--approve` so the CLI flips the frontmatter on the user's behalf. `okstra_ctl.run._validate_approved_plan` reads this field and refuses entry until it is `true`.
|
|
42
42
|
- Cross-verification mode:
|
|
43
|
-
- Phase 5.5 finding convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker finding (requirement gap / risk / option) by re-inspecting its cited evidence; the burden of proof sits on the claim. See `
|
|
44
|
-
- §5.5.9 plan-body verification runs with an **adversarial posture** (`
|
|
45
|
-
- **Coverage critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker critic pass is dispatched concurrently with the first convergence reverify round to surface missed findings; its gaps are merged only after a 1-round adversarial reverify that follows convergence. See `
|
|
43
|
+
- Phase 5.5 finding convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker finding (requirement gap / risk / option) by re-inspecting its cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode".
|
|
44
|
+
- §5.5.9 plan-body verification runs with an **adversarial posture** (`prompts/lead/convergence.md` §"Adversarial plan-body posture"): verifiers open and confirm every cited path / command and put the burden of proof on the plan. The gate threshold is unchanged — a *majority* `DISAGREE` (`majority-disagree`) is still required to block approval; a single dissent does not.
|
|
45
|
+
- **Coverage critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker critic pass is dispatched concurrently with the first convergence reverify round to surface missed findings; its gaps are merged only after a 1-round adversarial reverify that follows convergence. See `prompts/lead/convergence.md` "Coverage critic pass".
|
|
46
46
|
- Non-goals:
|
|
47
47
|
- code-level micro-optimization unless it changes the implementation approach
|
|
48
48
|
- **source code edits of any kind** — this run produces a plan document only; Edit/Write on project source files is forbidden until the plan is approved and a separate `implementation` run starts
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
- the YAML frontmatter MUST include the line `implementation-option:` directly under `approved:` (report-writer always emits it with an **empty value**). The user selects which Option Candidate the next `implementation` run executes by filling this line with that option's name (manual edit or `--implementation-option <name>` CLI). When left empty, the `implementation` run falls back to the `Recommended Option`.
|
|
91
91
|
- **the frontmatter `approved: false` line is rendered unconditionally; if the plan-body verification gate (§5.5.9) returns `blocked-by-disagreement` or `aborted-non-result`, the writer MUST keep `approved: false` and the validator refuses any report that ships with `approved: true` under such a gate result.**
|
|
92
92
|
- every ambiguity flagged during pre-planning that the user must resolve before approval registered as a `Blocks=approval` row in the `## 1. Clarification Items` table (do NOT create a separate `Open Questions` block under the implementation plan body — the unified table is the single home)
|
|
93
|
-
- **§5.5.9 Plan Body Verification (BLOCKING).** After report-writer finishes the draft, the lead MUST run a worker peer-review round on the consolidated plan body (Option Candidates / Trade-off Matrix / Recommended Option / Stage Map and per-stage sections / Dependency / Validation Checklist / Rollback / Requirement Coverage) and populate `### 5.5.9 Plan Body Verification` in the final report. The round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics, gate-result classification, and dissent log format are defined in `
|
|
93
|
+
- **§5.5.9 Plan Body Verification (BLOCKING).** After report-writer finishes the draft, the lead MUST run a worker peer-review round on the consolidated plan body (Option Candidates / Trade-off Matrix / Recommended Option / Stage Map and per-stage sections / Dependency / Validation Checklist / Rollback / Requirement Coverage) and populate `### 5.5.9 Plan Body Verification` in the final report. The round protocol, plan-item ID scheme (`P-Opt-*` / `P-Step-*` / `P-Dep-*` / `P-Val-*` / `P-Rb-*`), verdict semantics, gate-result classification, and dissent log format are defined in `prompts/lead/convergence.md` "Plan-body verification mode". The four gate-result values are `passed`, `passed-with-dissent`, `blocked-by-disagreement`, `aborted-non-result`. When the gate would have been `blocked-by-disagreement` or `aborted-non-result`, the lead MUST NOT silently flip it to one of the passing values to "unblock" the run — that is a contract violation. When `convergence.adversarial=true` (the default for this phase), this round uses the adversarial posture — verifiers confirm cited paths/commands and the burden of proof is on the plan — but the gate threshold stays `majority-disagree` (see that skill's §"Adversarial plan-body posture").
|
|
94
94
|
- **Decision-record evaluation (sole owner)**: this phase is the **single owner** of decision-record evaluation in the okstra lifecycle. The brief never evaluates or drafts decision records — it only forwards `adr-candidate:*` signals. Every `adr-candidate:*` entry inherited from the brief's `Open Questions` is a mandatory evaluation target. In addition, evaluate every decision the recommended option introduces against the three criteria:
|
|
95
95
|
1. **Hard to reverse** — would changing the decision later cost meaningfully more than deciding now?
|
|
96
96
|
2. **Surprising without context** — would a future reader, seeing only the code, wonder "why was it built this way?"?
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
- **Codebase-first ambiguity resolution (defect rule)**: any ambiguity that can be answered by `Read` / `Grep` / file inspection MUST be resolved that way and recorded with file:line evidence. Writing a clarification row for something the codebase already answers is a defect of this phase.
|
|
53
53
|
- **Evidence note required inside `Statement`**: every clarification row includes `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>` in the `Statement` cell. `none` is allowed ONLY when the row's nature is "only a human can answer this" (reporter intent, business priority, external authority). A row with `none` that *could* have been answered by the codebase is a defect.
|
|
54
54
|
- Cross-verification mode:
|
|
55
|
-
- Phase 5.5 convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker's finding by directly re-inspecting the cited evidence; the burden of proof sits on the claim. See `
|
|
56
|
-
- **Coverage critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker critic pass is dispatched concurrently with the first convergence reverify round to surface missed findings; its gaps are merged only after a 1-round adversarial reverify that follows convergence. See `
|
|
55
|
+
- Phase 5.5 convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker's finding by directly re-inspecting the cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode". A single evidence-backed refutation prevents a finding from reaching consensus.
|
|
56
|
+
- **Coverage critic (opt-in)**: when `convergence.critic.enabled=true` (chosen via the okstra-run picker or `--critic`), a reused-worker critic pass is dispatched concurrently with the first convergence reverify round to surface missed findings; its gaps are merged only after a 1-round adversarial reverify that follows convergence. See `prompts/lead/convergence.md` "Coverage critic pass".
|
|
57
57
|
- Non-goals:
|
|
58
58
|
- full implementation design unless it is required to decide the next phase
|
|
59
59
|
- **source code edits, plan authoring, builds, or deployments** — this run only classifies the work and routes it; deeper analysis and planning belong to subsequent phases
|
|
@@ -21,6 +21,7 @@ from typing import Any, Mapping, Sequence
|
|
|
21
21
|
from .lead_events import LeadEvent, append_lead_event
|
|
22
22
|
from .wrapper_status import status_path_for_prompt
|
|
23
23
|
from .paths import task_dir
|
|
24
|
+
from .worker_prompt_headers import WorkerPromptHeaderError, worker_prompt_headers
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
SUPPORTED_CLI_WORKERS = {
|
|
@@ -32,7 +33,6 @@ BACKEND_MIXED = "mixed"
|
|
|
32
33
|
MAX_WORKER_ATTEMPTS = 2
|
|
33
34
|
REPORT_WRITER_WORKER_ID = "report-writer"
|
|
34
35
|
REPORT_LANGUAGE_VALUES = {"en", "ko", "auto"}
|
|
35
|
-
WORKER_PREAMBLE_PATH = Path.home() / ".okstra" / "templates" / "worker-prompt-preamble.md"
|
|
36
36
|
ANALYSIS_WORKER_LABELS = {
|
|
37
37
|
"codex": "Codex worker",
|
|
38
38
|
"gemini": "Gemini worker",
|
|
@@ -676,19 +676,17 @@ def _base_prompt_headers(
|
|
|
676
676
|
prompt_rel: str,
|
|
677
677
|
result_rel: str,
|
|
678
678
|
) -> list[str]:
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
),
|
|
691
|
-
]
|
|
679
|
+
try:
|
|
680
|
+
return worker_prompt_headers(
|
|
681
|
+
project_root=project_root,
|
|
682
|
+
prompt_rel=prompt_rel,
|
|
683
|
+
result_rel=result_rel,
|
|
684
|
+
worker_id=worker_id,
|
|
685
|
+
manifest=manifest,
|
|
686
|
+
active_context=active_context,
|
|
687
|
+
)
|
|
688
|
+
except WorkerPromptHeaderError as exc:
|
|
689
|
+
raise DispatchError(str(exc)) from exc
|
|
692
690
|
|
|
693
691
|
|
|
694
692
|
def _analysis_input_lines(
|
|
@@ -814,53 +812,6 @@ def _implementation_executor_tail(
|
|
|
814
812
|
return preflight_path.read_text(encoding="utf-8")
|
|
815
813
|
|
|
816
814
|
|
|
817
|
-
def _errors_log_path(
|
|
818
|
-
project_root: Path,
|
|
819
|
-
manifest: Mapping[str, Any],
|
|
820
|
-
active_context: Mapping[str, Any],
|
|
821
|
-
) -> Path:
|
|
822
|
-
error_logs = active_context.get("errorLogs")
|
|
823
|
-
if isinstance(error_logs, Mapping):
|
|
824
|
-
value = _string_value(error_logs.get("runErrorsLogPath"))
|
|
825
|
-
if value:
|
|
826
|
-
return _resolve_project_path(project_root, value)
|
|
827
|
-
run_dir = _run_directory_path(project_root, manifest)
|
|
828
|
-
return run_dir / "logs" / f"errors-{_require_string(manifest, 'taskType')}-{_sequence(manifest, 'state')}.jsonl"
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
def _worker_errors_sidecar_path(
|
|
832
|
-
project_root: Path,
|
|
833
|
-
manifest: Mapping[str, Any],
|
|
834
|
-
active_context: Mapping[str, Any],
|
|
835
|
-
worker_id: str,
|
|
836
|
-
) -> Path:
|
|
837
|
-
error_logs = active_context.get("errorLogs")
|
|
838
|
-
if isinstance(error_logs, Mapping):
|
|
839
|
-
sidecars = error_logs.get("sidecarsByWorkerId")
|
|
840
|
-
if isinstance(sidecars, Mapping):
|
|
841
|
-
value = _string_value(sidecars.get(worker_id))
|
|
842
|
-
if value:
|
|
843
|
-
return _resolve_project_path(project_root, value)
|
|
844
|
-
run_dir = _run_directory_path(project_root, manifest)
|
|
845
|
-
task_type = _require_string(manifest, "taskType")
|
|
846
|
-
seq = _sequence(manifest, "workerResults")
|
|
847
|
-
return run_dir / "worker-results" / f"{worker_id}-worker-errors-{task_type}-{seq}.json"
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
def _run_directory_path(project_root: Path, manifest: Mapping[str, Any]) -> Path:
|
|
851
|
-
value = _string_value(manifest.get("runDirectoryPath"))
|
|
852
|
-
if value:
|
|
853
|
-
return _resolve_project_path(project_root, value)
|
|
854
|
-
return _resolve_required_path(project_root, manifest, "teamStatePath", "team-state").parent.parent
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
def _sequence(manifest: Mapping[str, Any], key: str) -> str:
|
|
858
|
-
seqs = manifest.get("runSequencesByCategory")
|
|
859
|
-
if not isinstance(seqs, Mapping):
|
|
860
|
-
return _run_seq(manifest)
|
|
861
|
-
return _string_value(seqs.get(key)) or _run_seq(manifest)
|
|
862
|
-
|
|
863
|
-
|
|
864
815
|
def _project_relative_path(project_root: Path, path: Path) -> str:
|
|
865
816
|
try:
|
|
866
817
|
return path.relative_to(project_root).as_posix()
|
|
@@ -23,15 +23,17 @@ INPUT_FILES = (
|
|
|
23
23
|
"reference-expectations.md",
|
|
24
24
|
"clarification-response.md",
|
|
25
25
|
)
|
|
26
|
-
# Per-run hot-path instruction assets the lead
|
|
27
|
-
#
|
|
26
|
+
# Per-run hot-path instruction assets the lead loads OUTSIDE the task bundle:
|
|
27
|
+
# the lifecycle lead contracts (Phase 1 / 2-5 / 5.5 / 6-7) plus the worker
|
|
28
28
|
# agent specs. These are the prompt-diet (perf plan v2 P2) targets; the
|
|
29
29
|
# bundle-local metrics below cannot see them, so they get their own metric.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
30
|
+
# The contracts ship as runtime resources under ~/.okstra/prompts/lead/, not
|
|
31
|
+
# as agent skills.
|
|
32
|
+
HOT_PATH_LEAD_RESOURCES = (
|
|
33
|
+
"context-loader",
|
|
34
|
+
"team-contract",
|
|
35
|
+
"convergence",
|
|
36
|
+
"report-writer",
|
|
35
37
|
)
|
|
36
38
|
WORKER_AGENT_FILES = (
|
|
37
39
|
"claude-worker.md",
|
|
@@ -178,13 +180,14 @@ def _skill_assets_metric() -> dict:
|
|
|
178
180
|
skill bodies + worker agent specs. These dominate the fixed per-run
|
|
179
181
|
instruction footprint and are the prompt-diet ranking input."""
|
|
180
182
|
entries = []
|
|
183
|
+
okstra_home = Path.home() / ".okstra"
|
|
181
184
|
claude_home = Path.home() / ".claude"
|
|
182
|
-
for name in
|
|
185
|
+
for name in HOT_PATH_LEAD_RESOURCES:
|
|
183
186
|
path = _installed_or_dev(
|
|
184
|
-
|
|
185
|
-
f"
|
|
187
|
+
okstra_home / "prompts" / "lead" / f"{name}.md",
|
|
188
|
+
f"prompts/lead/{name}.md",
|
|
186
189
|
)
|
|
187
|
-
entries.append((f"
|
|
190
|
+
entries.append((f"resource:{name}", path))
|
|
188
191
|
for fname in WORKER_AGENT_FILES:
|
|
189
192
|
path = _installed_or_dev(
|
|
190
193
|
claude_home / "agents" / fname,
|
|
@@ -12,6 +12,7 @@ from typing import Any, Mapping, Sequence
|
|
|
12
12
|
|
|
13
13
|
from . import tmux
|
|
14
14
|
from .lead_events import LeadEvent, append_lead_event
|
|
15
|
+
from .worker_prompt_headers import WorkerPromptHeaderError, worker_prompt_headers
|
|
15
16
|
from .wrapper_status import read_wrapper_status, status_path_for_prompt
|
|
16
17
|
|
|
17
18
|
|
|
@@ -290,9 +291,19 @@ def _job_from_roster_worker(
|
|
|
290
291
|
state = _worker_state(team_state, worker_id)
|
|
291
292
|
provider = _provider_for_worker(worker_id)
|
|
292
293
|
model = _model_for_worker(worker_id, state, report_writer_model)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
prompt_rel = _worker_prompt_path(manifest, worker_id)
|
|
295
|
+
result_rel = _require_string(state, "resultPath")
|
|
296
|
+
prompt_path = _resolve_project_path(project_root, prompt_rel)
|
|
297
|
+
result_path = _resolve_project_path(project_root, result_rel)
|
|
298
|
+
_materialize_prompt_if_missing(
|
|
299
|
+
prompt_path=prompt_path,
|
|
300
|
+
prompt_rel=prompt_rel,
|
|
301
|
+
worker_id=worker_id,
|
|
302
|
+
result_rel=result_rel,
|
|
303
|
+
project_root=project_root,
|
|
304
|
+
manifest=manifest,
|
|
305
|
+
active_context=active_context,
|
|
306
|
+
)
|
|
296
307
|
return WorkerJob(
|
|
297
308
|
worker_id=worker_id,
|
|
298
309
|
provider=provider,
|
|
@@ -747,19 +758,31 @@ def _resolve_wrapper(provider: str, workspace_root: Path, options: _BuildOptions
|
|
|
747
758
|
raise DispatchError(f"{script} not found (searched: {', '.join(str(c) for c in candidates)})")
|
|
748
759
|
|
|
749
760
|
|
|
750
|
-
def _materialize_prompt_if_missing(
|
|
761
|
+
def _materialize_prompt_if_missing(
|
|
762
|
+
*,
|
|
763
|
+
prompt_path: Path,
|
|
764
|
+
prompt_rel: str,
|
|
765
|
+
worker_id: str,
|
|
766
|
+
result_rel: str,
|
|
767
|
+
project_root: Path,
|
|
768
|
+
manifest: Mapping[str, Any],
|
|
769
|
+
active_context: Mapping[str, Any],
|
|
770
|
+
) -> None:
|
|
751
771
|
if prompt_path.is_file():
|
|
752
772
|
return
|
|
753
773
|
prompt_path.parent.mkdir(parents=True, exist_ok=True)
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
774
|
+
try:
|
|
775
|
+
headers = worker_prompt_headers(
|
|
776
|
+
project_root=project_root,
|
|
777
|
+
prompt_rel=prompt_rel,
|
|
778
|
+
result_rel=result_rel,
|
|
779
|
+
worker_id=worker_id,
|
|
780
|
+
manifest=manifest,
|
|
781
|
+
active_context=active_context,
|
|
782
|
+
)
|
|
783
|
+
except WorkerPromptHeaderError as exc:
|
|
784
|
+
raise DispatchError(str(exc)) from exc
|
|
785
|
+
prompt_path.write_text("\n".join([*headers, ""]), encoding="utf-8")
|
|
763
786
|
|
|
764
787
|
|
|
765
788
|
def _provider_for_worker(worker_id: str) -> str:
|