okstra 0.207.0 → 0.208.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 +3 -2
- package/dist/cli-registry.mjs +6 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/render-bundle.mjs +1 -1
- package/dist/commands/lifecycle/doctor.mjs +1 -1
- package/dist/lib/skill-catalog.mjs +1 -0
- package/dist/lib/skill-catalog.mjs.map +1 -1
- package/docs/architecture/storage-model.md +14 -0
- package/docs/architecture.md +30 -9
- package/docs/cli.md +26 -22
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/project-structure-overview.md +15 -8
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/operations/explain-flow.json +6 -0
- package/runtime/bin/lib/okstra/cli.sh +1 -5
- package/runtime/bin/lib/okstra/globals.sh +0 -2
- package/runtime/bin/lib/okstra/usage.sh +5 -3
- package/runtime/bin/okstra.sh +0 -2
- package/runtime/prompts/duties/business-flow-investigator.json +14 -0
- package/runtime/prompts/lead/context-loader.md +1 -1
- package/runtime/prompts/lead/convergence.md +22 -7
- package/runtime/prompts/lead/okstra-lead-contract.md +10 -6
- package/runtime/prompts/lead/report-writer.md +1 -1
- package/runtime/prompts/lead/team-contract.md +12 -17
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/wizard/prompts.ko.json +0 -91
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +6 -0
- package/runtime/python/okstra_ctl/agent/invocation.py +1 -1
- package/runtime/python/okstra_ctl/agent/prompt_cli/batch.py +1 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +1 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +11 -125
- package/runtime/python/okstra_ctl/agent/standalone.py +183 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +39 -8
- package/runtime/python/okstra_ctl/assignment_resolver.py +7 -1
- package/runtime/python/okstra_ctl/brief_frontmatter.py +10 -0
- package/runtime/python/okstra_ctl/business_flow/__init__.py +4 -0
- package/runtime/python/okstra_ctl/business_flow/cli.py +134 -0
- package/runtime/python/okstra_ctl/business_flow/contracts.py +268 -0
- package/runtime/python/okstra_ctl/business_flow/engine.py +518 -0
- package/runtime/python/okstra_ctl/business_flow/hooks.py +221 -0
- package/runtime/python/okstra_ctl/business_flow/invocation.py +170 -0
- package/runtime/python/okstra_ctl/business_flow/report.py +49 -0
- package/runtime/python/okstra_ctl/business_flow/source.py +206 -0
- package/runtime/python/okstra_ctl/business_flow/store.py +388 -0
- package/runtime/python/okstra_ctl/convergence.py +173 -2
- package/runtime/python/okstra_ctl/convergence_critic_verify_prompt.py +18 -0
- package/runtime/python/okstra_ctl/convergence_provenance.py +8 -0
- package/runtime/python/okstra_ctl/coverage_census.py +596 -0
- package/runtime/python/okstra_ctl/design_surfaces.py +4 -0
- package/runtime/python/okstra_ctl/direct_work.py +1 -1
- package/runtime/python/okstra_ctl/dispatch_core.py +7 -3
- package/runtime/python/okstra_ctl/doctor.py +12 -6
- package/runtime/python/okstra_ctl/domain/role.py +1 -0
- package/runtime/python/okstra_ctl/group_context.py +5 -4
- package/runtime/python/okstra_ctl/legacy_model_selection.py +7 -51
- package/runtime/python/okstra_ctl/manager_split.py +4 -1
- package/runtime/python/okstra_ctl/manager_view.py +9 -3
- package/runtime/python/okstra_ctl/model_io/lines.py +1 -24
- package/runtime/python/okstra_ctl/model_io/renderers.py +54 -41
- package/runtime/python/okstra_ctl/phases/change_impact_analysis/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/change_impact_analysis/profile.md +0 -8
- package/runtime/python/okstra_ctl/phases/error_analysis/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/error_analysis/profile.md +6 -8
- package/runtime/python/okstra_ctl/phases/feature_analysis/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/feature_analysis/profile.md +0 -8
- package/runtime/python/okstra_ctl/phases/final_verification/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/final_verification/profile.md +2 -8
- package/runtime/python/okstra_ctl/phases/implementation/boundary.json +1 -1
- package/runtime/python/okstra_ctl/phases/implementation/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/implementation/profile.md +0 -6
- package/runtime/python/okstra_ctl/phases/implementation/report_assets/implementation-input.template.md +1 -1
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/authoring.py +4 -3
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/entry.py +1 -14
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/profile.md +5 -8
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/spec.md +3 -3
- package/runtime/python/okstra_ctl/phases/implementation_option_selection/validation.py +15 -5
- package/runtime/python/okstra_ctl/phases/implementation_planning/authoring.py +9 -1
- package/runtime/python/okstra_ctl/phases/implementation_planning/boundary.json +1 -1
- package/runtime/python/okstra_ctl/phases/implementation_planning/instructions/plan-body-verification.md +4 -2
- package/runtime/python/okstra_ctl/phases/implementation_planning/plan_body.py +25 -9
- package/runtime/python/okstra_ctl/phases/implementation_planning/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/implementation_planning/profile.md +7 -10
- package/runtime/python/okstra_ctl/phases/improvement_discovery/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/improvement_discovery/profile.md +4 -11
- package/runtime/python/okstra_ctl/phases/project_analysis/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/project_analysis/profile.md +0 -8
- package/runtime/python/okstra_ctl/phases/release_handoff/profile.md +1 -1
- package/runtime/python/okstra_ctl/phases/release_handoff/spec.md +1 -1
- package/runtime/python/okstra_ctl/phases/requirements_discovery/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/requirements_discovery/profile.md +10 -8
- package/runtime/python/okstra_ctl/phases/requirements_discovery/spec.md +3 -3
- package/runtime/python/okstra_ctl/phases/technical_verification/profile.json +1 -1
- package/runtime/python/okstra_ctl/phases/technical_verification/profile.md +0 -4
- package/runtime/python/okstra_ctl/plan_items.py +1 -1
- package/runtime/python/okstra_ctl/render.py +10 -43
- package/runtime/python/okstra_ctl/render_final_report.py +3 -0
- package/runtime/python/okstra_ctl/report_assembly.py +15 -1
- package/runtime/python/okstra_ctl/report_finalize.py +40 -0
- package/runtime/python/okstra_ctl/report_html/render.py +3 -0
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +1 -2
- package/runtime/python/okstra_ctl/run.py +78 -409
- package/runtime/python/okstra_ctl/wizard/__init__.py +2 -24
- package/runtime/python/okstra_ctl/wizard/cli.py +3 -6
- package/runtime/python/okstra_ctl/wizard/confirmation.py +3 -35
- package/runtime/python/okstra_ctl/wizard/engine.py +2 -4
- package/runtime/python/okstra_ctl/wizard/ids.py +1 -88
- package/runtime/python/okstra_ctl/wizard/registry.py +36 -228
- package/runtime/python/okstra_ctl/wizard/render.py +2 -2
- package/runtime/python/okstra_ctl/wizard/roles.py +1 -3
- package/runtime/python/okstra_ctl/wizard/sources.py +9 -40
- package/runtime/python/okstra_ctl/wizard/state.py +36 -145
- package/runtime/python/okstra_ctl/wizard/statefile.py +27 -128
- package/runtime/python/okstra_ctl/wizard/steps_identity.py +22 -10
- package/runtime/python/okstra_ctl/wizard/steps_options.py +5 -4
- package/runtime/python/okstra_ctl/wizard/steps_roles.py +15 -565
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +9 -2
- package/runtime/schemas/business-flow-v1.schema.json +847 -0
- package/runtime/schemas/convergence-groups-v2.0.schema.json +7 -0
- package/runtime/skills/okstra-explain-flow/SKILL.md +42 -0
- package/runtime/skills/okstra-inspect/facets/history.md +5 -5
- package/runtime/skills/okstra-run/SKILL.md +2 -2
- package/runtime/templates/manager/view.template.html +7 -4
- package/runtime/templates/reports/business-flow.template.md +106 -0
- package/runtime/templates/reports/html/base.template.html +14 -1
- package/runtime/templates/reports/html/business-flow.template.html +31 -0
- package/runtime/templates/reports/html/i18n/en.json +1 -0
- package/runtime/templates/reports/html/i18n/ko.json +1 -0
- package/runtime/templates/worker-prompt-preamble.md +11 -2
- package/runtime/validators/checks/validate-prompt-metadata-01.py +10 -10
- package/runtime/validators/validate-run.py +70 -21
- package/runtime/validators/validate_analysis_report.py +21 -21
- package/runtime/python/okstra_ctl/workers.py +0 -133
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# Implementation Option Selection Profile
|
|
2
2
|
|
|
3
3
|
- Purpose: compare feasible implementation directions before planning, preserving a read-only record of the evidence and trade-offs that selects the direction to plan
|
|
4
|
-
- Required workers:
|
|
5
|
-
- claude
|
|
6
|
-
- codex
|
|
7
|
-
- antigravity
|
|
8
|
-
- report-writer
|
|
9
|
-
- Optional workers (opt-in via `--workers`):
|
|
10
|
-
- grok
|
|
11
|
-
- kimi
|
|
12
4
|
{{INCLUDE:_common-contract.md}}
|
|
13
5
|
- Brief consumption:
|
|
14
6
|
- Apply the shared reporter-confirmation precondition exactly as written. Unresolved `intent-check:` and `conversion-block:` rows use `Blocks=next-phase`.
|
|
@@ -18,6 +10,11 @@
|
|
|
18
10
|
- In `candidate-comparison` mode only, submit at most three candidates. A candidate must be feasible from inspected evidence, not from an assumed future change.
|
|
19
11
|
- In `preselected-validation` mode, receive one preselected direction from the lead and validate its evidence, counterevidence, criterion scores, and requirement mappings, and state the same feasibility verdict with its rationale and counterevidence. The worker must not generate new candidates.
|
|
20
12
|
- Do not produce detailed file lists, stage maps, execution commands, or a plan approval request.
|
|
13
|
+
- Census aspects:
|
|
14
|
+
- requirement mapping: Which candidate or preselected direction satisfies this requirement, and how?
|
|
15
|
+
- requirement support: Which inspected evidence supports that mapping?
|
|
16
|
+
- requirement counter-evidence: What is the strongest evidence against that mapping?
|
|
17
|
+
- task feasibility: Is each candidate feasible, not feasible, or uncertain on inspected evidence?
|
|
21
18
|
- Pre-selection context exploration:
|
|
22
19
|
- In `candidate-comparison` mode, inspect the code paths, interfaces, tests, and constraints needed to distinguish candidates before assigning scores.
|
|
23
20
|
- In `preselected-validation` mode, inspect the code paths, interfaces, tests, and constraints needed to validate the one preselected direction.
|
|
@@ -8,7 +8,7 @@ This directory owns candidate evaluation, vote completion, comparison projection
|
|
|
8
8
|
|---|---|---|
|
|
9
9
|
| IOS-1 | Candidate scores, coverage, votes and ranking are recomputed | `scripts/okstra_ctl/phases/implementation_option_selection/validation.py::validate_implementation_option_selection` |
|
|
10
10
|
| IOS-2 | Blocked facts retain their user decision or technical evidence channel | `scripts/okstra_ctl/phases/implementation_option_selection/validation.py::validate_blocked_answer_channel` |
|
|
11
|
-
| IOS-3 |
|
|
11
|
+
| IOS-3 | A valid candidate needs two `feasible` votes, or the single vote when the user selected one designer | `scripts/okstra_ctl/phases/implementation_option_selection/validation.py::required_feasible_votes`; `scripts/okstra_ctl/phases/implementation_option_selection/tests/test_implementation_options.py::test_a_single_designer_vote_validates_its_candidate` |
|
|
12
12
|
| IOS-4 | Candidate fingerprints deduplicate equivalent mechanisms | `scripts/okstra_ctl/phases/implementation_option_selection/tests/test_implementation_options.py::test_duplicate_candidates_share_a_fingerprint` |
|
|
13
13
|
|
|
14
14
|
Report schemas remain in `schemas/final-report-v2.0.schema.json` and `schemas/final-report-v3.0.schema.json`, under `implementationOptionSelection`. Next-phase decisions belong to `prompts/lead/phase-routing.md`.
|
|
@@ -36,11 +36,11 @@ Direction confirmation and detailed plan approval are independent user decisions
|
|
|
36
36
|
| `candidate-comparison` | Requirement ledger, cause evidence, code evidence, independently proposed raw candidates | At most three ranked valid directions and a separate user selection |
|
|
37
37
|
| `preselected-validation` | A direction already fixed by upstream evidence or an explicit user instruction | One normalized and validated direction, or `blocked`; no alternative is generated |
|
|
38
38
|
|
|
39
|
-
The
|
|
39
|
+
The user selects one to five designers (`profile.json`, three recommended) plus the report writer. Each designer may propose at most three raw candidates. All analysers reassess the merged candidate set before ranking.
|
|
40
40
|
|
|
41
41
|
## 3. Prepare gates
|
|
42
42
|
|
|
43
|
-
Prepare rejects the phase when the brief has no stable `EB-NNN`, `PB-NNN`, or `EO-NNN` requirement IDs. External Gates are not part of that denominator.
|
|
43
|
+
Prepare rejects the phase when the brief has no stable `EB-NNN`, `PB-NNN`, or `EO-NNN` requirement IDs. External Gates are not part of that denominator.
|
|
44
44
|
|
|
45
45
|
The phase reuses the task-key worktree and may inspect the code and prior task artifacts. It does not obtain a writable implementation-stage worktree.
|
|
46
46
|
|
|
@@ -224,6 +224,15 @@ def _validate_option_scores(
|
|
|
224
224
|
return values_valid and weighted_score_valid
|
|
225
225
|
|
|
226
226
|
|
|
227
|
+
def required_feasible_votes(participating_analysers: Sequence[str]) -> int:
|
|
228
|
+
"""유효한 후보에 필요한 `feasible` 표 수.
|
|
229
|
+
|
|
230
|
+
사용자가 설계자를 한 명만 고르면 두 번째 표는 오지 않는다. 그때는 그 한 표가
|
|
231
|
+
전부이고, 교차 모델 검증이 없었다는 사실은 run 의 advisory 와 리포트가 알린다.
|
|
232
|
+
"""
|
|
233
|
+
return min(MIN_FEASIBLE_VOTES, max(1, len(set(participating_analysers))))
|
|
234
|
+
|
|
235
|
+
|
|
227
236
|
def _validate_option_feasibility(
|
|
228
237
|
option: Mapping[str, object],
|
|
229
238
|
participating_analysers: Sequence[str],
|
|
@@ -246,8 +255,9 @@ def _validate_option_feasibility(
|
|
|
246
255
|
isinstance(vote, Mapping) and vote.get("verdict") == "feasible"
|
|
247
256
|
for vote in votes
|
|
248
257
|
)
|
|
249
|
-
|
|
250
|
-
|
|
258
|
+
required = required_feasible_votes(participating_analysers)
|
|
259
|
+
if require_valid and feasible < required:
|
|
260
|
+
errors.append(f"{option_id} must have at least {required} feasible vote(s)")
|
|
251
261
|
if require_valid and option.get("safetyBlockers"):
|
|
252
262
|
errors.append(f"{option_id} safetyBlockers must be empty")
|
|
253
263
|
if require_valid and option.get("unresolvedFeasibilityFacts"):
|
|
@@ -260,7 +270,7 @@ def _validate_option_feasibility(
|
|
|
260
270
|
)
|
|
261
271
|
return (
|
|
262
272
|
all_participated
|
|
263
|
-
and feasible >=
|
|
273
|
+
and feasible >= required
|
|
264
274
|
and not option.get("safetyBlockers")
|
|
265
275
|
and not option.get("unresolvedFeasibilityFacts")
|
|
266
276
|
and not copied
|
|
@@ -394,7 +404,7 @@ def vote_gaps(
|
|
|
394
404
|
여기서 세는 것은 **표만 모자란** 후보다. `safetyBlockers` 나
|
|
395
405
|
`unresolvedFeasibilityFacts` 가 있거나 베낀 표가 있으면 표를 더 받아도
|
|
396
406
|
유효해지지 않으므로 제외한다. 남은 표를 다 받아도 `feasible` 이
|
|
397
|
-
`
|
|
407
|
+
`required_feasible_votes` 에 못 미치는 후보도 제외한다 — 부쳐 봐야 결과가
|
|
398
408
|
같다.
|
|
399
409
|
"""
|
|
400
410
|
roster = list(dict.fromkeys(str(name) for name in participating_analysers))
|
|
@@ -422,7 +432,7 @@ def vote_gaps(
|
|
|
422
432
|
isinstance(vote, Mapping) and vote.get("verdict") == "feasible"
|
|
423
433
|
for vote in votes
|
|
424
434
|
)
|
|
425
|
-
if feasible + len(missing) <
|
|
435
|
+
if feasible + len(missing) < required_feasible_votes(roster):
|
|
426
436
|
continue
|
|
427
437
|
gaps.append(
|
|
428
438
|
VoteGap(
|
|
@@ -1377,7 +1377,8 @@ def _seed(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
1377
1377
|
|
|
1378
1378
|
Idempotent by id. An existing row keeps everything it carries — verdicts
|
|
1379
1379
|
already applied, `carriedForwardFromSeq`, `selfFixNote` — because a re-seed
|
|
1380
|
-
between rounds must not erase the round before it.
|
|
1380
|
+
between rounds must not erase the round before it. `contentHash` and
|
|
1381
|
+
`stageScope` are re-derived from the current plan.
|
|
1381
1382
|
|
|
1382
1383
|
`--prior-state` extends that to the previous *run*: a newly seeded item
|
|
1383
1384
|
whose text the previous run already judged inherits its verdicts instead of
|
|
@@ -1415,10 +1416,17 @@ def _seed(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
1415
1416
|
]
|
|
1416
1417
|
carried = _carry_prior_run_verdicts(args, added, hashes)
|
|
1417
1418
|
recorded.extend(added)
|
|
1419
|
+
scopes = {item["id"]: item.get("stageScope") for item in extracted}
|
|
1418
1420
|
for row in recorded:
|
|
1419
1421
|
item_id = row.get("id") if isinstance(row, Mapping) else None
|
|
1420
1422
|
if isinstance(item_id, str) and item_id in hashes:
|
|
1421
1423
|
row["contentHash"] = hashes[item_id]
|
|
1424
|
+
# 큐는 추출값으로, 게이트는 이 행으로 범위를 정한다. 행의 범위가 낡으면
|
|
1425
|
+
# 재검증 큐에서 빠진 항목이 게이트를 계속 막는다(2026-10-04 dev-11118 P-Val-5).
|
|
1426
|
+
if scopes[item_id]:
|
|
1427
|
+
row["stageScope"] = scopes[item_id]
|
|
1428
|
+
else:
|
|
1429
|
+
row.pop("stageScope", None)
|
|
1422
1430
|
if args.state is not None:
|
|
1423
1431
|
audit_rows = data.get("planItems")
|
|
1424
1432
|
if not isinstance(audit_rows, list):
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"file writes outside the run`s artifact directories (`reports/`, `prompts/`, `state/`, `manifests/`, `worker-results/`, `status/`, `sessions/`), including task-root QA scripts, manifest, and tsconfig (planning declares conformance commands and required dependencies; implementation writes these files); in particular, do not write to `docs/superpowers/specs/` or `docs/superpowers/plans/`",
|
|
6
6
|
"executing builds, migrations, deployments, or any state-mutating command",
|
|
7
7
|
"starting `implementation` inside this run (must be a separate run authorised by an approved deliverable from this phase), even if the user says \"다음 단계 진행해\"",
|
|
8
|
-
"dispatching parallel sub-agents beyond the
|
|
8
|
+
"dispatching parallel sub-agents beyond the run's selected roster (okstra owns worker fan-out)",
|
|
9
9
|
"leaving placeholders such as TBD / TODO / \"handle edge cases\" / \"similar to Option N\" in the report",
|
|
10
10
|
"delegating the self-review pass — the Okstra lead must run it"
|
|
11
11
|
]
|
|
@@ -55,7 +55,9 @@ Plan-body verification is configured under `convergence.planBodyVerification` in
|
|
|
55
55
|
|
|
56
56
|
Default values are emitted into the manifest by `scripts/okstra_ctl/render.py` (`_build_convergence_block`). The ctx knob `OKSTRA_PLAN_VERIFICATION=false` flips `planBodyVerification.enabled` to false. `gating=false` is not that opt-out: extraction and one round still run.
|
|
57
57
|
|
|
58
|
-
The shared Majority definition
|
|
58
|
+
The shared Majority definition is owned by `prompts/lead/convergence.md` §"Convergence Algorithm" / §"Configuration" and applies here unchanged.
|
|
59
|
+
|
|
60
|
+
**A one-analyser roster.** When the user selected one planner, no second vote can arrive, so that planner's vote is the panel: a non-error `DISAGREE` settles its item on that vote instead of returning `needs-reverify`, and the round closes on the gate it scored. The run carries a `no cross-model check` advisory. **Enforced:** `scripts/okstra_ctl/phases/implementation_planning/plan_body.py` `_classify_plan_item_gate` lowers its quorum to one when `planBodyVerification.participatingAnalysers.rostered` is 1.
|
|
59
61
|
|
|
60
62
|
## Plan-item extraction (Round 0 equivalent)
|
|
61
63
|
|
|
@@ -456,7 +458,7 @@ For contract 3.0, `prepare` checks the selected-direction draft with the same se
|
|
|
456
458
|
|
|
457
459
|
The environment exception in §"Planning-time environment gap" covers **running build and test commands only** — whether a referenced path exists, whether a command is declared in `package.json`, and whether the plan is internally consistent are all checkable without it, and a blanket "capability constraints prevent workspace resolution" is not a valid answer to any of them.
|
|
458
460
|
|
|
459
|
-
**How the corrective round is recorded.** The first prompt was dispatched, so it is immutable — `--replace-undispatched` refuses it, correctly. Materialize the correction under a NEW `--invocation-id` and a new prompt path. Before linking its result, retire the first attempt's link: `okstra agent-prompt reject-result --project-root <dir> --run-manifest <path> --dispatch-id <first dispatch id> --superseded-by <corrective dispatch id> --reason "<what was wrong with the returned result>"`. Without that step the corrective `link-result` fails with `agent result is already linked to another dispatch`, which is how a worker that ran for twenty minutes and wrote a good result ends up unrecordable. Nothing is deleted: the rejected link stays in `agentResultLinks` carrying `supersededBy` and `rejectionReason`, so the ledger shows both attempts and why the second exists.
|
|
461
|
+
**How the corrective round is recorded.** The first prompt was dispatched, so it is immutable — `--replace-undispatched` refuses it, correctly. Materialize the correction under a NEW `--invocation-id` and a new prompt path. Before linking its result, retire the first attempt's link: `okstra agent-prompt reject-result --project-root <dir> --run-manifest <path> --dispatch-id <first dispatch id> --superseded-by <corrective dispatch id> --reason "<what was wrong with the returned result>"`. Without that step the corrective `link-result` fails with `agent result is already linked to another dispatch`, which is how a worker that ran for twenty minutes and wrote a good result ends up unrecordable. Run it only when the first attempt has a link: a team dispatch links a result only when its attempt settles `completed`, so an attempt that ended in `error` has none, and `reject-result` then fails with `expected exactly one agent result link … found 0` — skip the step in that case. Nothing is deleted: the rejected link stays in `agentResultLinks` carrying `supersededBy` and `rejectionReason`, so the ledger shows both attempts and why the second exists.
|
|
460
462
|
|
|
461
463
|
Then run `okstra plan-items complete-round --state <plan-body-verification.json> --run-manifest <current-run-manifest.json> --round <N>`. Python appends one immutable round history entry, records each verified item's votes, derives the current projection from the actual assigned roster, and stamps `completedAt` after the preceding verification command succeeds. The file accumulates across rounds; it is never truncated to the latest one. Report assembly later projects the completed nested `planBodyVerification` into the final record.
|
|
462
464
|
7. **Self-fix loop (one rewrite, targeting planner-fixable defects).** After the initial verification, lead may run one report-writer rewrite when a `majority-disagree` item has a majority of `DISAGREE` verdicts at `fixability == planner-fixable`. Re-verify changed items once, preserving verdicts on unchanged content. Then stop automatic self-fix regardless of outcome and follow step 8. The fixed order is initial verification → one planner self-fix → targeted re-verification → lead decision or immediate user confirmation. A second automatic self-fix is rejected by `plan_items_cli._record_self_fixes`; `_validate_self_fix_grouping` and session activity validation detect multiple recorded rewrites. No rewrite is needed when no item qualifies.
|
|
@@ -207,7 +207,13 @@ def _critic_gate_class(item: dict) -> str | None:
|
|
|
207
207
|
return "has-dissent" if dissent else "full-consensus"
|
|
208
208
|
|
|
209
209
|
|
|
210
|
-
def
|
|
210
|
+
def _rostered_analysers(pbv: dict) -> int | None:
|
|
211
|
+
declared = pbv.get("participatingAnalysers")
|
|
212
|
+
rostered = declared.get("rostered") if isinstance(declared, dict) else None
|
|
213
|
+
return rostered if isinstance(rostered, int) else None
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _classify_plan_item_gate(item: dict, *, rostered_analysers: int | None = None) -> str:
|
|
211
217
|
"""Recompute one plan item's gate class from its per-worker verdicts,
|
|
212
218
|
per `prompts/lead/plan-body-verification.md` "Round protocol". Returns one of
|
|
213
219
|
``majority-disagree`` / ``needs-reverify`` / ``has-dissent`` /
|
|
@@ -216,7 +222,8 @@ def _classify_plan_item_gate(item: dict) -> str:
|
|
|
216
222
|
``majority-disagree`` so the user gate sees it. ``has-dissent`` remains
|
|
217
223
|
advisory-only, rollback items, and a single-vote kind that lost its
|
|
218
224
|
reproduction. An analyser 1-1 is ``needs-reverify`` until ``critic-worker``
|
|
219
|
-
settles it.
|
|
225
|
+
settles it. With a one-analyser roster the single vote is the panel: no
|
|
226
|
+
peer can ever vote, so waiting for one would stall the round.
|
|
220
227
|
"""
|
|
221
228
|
corrected = _critic_gate_class(item)
|
|
222
229
|
if corrected is not None:
|
|
@@ -253,6 +260,7 @@ def _classify_plan_item_gate(item: dict) -> str:
|
|
|
253
260
|
if not blocking_disagree:
|
|
254
261
|
return "has-dissent"
|
|
255
262
|
blocking_kinds = {bk for (_vd, bk) in blocking_disagree if bk}
|
|
263
|
+
quorum = 1 if rostered_analysers == 1 else 2
|
|
256
264
|
# Single-vote-blocking kinds: one confirmed DISAGREE on a concrete,
|
|
257
265
|
# safety-critical, adversarially-verifiable defect is enough to block, even
|
|
258
266
|
# in a two-worker roster — a lone correct dissent must not be outvoted here.
|
|
@@ -270,19 +278,19 @@ def _classify_plan_item_gate(item: dict) -> str:
|
|
|
270
278
|
# the dissent, so blocking here would reproduce the same
|
|
271
279
|
# worker-failure-makes-the-gate-stricter paradox the majority branch
|
|
272
280
|
# below guards against. Route it to a re-verify round instead.
|
|
273
|
-
if len(non_error) <
|
|
281
|
+
if len(non_error) < quorum:
|
|
274
282
|
return "needs-reverify"
|
|
275
283
|
return "majority-disagree"
|
|
276
284
|
# Otherwise a genuine majority is required — and a majority needs at least
|
|
277
285
|
# two participating votes, so a lone surviving DISAGREE (its peer returned a
|
|
278
286
|
# non-result) does NOT block. That fixes the paradox where a worker failure
|
|
279
287
|
# made the gate stricter than a healthy roster would.
|
|
280
|
-
if len(non_error) >=
|
|
288
|
+
if len(non_error) >= quorum and len(blocking_disagree) > len(agree):
|
|
281
289
|
return "majority-disagree"
|
|
282
290
|
if len(blocking_disagree) == len(agree) and len(non_error) >= 2:
|
|
283
291
|
return "needs-reverify"
|
|
284
292
|
if (
|
|
285
|
-
len(non_error) >=
|
|
293
|
+
len(non_error) >= quorum
|
|
286
294
|
and blocking_disagree
|
|
287
295
|
and (not (blocking_kinds & single_vote_kinds) or _is_variation_point_item(item))
|
|
288
296
|
):
|
|
@@ -486,7 +494,9 @@ def _resolved_noncritical_dissent_ids(data: dict) -> set[str]:
|
|
|
486
494
|
|
|
487
495
|
def _plan_item_decision_authority(item: dict, pbv: dict) -> str | None:
|
|
488
496
|
"""자동 수정 이후의 설계 판단만 리드가 결정하며 사실·사용자 권한은 남긴다."""
|
|
489
|
-
classification = _classify_plan_item_gate(
|
|
497
|
+
classification = _classify_plan_item_gate(
|
|
498
|
+
item, rostered_analysers=_rostered_analysers(pbv)
|
|
499
|
+
)
|
|
490
500
|
votes = [row for row in item.get("verdicts", []) if isinstance(row, dict)]
|
|
491
501
|
non_result = any(
|
|
492
502
|
row.get("verdict") not in {"AGREE", "SUPPLEMENT", "DISAGREE"} for row in votes
|
|
@@ -537,7 +547,9 @@ def _is_dissent_downgraded(
|
|
|
537
547
|
) -> bool:
|
|
538
548
|
"""유효한 리드 결정 또는 사용자 진행 처분은 반대 표를 보존하며 차단을 해소한다."""
|
|
539
549
|
return _lead_decision_applies(item, pbv) or (
|
|
540
|
-
_classify_plan_item_gate(
|
|
550
|
+
_classify_plan_item_gate(
|
|
551
|
+
item, rostered_analysers=_rostered_analysers(pbv)
|
|
552
|
+
) == "majority-disagree"
|
|
541
553
|
and str(item.get("id") or "") in accepted_item_ids
|
|
542
554
|
)
|
|
543
555
|
|
|
@@ -582,7 +594,9 @@ def _set_aside_reason(item: dict, pbv: dict, accepted_item_ids: set[str]) -> str
|
|
|
582
594
|
raw = (
|
|
583
595
|
"has-dissent"
|
|
584
596
|
if _is_dissent_downgraded(item, pbv, accepted_item_ids)
|
|
585
|
-
else _classify_plan_item_gate(
|
|
597
|
+
else _classify_plan_item_gate(
|
|
598
|
+
item, rostered_analysers=_rostered_analysers(pbv)
|
|
599
|
+
)
|
|
586
600
|
)
|
|
587
601
|
if raw != "majority-disagree":
|
|
588
602
|
return None
|
|
@@ -619,7 +633,9 @@ def _plan_item_gate_class(
|
|
|
619
633
|
classification = (
|
|
620
634
|
"has-dissent"
|
|
621
635
|
if _is_dissent_downgraded(item, pbv, accepted_item_ids)
|
|
622
|
-
else _classify_plan_item_gate(
|
|
636
|
+
else _classify_plan_item_gate(
|
|
637
|
+
item, rostered_analysers=_rostered_analysers(pbv)
|
|
638
|
+
)
|
|
623
639
|
)
|
|
624
640
|
if classification != "majority-disagree":
|
|
625
641
|
return classification
|
|
@@ -7,14 +7,6 @@ Validation commands are executable inputs: preserve their newlines, quotes, and
|
|
|
7
7
|
Plan for the actual worktree layout before approval. Shared documentation directories can be links to the main checkout. Choose a build command compatible with those links (for example, an installed Next.js version may provide `next build --webpack`); verify the available option rather than assuming it. Do not plan for a verifier to move links or repair its environment. Compare negative-case assertions with the brief and the script body: a requirement to cache existing assets does not establish that missing assets should be cached. Record any changed expectation in a new plan revision; preserve the earlier approved plan.
|
|
8
8
|
|
|
9
9
|
- Purpose: turn an upstream-selected direction into an executable plan; legacy reruns may retain candidate comparison
|
|
10
|
-
- Required workers:
|
|
11
|
-
- claude
|
|
12
|
-
- codex
|
|
13
|
-
- report-writer
|
|
14
|
-
- Optional workers (opt-in via `--workers`):
|
|
15
|
-
- antigravity — when added to the roster it joins the analyser set; omitted by default
|
|
16
|
-
- grok — optional adversarial analyser/critic through the Grok CLI wrapper
|
|
17
|
-
- kimi — optional long-context analyser/critic through the Kimi CLI wrapper
|
|
18
10
|
{{INCLUDE:_common-contract.md}}
|
|
19
11
|
{{INCLUDE:_stage-discipline.md}}
|
|
20
12
|
- Brief consumption (phase-specific addendum — shared rules live in `_common-contract.md` under "Brief handoff contract"):
|
|
@@ -32,6 +24,11 @@ Plan for the actual worktree layout before approval. Shared documentation direct
|
|
|
32
24
|
4. If current evidence requires changing the selected direction, emit `direction-invalidated` and stop planning.
|
|
33
25
|
- identify requirement gaps and affected interfaces with file:line evidence, resolving codebase-answerable ambiguity before returning findings
|
|
34
26
|
- surface migration, deployment, cross-project, and approval risks without drafting final-report headings or schema rows
|
|
27
|
+
- Census aspects:
|
|
28
|
+
- requirement plan-linkage: Which planned files and stages realize this requirement?
|
|
29
|
+
- requirement interface-impact: Which interfaces does realizing this requirement change, and who calls them?
|
|
30
|
+
- requirement validation: Which validation step proves this requirement once the plan is executed?
|
|
31
|
+
- task migration-deploy-approval-risk: Which migration, deployment, cross-project, or approval risk does the plan carry?
|
|
35
32
|
- Legacy candidate-comparison-only responsibilities:
|
|
36
33
|
- **Legacy candidate-comparison procedure** — only a legacy rerun without `selected-direction.json` compares feasible Option Candidates, preserves their trade-offs and Recommended Option, then produces stages, validation, rollback, and requirement coverage. This is the only branch that generates candidates, assigns candidate scores, recommends a direction, or awaits a user candidate choice.
|
|
37
34
|
- **Spec-settled short-circuit** — when the brief already carries a decision-complete design the reporter has confirmed, do not re-litigate it. Preserve that design as the Recommended Option and its already-weighed alternatives as the remaining Option Candidates.
|
|
@@ -95,7 +92,7 @@ Plan for the actual worktree layout before approval. Shared documentation direct
|
|
|
95
92
|
- **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
|
|
96
93
|
- executing builds, migrations, deployments, or any command that mutates project state outside the run's own artifact directories (`reports/`, `prompts/`, `state/`, `manifests/`, `worker-results/`, `status/`, `sessions/`)
|
|
97
94
|
- this run stays in `implementation-planning` regardless of user phrasing — the shared anti-escalation rule applies
|
|
98
|
-
- dispatching parallel sub-agents beyond the
|
|
95
|
+
- dispatching parallel sub-agents beyond the run's selected roster — okstra owns worker fan-out
|
|
99
96
|
- writing artifacts anywhere except `<PROJECT_ROOT>/.okstra/` — the run's `reports/` directory is the canonical location for this phase
|
|
100
97
|
- Clarification request policy (phase-specific addenda — shared policy is in `_common-contract.md`):
|
|
101
98
|
{{INCLUDE:_clarification-recommendation.md}}
|
|
@@ -293,7 +290,7 @@ For a new `implementation-planning` run, the fixed order is initial verification
|
|
|
293
290
|
```
|
|
294
291
|
|
|
295
292
|
An `AGREE` response records the considered counterexample and exclusion reason in its note; unverified external material is `verification-error`, not `DISAGREE`.
|
|
296
|
-
2. Dispatch a single plan-body reverify round to every analyser worker in the roster
|
|
293
|
+
2. Dispatch a single plan-body reverify round to every analyser worker in the run's roster. `Report writer worker` is NOT a participant in this round.
|
|
297
294
|
3. Record each verifier Markdown result through `okstra plan-items apply-verdicts --state <plan-body-verification.json> --result <worker-id>=<result.md> --round <N>`. Python validates every submitted `P-*` identifier against the current convergence state and overwrites only that round's verdicts. Then resolve the gate result to one of `passed` / `passed-with-dissent` / `blocked-by-disagreement` / `aborted-non-result`.
|
|
298
295
|
4. After `okstra plan-verify` succeeds, run `okstra plan-items complete-round --state <plan-body-verification.json> --run-manifest <current-run-manifest.json> --round <N>`. Python reads the current worker assignments, atomically appends the convergence-owned history, and updates its nested final projection. This state is the only plan-verification input report assembly reads.
|
|
299
296
|
5. Record every *in-scope execution* `majority-disagree` decision through `okstra approval-decision`; record its plan and clarification links only on activities. Do not promote `observed` / `deferred` / `record` items, and do not append `clarificationItems[]` directly.
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
# Improvement Discovery Profile
|
|
2
2
|
|
|
3
3
|
- Purpose: scan a codebase scope through a fixed lens whitelist and surface ranked improvement candidates with multi-worker consensus classification
|
|
4
|
-
- Required workers:
|
|
5
|
-
- claude
|
|
6
|
-
- codex
|
|
7
|
-
- antigravity
|
|
8
|
-
- report-writer
|
|
9
|
-
- Optional workers (opt-in via `--workers`):
|
|
10
|
-
- grok — optional adversarial analyser/critic through the Grok CLI wrapper
|
|
11
|
-
- kimi — optional long-context analyser/critic through the Kimi CLI wrapper
|
|
12
|
-
- Roster guidance: the required block plus these opt-in providers form the full allowlist. As everywhere, `--workers` may narrow within it (`okstra_ctl.workers.validate_workers_against_profile` enforces the allowlist only, minimum 1), but narrowing this phase is strongly discouraged: cross-worker lens diversity is its load-bearing value, and a reduced roster produces candidates no second worker ever challenged.
|
|
13
4
|
{{INCLUDE:_common-contract.md}}
|
|
14
5
|
- Brief consumption (phase-specific addendum — shared rules live in `_common-contract.md` under "Brief handoff contract"):
|
|
15
6
|
- this phase REQUIRES a codebase-scan brief whose frontmatter contains `scope: codebase`. A brief without that marker is rejected before worker dispatch.
|
|
@@ -29,18 +20,20 @@
|
|
|
29
20
|
- for every candidate, record lens, scope, severity, effort, recommended next phase, evidence, and a worker-local source item ID
|
|
30
21
|
- identify overlap with other findings or linked tasks as duplicate, broader/narrower, conflicting, blocked-by, or follow-up instead of silently merging it
|
|
31
22
|
- Worker diversity rule:
|
|
32
|
-
- every analyser inspects every resolved priority lens. The Phase 1.5 grilling log assigns only the first pass: enumerate selected analyser worker instances in `
|
|
23
|
+
- every analyser inspects every resolved priority lens. The Phase 1.5 grilling log assigns only the first pass: enumerate selected analyser worker instances in `workerRoles` order and rotate them over resolved priority lenses in log order. Provider/model names never determine the position.
|
|
33
24
|
- each worker, before broadening to the remaining lenses, must do one of: (a) produce at least one candidate from its primary pass, or (b) record a no-candidate rationale citing the highest-signal path:line evidence it inspected.
|
|
34
25
|
- two workers' candidates are the same candidate only when they cite the same underlying design/code problem and the same remediation direction. Shared evidence paths alone are not enough to merge; keep distinct failure modes distinct.
|
|
35
26
|
- when a candidate from one worker overlaps another worker's evidence, convergence must classify the relationship as one of: duplicate, broader/narrower, or conflicting. Do not collapse contested candidates just to meet the candidate cap.
|
|
36
27
|
- when a candidate overlaps a brief `Related Task Graph` edge, convergence must classify whether the candidate is a duplicate of, blocked by, or follow-up to the linked task. Do not assign a new task-key without carrying the linked task reference into Recommended Next Steps.
|
|
28
|
+
- Census aspects:
|
|
29
|
+
- lens lens-review: Which improvement candidate, or which no-candidate rationale with path:line evidence, does this lens yield inside the scan scope?
|
|
37
30
|
- Phase 1.5 — Lead reflect-back grilling (runs after Phase 1 context loading and before Phase 4 worker dispatch):
|
|
38
31
|
- Lead inspects scan-scope paths via `ls` / `Grep` / `Read` to map modules, entry points, dependencies, and approximate LOC, and reviews recent git history to note which scan-scope files change most.
|
|
39
32
|
- Lead emits a single reflect-back message covering: (a) understood scope per path (one-line summary), (b) understood meaning of each priority lens in this scope, (c) understood out-of-scope rationale, (d) ordered list of N open questions.
|
|
40
33
|
- For each open question Lead asks ONE `AskUserQuestion` with a `(Recommended)` answer drawn from a codebase-first inspection. Budget: at most 12 questions in this phase.
|
|
41
34
|
- Stop conditions (OR): all questions resolved / budget exhausted / user signals proceed.
|
|
42
35
|
- Lead persists the round at `<RUN_DIR>/state/phase-1.5-grilling.md` with one section per question (question / recommended / user answer) and a closing `Resolved scope` / `Resolved lenses` block. Worker prompts use this resolved block as the authoritative scope and lens definition.
|
|
43
|
-
- The same log includes `## Primary Pass Assignments` with a `Worker ID | Primary lens` table. It contains every selected analyser exactly once in `
|
|
36
|
+
- The same log includes `## Primary Pass Assignments` with a `Worker ID | Primary lens` table. It contains every selected analyser exactly once in `workerRoles` order; the lead derives it from the resolved roster and lenses rather than provider catalog order.
|
|
44
37
|
- After writing the log and before Phase 4 dispatch, the lead injects its **absolute path** into every analyser prompt as the `**Phase 1.5 Grilling Log:** <absolute-path>` anchor header (see `okstra_ctl.worker_prompt_headers.worker_prompt_headers()`). This is the improvement-discovery counterpart to the `**Worktree:**` / `**Verification …:**` anchors that implementation / final-verification inject: workers read the log from this explicit path rather than re-deriving `<RUN_DIR>`. The path is byte-identical across all analysers, so it does not break the dispatch-prompt invariant.
|
|
45
38
|
- Decision-tree walk (bounded):
|
|
46
39
|
- When candidates branch on a structural question (e.g. "is module X meant to own this responsibility?"), resolve via `Read` / `Grep` first. Only escalate to the user inside the Phase 1.5 budget.
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# Project Analysis Profile
|
|
2
2
|
|
|
3
3
|
- Purpose: map a bounded project area so later work can navigate components, dependencies, entry points, repositories, and external integrations without changing the source
|
|
4
|
-
- Required workers:
|
|
5
|
-
- claude
|
|
6
|
-
- codex
|
|
7
|
-
- report-writer
|
|
8
|
-
- Optional workers (opt-in via `--workers`):
|
|
9
|
-
- antigravity
|
|
10
|
-
- grok — optional adversarial analyser/critic through the Grok CLI wrapper
|
|
11
|
-
- kimi — optional long-context analyser/critic through the Kimi CLI wrapper
|
|
12
4
|
{{INCLUDE:_common-contract.md}}
|
|
13
5
|
- Phase 1.5 questions:
|
|
14
6
|
- Which repositories, directories, and external systems are inside the scan scope?
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
shipped and in what order their PRs must be merged — the branch names do not say.
|
|
6
6
|
- Purpose: take a release-ready single-stage final-verification verdict for each already-committed implementation stage and turn it into a delivered push and/or pull request, with explicit user selection at every mutating step. **One stage is one PR.** The PR head is that stage's stack branch (`<prefix>-<task-id>-s<N>`); nothing is squashed, rebased, or collected into a bundle branch.
|
|
7
7
|
- **Execution model: single-lead, no worker dispatch.** This phase is a thin orchestrator over `git` / `gh`; it does NOT dispatch teammates, does NOT dispatch analysis or drafter sub-agents, and does NOT run convergence. The host-native Okstra lead performs every step inline (drafting PR text, asking the user, running git / gh, writing the final report) — see "Lead-only contract" below.
|
|
8
|
-
- Worker roster: none —
|
|
8
|
+
- Worker roster: none — `profile.json` declares no roles; the run is executed entirely by the Okstra lead.
|
|
9
9
|
- Lead-only contract (replaces the shared team contract for this phase):
|
|
10
10
|
- The host-native Okstra lead is the sole agent for this run. No worker dispatch, no teammates, no parallel sub-agents, no convergence loop. Do NOT run `okstra convergence` in any form: prepare already wrote this run's convergence state as "not run — fewer than two analysers", which is the record report assembly reads. **Enforced:** `okstra_ctl.render._initialize_lead_only_convergence` writes it when the run has no analysers, and leaves an existing state alone.
|
|
11
11
|
- The lead drafts each stage's PR title and PR body **inline** by reading the run brief, that stage's cited final-verification report, `git log --oneline <stage base>..<stage head>`, and `git diff <stage base>..<stage head> --stat`. No drafter worker is dispatched.
|
|
@@ -79,7 +79,7 @@ sequenceDiagram
|
|
|
79
79
|
P-->>W: lead prompt for current session
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
`profile.json` declares no roles, so prepare resolves an empty roster for `release-handoff`. So not going through the general TeamCreate / convergence / report-writer flow of `prompts/lead/okstra-lead-contract.md` is the intended behavior.
|
|
83
83
|
|
|
84
84
|
## 4. entry gate
|
|
85
85
|
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
# Requirements Discovery Profile
|
|
2
2
|
|
|
3
3
|
- Purpose: classify the work request, identify missing requirement evidence, and route the task to the safest next lifecycle phase before implementation starts
|
|
4
|
-
- Required workers:
|
|
5
|
-
- claude
|
|
6
|
-
- codex
|
|
7
|
-
- report-writer
|
|
8
|
-
- Optional workers (opt-in via `--workers`):
|
|
9
|
-
- antigravity — when added to the roster it joins the analyser set; omitted by default
|
|
10
|
-
- grok — optional adversarial analyser/critic through the Grok CLI wrapper
|
|
11
|
-
- kimi — optional long-context analyser/critic through the Kimi CLI wrapper
|
|
12
4
|
{{INCLUDE:_common-contract.md}}
|
|
13
5
|
- Brief consumption (phase-specific addendum — shared rules live in `_common-contract.md` under "Brief handoff contract"):
|
|
14
6
|
- Apply the shared reporter-confirmation precondition exactly as written. In this phase, unresolved `intent-check:` / `conversion-block:` rows use `Blocks=next-phase`.
|
|
@@ -22,6 +14,16 @@
|
|
|
22
14
|
- identify independently startable decomposition candidates without publishing or rendering fan-out artifacts; preserve every directed dependency from `Related Task Graph`
|
|
23
15
|
- resolve codebase-answerable ambiguity by inspection and record file:line evidence; return only human-owned decisions as clarification candidates with the evidence already checked
|
|
24
16
|
- state the reporter's rejection criteria, missing routing inputs, and the evidence boundary behind each recommendation
|
|
17
|
+
- Census aspects:
|
|
18
|
+
- requirement interpretation: What does this requirement ask for, read against the brief and the code it touches?
|
|
19
|
+
- requirement scope-boundary: Where does this requirement stop, and which nearby behaviour does it leave out?
|
|
20
|
+
- requirement dependency: What must exist or happen first for this requirement, in code or in a related task?
|
|
21
|
+
- requirement verification-method: How would a later phase observe that this requirement is met?
|
|
22
|
+
- requirement human-decision: Does this requirement need a decision only a person can make? Name it, or cite the code that settles it.
|
|
23
|
+
- task classification: Which work category (bugfix, feature, improvement, refactor, ops) does the evidence support?
|
|
24
|
+
- task rejection-criteria: Which delivered outcome would the reporter reject?
|
|
25
|
+
- task missing-materials: Which missing material blocks reliable routing?
|
|
26
|
+
- task terminology: Which fuzzy or overloaded terms need one canonical form, and what decides it?
|
|
25
27
|
- Primary focus areas:
|
|
26
28
|
- classify the work as bugfix, feature, improvement, refactor, or ops
|
|
27
29
|
- capture the reporter's **rejection criteria** — the delivered outcome that would make this work wrong or unacceptable — as a routing input. Consume it from the brief's `Desired Outcome` / `Out of Scope` / `Source Material` when present; when it is absent AND it would change the classification (e.g. bugfix vs feature) or the next-phase choice, raise it as one `decision` clarification row with `Evidence checked: none — reporter intent`. Never infer it — this is a reporter-intent signal, the mirror of improvement-discovery's `Anti-goals`
|
|
@@ -64,10 +64,10 @@ sequenceDiagram
|
|
|
64
64
|
participant Git as worktree registry
|
|
65
65
|
participant FS as task artifacts
|
|
66
66
|
|
|
67
|
-
W->>P: task-type=requirements-discovery, brief, base-ref,
|
|
68
|
-
P->>Prof: profile
|
|
67
|
+
W->>P: task-type=requirements-discovery, brief, base-ref, role selection
|
|
68
|
+
P->>Prof: profile.json role requirements loaded
|
|
69
69
|
P->>P: verify installation, upsert project.json
|
|
70
|
-
P->>P: resolve
|
|
70
|
+
P->>P: resolve role assignments from selection + model defaults
|
|
71
71
|
P->>Git: create or reuse task worktree
|
|
72
72
|
P->>P: expand _common-contract include
|
|
73
73
|
P->>FS: write instruction-set and manifests
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# Technical Verification Profile
|
|
2
2
|
|
|
3
3
|
- Purpose: collect experimental evidence for unresolved technical facts before a new implementation comparison.
|
|
4
|
-
- Required workers:
|
|
5
|
-
- claude
|
|
6
|
-
- codex
|
|
7
|
-
- report-writer
|
|
8
4
|
{{INCLUDE:_common-contract.md}}
|
|
9
5
|
|
|
10
6
|
## Input and experiment procedure
|
|
@@ -701,7 +701,7 @@ def critic_is_rostered(run_manifest: Mapping[str, Any]) -> bool:
|
|
|
701
701
|
"""이 run 이 critic 슬롯을 실제로 배정했는가.
|
|
702
702
|
|
|
703
703
|
정본은 `invocationAssignments` 다 — run 이 해소한 critic 을 적는 곳이고
|
|
704
|
-
(`okstra_ctl.render.
|
|
704
|
+
(`okstra_ctl.render._critic_role_rows`), `critic/*` 항목이 없으면
|
|
705
705
|
critic 이 없다. `workerAssignments` 로는 판정할 수 없다: critic 은 분석
|
|
706
706
|
워커 로스터에서 제외되므로(`okstra_ctl.run._analysis_worker_rows`)
|
|
707
707
|
rostered 여부와 무관하게 그 배열에 나타나지 않는다.
|