okstra 0.202.0 → 0.204.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 -3
- package/dist/cli-registry.mjs +7 -7
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/lifecycle/install.mjs +50 -124
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/memory/memory.mjs +41 -8
- package/dist/commands/memory/memory.mjs.map +1 -1
- package/dist/lib/install-assets.mjs +3 -0
- package/dist/lib/install-assets.mjs.map +1 -1
- package/dist/lib/runtime-manifest.mjs +2 -1
- package/dist/lib/runtime-manifest.mjs.map +1 -1
- package/dist/lib/types.d.mts +2 -1
- package/docs/architecture/storage-model.md +14 -11
- package/docs/architecture.md +25 -19
- package/docs/cli.md +15 -12
- package/docs/contributor-change-matrix.md +3 -2
- package/docs/performance-improvement-plan-v2.md +2 -3
- package/docs/project-structure-overview.md +35 -9
- package/docs/task-process/README.md +1 -1
- package/docs/task-process/common-flow.md +1 -1
- package/docs/task-process/final-verification.md +3 -1
- package/docs/task-process/implementation.md +1 -1
- package/docs/task-process/release-handoff.md +36 -39
- package/package.json +1 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/common.json +28 -0
- package/runtime/agents/operations/code-review.json +6 -0
- package/runtime/agents/operations/report-translation.json +6 -0
- package/runtime/agents/operations/schedule-verification.json +6 -0
- package/runtime/agents/roles/analyser.json +18 -0
- package/runtime/agents/roles/critic.json +18 -0
- package/runtime/agents/roles/designer.json +18 -0
- package/runtime/agents/roles/implementer.json +20 -0
- package/runtime/agents/roles/leader.json +20 -0
- package/runtime/agents/roles/planner.json +18 -0
- package/runtime/agents/roles/report-writer.json +19 -0
- package/runtime/agents/roles/translator.json +19 -0
- package/runtime/agents/roles/verifier.json +18 -0
- package/runtime/bin/lib/okstra/usage.sh +5 -5
- package/runtime/prompts/duties/acceptance-critic.json +32 -0
- package/runtime/prompts/duties/acceptance-verifier.json +32 -0
- package/runtime/prompts/duties/analysis-worker.json +32 -0
- package/runtime/prompts/duties/code-reviewer.json +32 -0
- package/runtime/prompts/duties/diagnosis-worker.json +32 -0
- package/runtime/prompts/duties/direction-selection-worker.json +32 -0
- package/runtime/prompts/duties/discovery-worker.json +32 -0
- package/runtime/prompts/duties/implementation-executor.json +32 -0
- package/runtime/prompts/duties/implementation-verifier.json +32 -0
- package/runtime/prompts/duties/lead.json +32 -0
- package/runtime/prompts/duties/planning-worker.json +36 -0
- package/runtime/prompts/duties/report-writer.json +32 -0
- package/runtime/prompts/duties/reverification-worker.json +32 -0
- package/runtime/prompts/duties/schedule-verifier.json +32 -0
- package/runtime/prompts/duties/scope-critic.json +32 -0
- package/runtime/prompts/duties/technical-verification-worker.json +32 -0
- package/runtime/prompts/duties/translator.json +32 -0
- package/runtime/prompts/launch.template.md +2 -1
- package/runtime/prompts/lead/adapters/cmux.md +1 -1
- package/runtime/prompts/lead/convergence.md +4 -4
- package/runtime/prompts/lead/okstra-lead-contract.md +113 -4
- package/runtime/prompts/lead/plan-body-verification.md +6 -6
- package/runtime/prompts/lead/report-writer.md +3 -3
- package/runtime/prompts/profiles/_common-contract.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +4 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
- package/runtime/prompts/profiles/change-impact-analysis.json +31 -0
- package/runtime/prompts/profiles/change-impact-analysis.md +0 -20
- package/runtime/prompts/profiles/error-analysis.json +39 -0
- package/runtime/prompts/profiles/error-analysis.md +0 -25
- package/runtime/prompts/profiles/feature-analysis.json +31 -0
- package/runtime/prompts/profiles/feature-analysis.md +0 -20
- package/runtime/prompts/profiles/final-verification.json +30 -0
- package/runtime/prompts/profiles/final-verification.md +3 -22
- package/runtime/prompts/profiles/forbidden-actions.json +4 -3
- package/runtime/prompts/profiles/implementation-option-selection.json +31 -0
- package/runtime/prompts/profiles/implementation-option-selection.md +0 -20
- package/runtime/prompts/profiles/implementation-planning.json +40 -0
- package/runtime/prompts/profiles/implementation-planning.md +4 -29
- package/runtime/prompts/profiles/implementation.json +30 -0
- package/runtime/prompts/profiles/implementation.md +1 -20
- package/runtime/prompts/profiles/improvement-discovery.json +31 -0
- package/runtime/prompts/profiles/improvement-discovery.md +0 -20
- package/runtime/prompts/profiles/project-analysis.json +31 -0
- package/runtime/prompts/profiles/project-analysis.md +0 -20
- package/runtime/prompts/profiles/release-handoff.json +5 -0
- package/runtime/prompts/profiles/release-handoff.md +71 -73
- package/runtime/prompts/profiles/requirements-discovery.json +39 -0
- package/runtime/prompts/profiles/requirements-discovery.md +0 -25
- package/runtime/prompts/profiles/technical-verification.json +39 -0
- package/runtime/prompts/profiles/technical-verification.md +0 -25
- package/runtime/prompts/wizard/prompts.ko.json +12 -17
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +3 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -3
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/worker-session.md +108 -0
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -0
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +8 -1
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +8 -0
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +23 -6
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +6 -2
- package/runtime/python/okstra_ctl/agent/invocation.py +168 -113
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +120 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +107 -2
- package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -49
- package/runtime/python/okstra_ctl/analysis_packet.py +4 -1
- package/runtime/python/okstra_ctl/application/open_worker.py +6 -1
- package/runtime/python/okstra_ctl/assignment_resolver.py +16 -5
- package/runtime/python/okstra_ctl/cmux.py +69 -20
- package/runtime/python/okstra_ctl/code_review_target.py +16 -8
- package/runtime/python/okstra_ctl/conformance.py +43 -0
- package/runtime/python/okstra_ctl/consumers.py +6 -3
- package/runtime/python/okstra_ctl/container.py +31 -8
- package/runtime/python/okstra_ctl/context_cost.py +11 -15
- package/runtime/python/okstra_ctl/contract_refreeze.py +156 -0
- package/runtime/python/okstra_ctl/convergence_provenance.py +7 -1
- package/runtime/python/okstra_ctl/design_prep.py +34 -1
- package/runtime/python/okstra_ctl/dispatch_core.py +53 -27
- package/runtime/python/okstra_ctl/domain/host.py +5 -0
- package/runtime/python/okstra_ctl/domain/worker_runtime.py +10 -0
- package/runtime/python/okstra_ctl/error_report.py +4 -3
- package/runtime/python/okstra_ctl/execution_manifest.py +71 -18
- package/runtime/python/okstra_ctl/handoff.py +167 -277
- package/runtime/python/okstra_ctl/implementation_stage.py +9 -0
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +113 -0
- package/runtime/python/okstra_ctl/lead_progress.py +1 -1
- package/runtime/python/okstra_ctl/legacy_model_selection.py +2 -2
- package/runtime/python/okstra_ctl/manager_cli.py +92 -4
- package/runtime/python/okstra_ctl/manager_launch.py +1 -1
- package/runtime/python/okstra_ctl/manager_paths.py +14 -3
- package/runtime/python/okstra_ctl/manager_store.py +210 -3
- package/runtime/python/okstra_ctl/manager_sync.py +4 -1
- package/runtime/python/okstra_ctl/manager_view.py +2 -1
- package/runtime/python/okstra_ctl/model_discovery.py +30 -0
- package/runtime/python/okstra_ctl/model_io/lines.py +14 -1
- package/runtime/python/okstra_ctl/model_io/renderers.py +4 -3
- package/runtime/python/okstra_ctl/models.py +1 -1
- package/runtime/python/okstra_ctl/next_phase.py +16 -6
- package/runtime/python/okstra_ctl/operation_invocation.py +86 -0
- package/runtime/python/okstra_ctl/option_comparison.py +168 -0
- package/runtime/python/okstra_ctl/path_hints.py +9 -0
- package/runtime/python/okstra_ctl/paths.py +3 -0
- package/runtime/python/okstra_ctl/profile_show.py +42 -1
- package/runtime/python/okstra_ctl/registry/host_discovery.py +20 -12
- package/runtime/python/okstra_ctl/registry/host_registry.py +11 -0
- package/runtime/python/okstra_ctl/render.py +50 -0
- package/runtime/python/okstra_ctl/report_contract.py +1 -1
- package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +21 -3
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +177 -17
- package/runtime/python/okstra_ctl/report_translation.py +2 -1
- package/runtime/python/okstra_ctl/report_translation_dispatch.py +69 -9
- package/runtime/python/okstra_ctl/role_requirements.py +142 -129
- package/runtime/python/okstra_ctl/rollup.py +3 -1
- package/runtime/python/okstra_ctl/run.py +76 -29
- package/runtime/python/okstra_ctl/schedule_semantics.py +17 -6
- package/runtime/python/okstra_ctl/stage_fix_carry.py +23 -4
- package/runtime/python/okstra_ctl/stage_integrate.py +178 -18
- package/runtime/python/okstra_ctl/stage_map.py +16 -2
- package/runtime/python/okstra_ctl/stage_targets.py +209 -43
- package/runtime/python/okstra_ctl/team.py +22 -13
- package/runtime/python/okstra_ctl/time_report.py +2 -1
- package/runtime/python/okstra_ctl/usage_report.py +3 -1
- package/runtime/python/okstra_ctl/wizard/confirmation.py +3 -9
- package/runtime/python/okstra_ctl/wizard/ids.py +1 -1
- package/runtime/python/okstra_ctl/wizard/registry.py +1 -1
- package/runtime/python/okstra_ctl/wizard/state.py +3 -5
- package/runtime/python/okstra_ctl/wizard/steps_plan.py +3 -23
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +5 -1
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +35 -7
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +66 -48
- package/runtime/python/okstra_ctl/workflow.py +1 -1
- package/runtime/python/okstra_ctl/worktree/__init__.py +3 -1
- package/runtime/python/okstra_ctl/worktree/naming.py +9 -0
- package/runtime/python/okstra_ctl/worktree_registry.py +38 -9
- package/runtime/python/okstra_token_usage/pricing.py +6 -4
- package/runtime/schemas/agent-common-v1.schema.json +34 -0
- package/runtime/schemas/agent-duty-v1.schema.json +38 -0
- package/runtime/schemas/agent-operation-v1.schema.json +11 -0
- package/runtime/schemas/agent-profile-v1.schema.json +46 -0
- package/runtime/schemas/agent-role-v1.schema.json +29 -0
- package/runtime/schemas/final-report-v2.0.schema.json +118 -97
- package/runtime/schemas/final-report-v3.0.schema.json +118 -97
- package/runtime/skills/okstra-brief-gen/SKILL.md +84 -4
- package/runtime/skills/okstra-chat/SKILL.md +2 -2
- package/runtime/skills/okstra-code-review/SKILL.md +23 -9
- package/runtime/skills/okstra-container-build/SKILL.md +10 -10
- package/runtime/skills/okstra-inspect/SKILL.md +1 -1
- package/runtime/skills/okstra-inspect/facets/cost.md +1 -1
- package/runtime/skills/okstra-inspect/facets/error-zip.md +9 -9
- package/runtime/skills/okstra-inspect/facets/errors.md +16 -16
- package/runtime/skills/okstra-inspect/facets/logs.md +7 -7
- package/runtime/skills/okstra-inspect/facets/recap.md +2 -2
- package/runtime/skills/okstra-inspect/facets/report.md +1 -1
- package/runtime/skills/okstra-inspect/facets/status.md +4 -3
- package/runtime/skills/okstra-inspect/facets/time.md +11 -10
- package/runtime/skills/okstra-manager/SKILL.md +18 -2
- package/runtime/skills/okstra-pr-gen/SKILL.md +6 -5
- package/runtime/skills/okstra-rollup/SKILL.md +5 -5
- package/runtime/skills/okstra-run/SKILL.md +31 -12
- package/runtime/skills/okstra-schedule-gen/SKILL.md +19 -14
- package/runtime/skills/okstra-setup/SKILL.md +12 -10
- package/runtime/skills/okstra-setup/references/project-config.md +7 -6
- package/runtime/skills/okstra-usage/SKILL.md +1 -1
- package/runtime/skills/okstra-user-response/SKILL.md +1 -1
- package/runtime/templates/manager/view.template.html +1 -0
- package/runtime/templates/report-writer-prompt-preamble.md +8 -0
- package/runtime/templates/reports/brief.template.md +14 -4
- package/runtime/templates/reports/html/i18n/en.json +5 -4
- package/runtime/templates/reports/html/i18n/ko.json +5 -4
- package/runtime/templates/reports/html/tasks/release-handoff.template.html +8 -5
- package/runtime/templates/reports/i18n/en.json +1 -1
- package/runtime/templates/reports/md/tasks/release-handoff.template.md +1 -1
- package/runtime/templates/reports/release-handoff-input.template.md +6 -4
- package/runtime/templates/translator-prompt-preamble.md +36 -0
- package/runtime/validators/checks/validate-assets-01.py +7 -8
- package/runtime/validators/validate-brief.py +70 -0
- package/runtime/validators/validate-implementation-plan-stages.py +2 -1
- package/runtime/validators/validate-run.py +59 -9
- package/runtime/validators/validate-schedule.py +9 -0
- package/docs/for-ai/README.md +0 -68
- package/docs/for-ai/skills/okstra-brief-gen.md +0 -262
- package/docs/for-ai/skills/okstra-chat.md +0 -34
- package/docs/for-ai/skills/okstra-code-review.md +0 -57
- package/docs/for-ai/skills/okstra-container-build.md +0 -129
- package/docs/for-ai/skills/okstra-inspect.md +0 -262
- package/docs/for-ai/skills/okstra-manager.md +0 -86
- package/docs/for-ai/skills/okstra-memory.md +0 -126
- package/docs/for-ai/skills/okstra-pr-gen.md +0 -49
- package/docs/for-ai/skills/okstra-rollup.md +0 -114
- package/docs/for-ai/skills/okstra-run.md +0 -250
- package/docs/for-ai/skills/okstra-schedule-gen.md +0 -240
- package/docs/for-ai/skills/okstra-setup.md +0 -167
- package/docs/for-ai/skills/okstra-usage.md +0 -29
- package/docs/for-ai/skills/okstra-user-response.md +0 -72
- package/runtime/agents/workers/claude-worker.md +0 -128
- package/runtime/agents/workers/report-writer-worker.md +0 -37
- package/runtime/agents/workers/translator-worker.md +0 -63
- package/runtime/prompts/duties/acceptance-critic.md +0 -44
- package/runtime/prompts/duties/acceptance-verifier.md +0 -44
- package/runtime/prompts/duties/analysis-worker.md +0 -44
- package/runtime/prompts/duties/code-reviewer.md +0 -44
- package/runtime/prompts/duties/common.md +0 -39
- package/runtime/prompts/duties/diagnosis-worker.md +0 -44
- package/runtime/prompts/duties/direction-selection-worker.md +0 -44
- package/runtime/prompts/duties/discovery-worker.md +0 -44
- package/runtime/prompts/duties/implementation-executor.md +0 -44
- package/runtime/prompts/duties/implementation-verifier.md +0 -44
- package/runtime/prompts/duties/lead.md +0 -44
- package/runtime/prompts/duties/planning-worker.md +0 -52
- package/runtime/prompts/duties/report-writer.md +0 -44
- package/runtime/prompts/duties/reverification-worker.md +0 -44
- package/runtime/prompts/duties/schedule-verifier.md +0 -44
- package/runtime/prompts/duties/scope-critic.md +0 -44
- package/runtime/prompts/duties/technical-verification-worker.md +0 -44
- package/runtime/prompts/duties/translator.md +0 -44
- package/runtime/python/okstra_ctl/pane_title.py +0 -154
|
@@ -24,7 +24,7 @@ Report assembly reads the role-owned inputs, validates them, derives links and s
|
|
|
24
24
|
|
|
25
25
|
An active clarification exists only in `activeClarifications[]`. A decision carried from a previous run exists only in `carriedDecisions[]`; do not recreate it as an active question.
|
|
26
26
|
|
|
27
|
-
Prepare seeds `carriedDecisions[]` when it creates the ledger: every clarification the run's carry-in record answered or resolved, plus every row that record's user-responses sidecars answered, arrives carried (`scripts/okstra_ctl/approval_decisions.py` `seed_carried_decisions`). The carry-in record is the `--clarification-response` file; for a new plan it is the option-selection record `--selected-direction` names, and for an implementation run the approved plan `--approved-plan` names (`render._carry_in_source`) — the same pointer assembly writes to `clarificationCarryIn.sourceFile`, so the page links those ids to the prior run's page. A carried plan row's `requirementCoverage[].decisionRefs` may still name a `C-NNN` the carry-in record does not answer — a decision from an older run. Carry it before assembly: `okstra approval-decision carry --ledger <approvalDecisionsPath> --from-responses <
|
|
27
|
+
Prepare seeds `carriedDecisions[]` when it creates the ledger: every clarification the run's carry-in record answered or resolved, plus every row that record's user-responses sidecars answered, arrives carried (`scripts/okstra_ctl/approval_decisions.py` `seed_carried_decisions`). The carry-in record is the `--clarification-response` file; for a new plan it is the option-selection record `--selected-direction` names, and for an implementation run the approved plan `--approved-plan` names (`render._carry_in_source`) — the same pointer assembly writes to `clarificationCarryIn.sourceFile`, so the page links those ids to the prior run's page. A carried plan row's `requirementCoverage[].decisionRefs` may still name a `C-NNN` the carry-in record does not answer — a decision from an older run. Carry it before assembly: `okstra approval-decision carry --ledger <approvalDecisionsPath> --from-responses <launch prompt "Clarification Response Carried In" → Source path> --clarification-id C-NNN` — repeat `--clarification-id` to take several in one call. That bundle is the source of truth for an earlier run's answer: it is task-level and cumulative, so no prior run seq has to be located, and each response section names the report that posed the question, which is where the row's `statement`, `expectedForm`, and options come from. A carried row lands as `answered`, not `resolved` — it was resolved in another run, and `resolution.checkRefs` names *this* run's activity rows. Carrying an answer also obliges a `supersessionLedger` entry for it.
|
|
28
28
|
|
|
29
29
|
Each decision option has `role`, `answer`, `rationale`, `disposition`, `reach`, optional `scopeEffects`, `addedWork`, and `directionChange`. `reach` is exactly one of `in-repo` or `cross-repo`. `scopeEffects` may contain `new-schema` and `deferrable`. A `correctness-critical` option cannot use `select` or `accept-risk`; a `noncritical-dissent` option cannot use `select`.
|
|
30
30
|
|
|
@@ -58,7 +58,7 @@ This is enforced by
|
|
|
58
58
|
`report_synthesis_packet.build_report_synthesis_packet()`, and
|
|
59
59
|
`report_assembly.assemble_report()`.
|
|
60
60
|
|
|
61
|
-
Materialize the duty prompt with `okstra agent-prompt materialize --audience report-writer
|
|
61
|
+
Materialize the duty prompt with `okstra agent-prompt materialize --audience report-writer ...`. `--assignment-ref` is `initial/report-writer` — the run manifest declares the report writer under the `initial` phase, so `report-writer/report-writer` is refused. `--result` is the narrative path the run manifest's `reportNarrativePath` names (report contract 3.0; the `expectedReportRecordPath` data.json under 2.0) and `--audit-source` is the roster's worker result (`team-state` `workers[].resultPath` for `report-writer`). The materializer refuses any other value: report assembly reads the narrative from the manifest path and nowhere else, and `okstra team await` records the roster row completed only when the roster's file exists. A corrective dispatch (fix, self-fix, verdict, citations, supersession) reuses both paths and changes only the prompt path and the invocation ID. **Enforced:** `_validate_report_writer_paths` in `scripts/okstra_ctl/agent/prompt_cli/materialize.py`. The materializer also writes the report synthesis packet next to the narrative and puts `- Report synthesis packet: <path>` as the first line of the prompt's `## Inputs` section — opening the section when the instruction has none, or inserting under the instruction's own `## Inputs` heading when it has one. The instruction therefore does not enumerate raw source paths; a missing or unreadable packet source is refused before dispatch with its owner (`report synthesis packet contract defects`). **Enforced:** `_report_writer_input_lines` in `scripts/okstra_ctl/agent/prompt_cli/materialize.py`. The prompt starts with these anchors in order:
|
|
62
62
|
|
|
63
63
|
1. `**Project Root:**`
|
|
64
64
|
2. `**Prompt History Path:**`
|
|
@@ -147,7 +147,7 @@ When the result carries `recovery.mode: same-run`, continue the authorized work
|
|
|
147
147
|
|
|
148
148
|
### The translation sidecar: the `translate` step
|
|
149
149
|
|
|
150
|
-
`report-finalize` dispatches the translator itself. Its `translate` step runs directly before `render-views` (which overlays the sidecar), and it is a no-op when `reportLanguage` is `en` or the `*.i18n.<lang>.json` sidecar already exists. When the sidecar is missing, the step reuses this run's undispatched translator reservation if the lead already materialized one, otherwise it materializes the prompt itself — instruction file `state/translator-instructions-<task-type>-<seq>.md` (kept when the lead wrote one), prompt `prompts/translator-worker-prompt-<task-type>-<seq>.md`, `--result worker-results/translator-translations-<task-type>-<seq>.md`, `--audit-source worker-results/translator-worker-<task-type>-<seq>.md`, invocation id `<task-type>-<seq>-translator` (`-r2`, `-r3` after a failed attempt) — then
|
|
150
|
+
`report-finalize` dispatches the translator itself. Its `translate` step runs directly before `render-views` (which overlays the sidecar), and it is a no-op when `reportLanguage` is `en` or the `*.i18n.<lang>.json` sidecar already exists. When the sidecar is missing, the step reuses this run's undispatched translator reservation if the lead already materialized one, otherwise it materializes the prompt itself — instruction file `state/translator-instructions-<task-type>-<seq>.md` (kept when the lead wrote one), prompt `prompts/translator-worker-prompt-<task-type>-<seq>.md`, `--result worker-results/translator-translations-<task-type>-<seq>.md`, `--audit-source worker-results/translator-worker-<task-type>-<seq>.md`, invocation id `<task-type>-<seq>-translator` (`-r2`, `-r3` after a failed attempt) — then dispatches the worker and waits for it: on a `terminalBackend: cmux-pane` run into a cmux pane like every other worker (the same code as `okstra team dispatch` followed by `okstra team await`; run-end `okstra team teardown` closes that pane), otherwise through the CLI-wrapper dispatcher. Either path records the dispatch and links the result. Do not run `agent-prompt materialize --audience translator` or `worker-dispatch --workers translator` by hand before `report-finalize`; the sequence used to be a manual lead step and was skipped in practice (2026-09-09, fontsninja-v3-site dev-10628-3: a `ko` run finalized in one call, zero translator reservations, English HTML). **Enforced:** `okstra_ctl.report_finalize.V3_STEP_ORDER` places the step; `okstra_ctl.report_translation_dispatch.translate_report` owns it; `_translator_job_from_reservation` in `scripts/okstra_ctl/dispatch_core.py` still refuses two undispatched reservations for one run, which only a hand-made second reservation produces.
|
|
151
151
|
|
|
152
152
|
The step succeeds only when the sidecar exists afterwards; a translator that exits 0 without publishing it fails the step. A failed `translate` does not stop the sequence: `render-views` still writes the view from the English body, `validate-run` records the missing sidecar as an advisory, and the result's resume hint starts at `--only translate --only render-views …` — run that once the cause (a host approval gate, an unavailable provider) is cleared rather than closing the run on an English view.
|
|
153
153
|
|
|
@@ -5,7 +5,7 @@ Edit here once; every profile picks the change up at next render. Do NOT
|
|
|
5
5
|
add phase-specific rules to this file — phase rules stay in the per-
|
|
6
6
|
profile document.
|
|
7
7
|
-->
|
|
8
|
-
- Team contract (shared): roster roles, model-assignment rules, dispatch invariants, and required-worker attempt rules are canonical in the team contract (`prompts/lead/team-contract.md`). Two consequences every phase honours: the host-native Okstra lead is synthesis-only (in `implementation`, distinct from the `Executor` and verifiers), and unnamed generic parallel workers never replace or extend the per-profile `Required workers:` roster. Prep-time model recommendations come from the catalog defaults in `okstra_ctl.models` (for example, `Codex worker` → `gpt-
|
|
8
|
+
- Team contract (shared): roster roles, model-assignment rules, dispatch invariants, and required-worker attempt rules are canonical in the team contract (`prompts/lead/team-contract.md`). Two consequences every phase honours: the host-native Okstra lead is synthesis-only (in `implementation`, distinct from the `Executor` and verifiers), and unnamed generic parallel workers never replace or extend the per-profile `Required workers:` roster. Prep-time model recommendations come from the catalog defaults in `okstra_ctl.models` (for example, `Codex worker` → `gpt-6-sol`); at dispatch time the task-manifest's materialized assignment is the only source — there is no dispatch-time fallback.
|
|
9
9
|
- Worker interaction model (shared — read before inferring behaviour from the roster):
|
|
10
10
|
- 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.
|
|
11
11
|
- **Phase 4 / 5 (independent analysis)**: every analyser in the resolved provider assignment roster produces findings independently and has no access to another worker's output. `report-writer` does not analyse.
|
|
@@ -86,7 +86,7 @@ profile document.
|
|
|
86
86
|
- **One decision per row.** A `decision` row asks one question. When a single option bundles two independent decisions, split the row. The tell is usually the option's `reach`: an option that is `cross-repo` only because one bundled clause crosses a repository boundary contains two decisions of different cost. The §5.5.9 adversarial round judges this semantic rule.
|
|
87
87
|
- each row's `Blocks` column picks one of `{approval, next-phase, none}`. `approval` is reserved for items that gate an approval action, especially the `implementation-planning` `approved:` frontmatter flip; outside `implementation-planning`, unresolved brief reporter-confirmation rows use `next-phase` instead. `next-phase` blocks the next run from starting cleanly. `none` is informational/audit-only.
|
|
88
88
|
- write every entry in full, descriptive sentences that a non-developer can act on without further context. Avoid abbreviations and internal jargon. The `Statement` cell must state *what* is needed, *why* the answer / attachment changes the next step, and (for `material`) *where* the user can find it and *where* to place it. The `Expected form` cell must state the answer shape (yes/no, one of the options, number/date, file path, short description, etc.); supply concrete option choices when applicable.
|
|
89
|
-
- **Record coordinates only.** A clarification `statement`, `expectedForm`, or `options[]` answer/rationale may cite a report-record row id (`RB-002`, `C-014`) or a `path:line`. Do not cite a section number (`§4.7`, `§1`). That number exists only on one full reading copy. **Guideline — the cost is a worse question, not a failed run.** `scripts/okstra_ctl/user_response.py` `resolve_refs_from_record` resolves a row id against the report record and returns `null` for a `§` number, so the `okstra user-response` picker shows the user a bare `§4.7` with no context snippet next to the question it is supposed to explain. Nothing rejects the row.
|
|
89
|
+
- **Record coordinates only.** A clarification `statement`, `expectedForm`, or `options[]` answer/rationale may cite a report-record row id (`RB-002`, `C-014`) or a `path:line`. Do not cite a section number (`§4.7`, `§1`). That number exists only on one full reading copy. **Guideline — the cost is a worse question, not a failed run.** `scripts/okstra_ctl/user_response.py` `resolve_refs_from_record` resolves a row id against the report record and returns `null` for a `§` number, so the `okstra user-response` picker shows the user a bare `§4.7` with no context snippet next to the question it is supposed to explain. Nothing rejects the row. A row id the picker *can* resolve still reaches the user as an id: the `statement` says in one clause what the cited row requires before the question leans on it — see the lifecycle core contract "Asking the user" rule 4.
|
|
90
90
|
- **Schema-v2 authors do not use the string grammar below.** A v2 `Kind=decision` row carries its choices in `options[]` (see the Clarification recommendation fragment for the field list); the renderer and the `okstra user-response` picker both build their selectable options from that array, so a choice that exists only in prose is a choice the user cannot pick. The rest of this bullet governs schema-v1 tables and analysis-worker result tables, which have only string cells.
|
|
91
91
|
- if a schema-v1 table or an analysis-worker result table requires a recommended answer, alternatives, or an evidence-check note, encode it inside the existing 4-column schema: put evidence notes in `Statement` as `Evidence checked: <path:line>` or `Evidence checked: none — <human-only reason>`, and put recommendations/options in `Expected form` as `Recommended: (a) <answer> — <rationale>; Alternatives: (b) <option> (c) <option>`. The recommended answer is always the first option and MUST carry the `(a)` label; alternatives continue the same letter sequence from `(b)` (a lone alternative is `(b) <option>`, never restart at `(a)`), so the full option set reads `(a) (b) (c) …` in order and renders each as its own selectable option. Do **not** append a pick-one answer-space summary such as `(pick 1 of A / B)` or `(pick N of …)` to `<options>` — the rendered `<select>` already enforces single choice, and that annotation leaks verbatim into an option label. Do not add `Recommended`, `Evidence`, `Alternatives`, or `evidence-checked` columns, and do not break the merged record-meta cell back into separate columns.
|
|
92
92
|
- For schema v2, data.json is canonical and the HTML exports answers to a user-response sidecar; the source report is never edited. `--resume-clarification` carries those answers into the next run. The lower-level `--clarification-response <path>` remains available for scripted runs.
|
|
@@ -33,6 +33,9 @@ reaches it. Enforcement: `_required_resource_path_candidates` names the three
|
|
|
33
33
|
bodies for the `implementation-executor` audience, so composing the prompt is
|
|
34
34
|
what puts them there — there is no separate dispatch-time heading check, and a
|
|
35
35
|
missing heading means the composer did not run, not that a worker dropped it.
|
|
36
|
+
Both publishers compose it: the dispatch-time composer for a prompt that does not
|
|
37
|
+
exist yet, and `okstra agent-prompt materialize` for a prompt the lead publishes
|
|
38
|
+
first (`required_resource_block`), because dispatch reuses an existing prompt as is.
|
|
36
39
|
The `<SENTINEL_PREFIX>_PREFLIGHT_MISSING` /
|
|
37
40
|
`<SENTINEL_PREFIX>_POSTWRITE_GATE_MISSING` sentinels were the CLI-wrapper
|
|
38
41
|
template's check; that template is gone.
|
|
@@ -46,7 +49,7 @@ template's check; that template is gone.
|
|
|
46
49
|
- **DB / IO / SQL changes require real execution — mock-only is NOT validation evidence:** when this run's diff touches DB/IO/SQL (ORM / query-builder code — sequelize / typeorm / prisma / knex / raw SQL — `*.repository.*`, model/entity files, `migrations/**`, `*.sql`, or any changed query string), a mocked unit test cannot observe the SQL the query builder actually emits (observed failure class: `_implementation-verifier.md` §"DB / IO / SQL change — real-execution gate"). The executor MUST run the change against a real (or faithful-replica) datastore — the `db-test` validation step (plan `validation` db step, else `project.json.qaCommands.db-test`), targeting a **local / replica** DB — and cite its exact command + exit code in the final report's `Validation evidence`. If no real DB / `db-test` command is reachable, do NOT claim the change verified: label the DB portion `static-analysis only …, unverified (not executed)` in the report, surface it in the routing recommendation, and never downplay the real run as "too heavy". `git push` stays forbidden (universal list); the unverified DB state is carried forward so `final-verification` cannot accept it and `release-handoff` cannot push.
|
|
47
50
|
- **External-source adapters — structure AND fixture both derive from a captured real sample; a self-authored fixture is NOT reality evidence:** when this run's diff builds or changes an `external-interface` or `transformation-mapping` surface (an HTTP / network client, or a parser / mapper of a third-party payload — HTML / JSON / XML / CSV originating outside this repo), the adapter's structural assumptions (selectors, field paths, expected response shape) AND the static fixture / golden that tests them MUST BOTH derive from a **captured real sample** of that payload — the capture cited in the stage's `external-interface` / `transformation-mapping` design-prep item, or one captured this run and recorded with its `source` + capture time. The captured sample is a static fixture (no live socket), so a parser test against it stays in source like any unit test — the Real-IO isolation rule below governs *live* calls, not the captured bytes. Do NOT hand-invent the shape and then hand-write a fixture that agrees with it: the passing test then only proves the code matches your assumption, never that the assumption matches reality (self-confirming oracle — the observed failure was a parser whose selectors existed in its synthetic fixture and in zero real pages: hundreds of green units over a fiction, and the whole structure built on the wrong shape). When no real sample is reachable (no network this run, or the brief supplied none), do NOT synthesize a stand-in and present its green tests as correctness: mark the adapter's shape `reality-unverified (no captured sample)` in `Validation evidence`, keep any placeholder fixture explicitly labelled an assumption (never validation evidence), and surface an explicit **user-owned** item in the routing recommendation to confirm against real data. Unlike the DB gate above this does NOT itself block acceptance — live external verification stays a user-owned item per `final-verification`'s External QA advisory policy — but a synthetic external fixture presented as reality-verified is exactly the mock-only external evidence the `final-verification` test-correctness pass is meant to reject.
|
|
48
51
|
- **Real-IO test isolation (BLOCKING).** A test that exercises a **real** datastore, HTTP endpoint, external service, message queue, or filesystem — a live DB connection / DSN, a real `fetch` / `axios` / `http` request, an actual S3 / queue client, anything the project's normal CI test suite cannot run because that backend is absent — MUST be written under the task's qa scripts directory `<task_root>/qa/scripts/` (`<TASK_QA_PATH>/scripts`; the `qa/` root itself holds only data sidecars — the Tier 3 conformance manifest and `result-*.json`). It MUST NOT be written into the project source test tree — `src/**`, `test/**`, `tests/**`, `**/__test__/**`, `**/__tests__/**`, `*.spec.*`, `*.test.*`, or anywhere the project's lint/test globs collect. Two reasons: (a) the project's CI / normal suite has no real DB or network, so a real-IO test placed in source silently breaks the pipeline; (b) it is an okstra verification artifact, and the artifact-home rule confines okstra outputs to `.okstra/`. **The dividing line is the IO, not the intent:** a unit test that stubs/spies only *injected collaborators* (mock — no real socket, no real DB handle) is a TDD red-green artifact and stays in source; the moment a test opens a real connection or makes a real network call it belongs in qa. A stage's real-IO requirement check is a Tier 3 conformance script under `<task_root>/qa/scripts/` (declared via the implementation-planning conformance entry) — never smuggle real IO into a `*.spec.*` in source to make it run "as a unit test". The `db-test` real-execution gate above is satisfied by the conformance/db-test path against the replica, NOT by adding a live-DB `*.spec.*` to the project suite. **Author qa specs with the project's own test framework — never hand-roll `describe`/`it`/`expect`.** When the project ships a test runner as a devDependency (jest / vitest / pytest …), the qa spec uses it, invoked with the project config plus a discovery override pointing at the qa scripts dir (jest: `npx jest --config <project jest config> --roots <task_root>/qa/scripts --runInBand <spec-name>`) — the project config keeps module aliases resolving while the default sweep never collects the file; never widen the project's own test config to include qa paths. For TypeScript qa specs also write `<task_root>/qa/scripts/tsconfig.json` (`extends` the project tsconfig, adds the runner's `types` entry, `"include": ["**/*.ts"]`) so editors resolve path aliases and test globals — it is a qa artifact like the rest (untracked). **These qa artifacts stay untracked — never commit them.** `.okstra/**` is gitignored (the artifact-home rule); conformance scripts and their results are *executed* and recorded in the carry sidecar / verifier result, never written into git history. A committed `.okstra/qa` file is a stage-branch defect that leaks okstra internals into the eventual PR (see the `git add` rules below).
|
|
49
|
-
- **Stage conformance script (BLOCKING when the approved plan declared `Conformance tests:`).** Planning only declared the path and `requires`. This run MUST write the script to that path under `<task_root>/qa/scripts/` and add the matching `<task_root>/qa/conformance-manifest.json` entry: `stageKey` (= `<task-id>-stage-<N>`), `script`, `runCommand`, `requirementIds`, `requires` (the set the plan declared), `passContract`, `exemption: null`, `waiver: null`. Do not skip this when the plan declared tests. If the plan declared `Conformance exemption:`, do not invent a script — with one exception: when this stage's diff touches a db/io/http/external surface the exemption promised it would not (the verifier's diff-surface cross-check names the surface), write the script and the manifest entry for this stage exactly as for a declared stage, with `requires` covering those surfaces. The approved plan is not rewritten; `validate-run.py` `_declared_conformance_errors` accepts an entry for a stage the plan exempted and still rejects one for a stage the plan does not have. The script's standard interface: a `main` that exits `0`=PASS / non-zero=FAIL, and whose stdout ends with `QA-RESULT: PASS|FAIL` followed by one `REQ <id>: PASS|FAIL: <reason>` line per requirement. The verifier runs `runCommand` from the **worktree cwd**, and that cwd is the tree under test. `runCommand` MUST NOT repoint it: a leading `cd <checkout> &&` sends the script at a tree without this stage's changes. Absolute paths are fine and usually necessary — the script and its `tsconfig` live under `<task_root>/qa/scripts/`, i.e. under `.okstra/`, and a worktree does not carry `.okstra/`. Point at those by absolute path; leave the cwd alone. **Enforced:** `scripts/okstra_ctl/conformance.py` `_check_entry` rejects a `runCommand` whose first word in any `&&` / `;` segment changes directory; `validators/validate-run.py` `_validate_conformance` fails the run if the inherited declaration has no script file.
|
|
52
|
+
- **Stage conformance script (BLOCKING when the approved plan declared `Conformance tests:`).** Planning only declared the path and `requires`. This run MUST write the script to that path under `<task_root>/qa/scripts/` and add the matching `<task_root>/qa/conformance-manifest.json` entry: `stageKey` (= `<task-id>-stage-<N>`), `script`, `runCommand`, `requirementIds`, `requires` (the set the plan declared, widened by any db/io/http/external surface this stage's diff touches that the plan left out — never narrowed; `validate-run.py` `_declared_conformance_errors` accepts a superset and rejects a subset), `passContract`, `exemption: null`, `waiver: null`. Do not skip this when the plan declared tests. If the plan declared `Conformance exemption:`, do not invent a script — with one exception: when this stage's diff touches a db/io/http/external surface the exemption promised it would not (the verifier's diff-surface cross-check names the surface), write the script and the manifest entry for this stage exactly as for a declared stage, with `requires` covering those surfaces. The approved plan is not rewritten; `validate-run.py` `_declared_conformance_errors` accepts an entry for a stage the plan exempted and still rejects one for a stage the plan does not have. The script's standard interface: a `main` that exits `0`=PASS / non-zero=FAIL, and whose stdout ends with `QA-RESULT: PASS|FAIL` followed by one `REQ <id>: PASS|FAIL: <reason>` line per requirement. The verifier runs `runCommand` from the **worktree cwd**, and that cwd is the tree under test. `runCommand` MUST NOT repoint it: a leading `cd <checkout> &&` sends the script at a tree without this stage's changes. Absolute paths are fine and usually necessary — the script and its `tsconfig` live under `<task_root>/qa/scripts/`, i.e. under `.okstra/`, and a worktree does not carry `.okstra/`. Point at those by absolute path; leave the cwd alone. **Enforced:** `scripts/okstra_ctl/conformance.py` `_check_entry` rejects a `runCommand` whose first word in any `&&` / `;` segment changes directory; `validators/validate-run.py` `_validate_conformance` fails the run if the inherited declaration has no script file.
|
|
50
53
|
- read the approved plan at this prompt's `**Approved plan:**` anchor end-to-end and parse the `## 5.5 Stage Map`. Read this prompt's `**Stage for this implementation run:**` anchor: the single stage number this run owns. The runtime already selected and reserved this stage (one run = one stage) — do NOT recompute the start stage from `consumers.jsonl`. Both anchors are generated headers; when either is missing, stop and report `contract-violated` rather than inferring the value.
|
|
51
54
|
- load every `runs/<plan-key>/carry/stage-<i>.json` for `i ∈ depends-on(this stage)` and inject them into the executor's working context as "runtime carry-in". For a `depends-on (none)` stage, no sidecar load — task-brief only.
|
|
52
55
|
- this stage's `depends-on` are all already `status:done`. Its file list, step order, Stage Validation commands, Stage Exit Contract, and rollback path are the authoritative scope.
|
|
@@ -9,7 +9,7 @@ at Phase 5, BEFORE constructing the verifier worker dispatch prompts.
|
|
|
9
9
|
|
|
10
10
|
- Every verdict comes from a fresh session with no shared context, never from the 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.
|
|
11
11
|
- Session isolation is the primary self-review safeguard: each verifier is a separate invocation with its own context window. Reusing the executor's model is acceptable. The model comes from the run's stored assignment.
|
|
12
|
-
- Verifiers read from the SAME working tree path the Executor used so they observe the exact diff the Executor produced. Source files, lockfiles, Git state, and shared links remain read-only. Declared verification commands may create their normal worktree-local build/cache outputs and install dependencies
|
|
12
|
+
- Verifiers read from the SAME working tree path the Executor used so they observe the exact diff the Executor produced. Source files, lockfiles, Git state, and shared links remain read-only. Declared verification commands may create their normal worktree-local build/cache outputs. **Do not re-run a dependency install** (`npm ci`, `yarn install --frozen-lockfile`, `pnpm install --frozen-lockfile`, and the like — typically the plan's `phase: pre` dependency-precondition row): the executor already installed into this worktree, and the other verifiers of this stage run at the same time against the same `node_modules`, so concurrent installs break each other and report exit codes that say nothing about the code (measured 2026-09-22, jobs dev-10860 stage 1: verifiers dispatched within 4 seconds, `EEXIST` on a workspace symlink in 2 of 3 reruns). Record such a row in `independentValidationRerun` as `not re-run — dependency install precondition, executor exit <code>`; it is outside the Discrepancy rule below. If the installed dependencies are actually missing or broken, the checks that need them fail, and that failure is what you report. This is a guideline: nothing parses the command log for installs. This is the bounded exception to the preceding write restriction; it does not permit source repairs, moving shared links, or redirecting build outputs outside the worktree. Run-owned logs remain in the run artifact directories.
|
|
13
13
|
|
|
14
14
|
**Enforced:** `_validate_verifier_command_log_is_read_only` in `validators/validate-run.py` scans every `verifierResults[].readOnlyCommandLog` for source-mutating commands (`sed -i`, `git checkout --`/`restore`/`reset --hard`/`stash`/`clean`/`apply`, `patch -p`, `rm -rf`, `truncate`). Read-only forms (`git stash list`, `git clean --dry-run`, `git apply --check`) pass.
|
|
15
15
|
|
|
@@ -150,7 +150,7 @@ The runtime AND the verifier MUST reject any `cmd` containing tokens that imply
|
|
|
150
150
|
|
|
151
151
|
### Discrepancy rule
|
|
152
152
|
|
|
153
|
-
Tier 3 external-advisory discrepancies are excluded from this promotion: preserve the executor/verifier divergence in the advisory evidence and user-owned follow-up without changing the verdict. For Tier 1, Tier 2, and blocking `io`-only Tier 3, if the verifier's re-run result differs from what the executor reported (a passing test fails on re-run, a clean lint surfaces warnings, an exit code mismatches), the verifier MUST issue verdict `FAIL` with the divergence cited. The Okstra lead has no synthesis-time override for that FAIL. It MUST NOT prefer the executor's evidence over a verifier's reproduced result, with or without a cited reason: `_validate_verifier_fail_blocks_verdict` fails any report that publishes a passing `finalVerdict.verdictToken` while a `verifierResults[]` row records `FAIL`, and it reads only that row — no rationale field reaches it. A divergence the lead believes is not the code's (a flaky test, a documented environment delta) is resolved where the verdict is written, not after it: it is carried into the next fix run, where the verifier re-checks the finding and cites it `resolved`. Recording the reason in the report without changing the verdict row is what the routing recommendation and the user-owned follow-up are for.
|
|
153
|
+
Tier 3 external-advisory discrepancies are excluded from this promotion: preserve the executor/verifier divergence in the advisory evidence and user-owned follow-up without changing the verdict. A dependency-install row is not re-run (see the worktree rule above), so it never yields a discrepancy. For Tier 1, Tier 2, and blocking `io`-only Tier 3, if the verifier's re-run result differs from what the executor reported (a passing test fails on re-run, a clean lint surfaces warnings, an exit code mismatches), the verifier MUST issue verdict `FAIL` with the divergence cited. The Okstra lead has no synthesis-time override for that FAIL. It MUST NOT prefer the executor's evidence over a verifier's reproduced result, with or without a cited reason: `_validate_verifier_fail_blocks_verdict` fails any report that publishes a passing `finalVerdict.verdictToken` while a `verifierResults[]` row records `FAIL`, and it reads only that row — no rationale field reaches it. A divergence the lead believes is not the code's (a flaky test, a documented environment delta) is resolved where the verdict is written, not after it: it is carried into the next fix run, where the verifier re-checks the finding and cites it `resolved`. Recording the reason in the report without changing the verdict row is what the routing recommendation and the user-owned follow-up are for.
|
|
154
154
|
|
|
155
155
|
**When the re-run matched, leave `discrepancy` empty and omit the `Discrepancy` line.** The field records a divergence, so an empty field *is* the record of "no divergence" — the schema makes it optional for exactly that. Do not write `None`, `n/a`, or a sentence explaining that nothing diverged: the check reads any non-empty text as a recorded divergence, so a verifier that states its clean result in prose is failed for the result it is reporting.
|
|
156
156
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"id": "change-impact-analysis",
|
|
4
|
+
"roles": [
|
|
5
|
+
{
|
|
6
|
+
"mode": "static",
|
|
7
|
+
"roleId": "analyser",
|
|
8
|
+
"dutyId": "analysis-worker",
|
|
9
|
+
"min": 2,
|
|
10
|
+
"recommended": 3,
|
|
11
|
+
"max": 5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"mode": "static",
|
|
15
|
+
"roleId": "report-writer",
|
|
16
|
+
"dutyId": "report-writer",
|
|
17
|
+
"min": 1,
|
|
18
|
+
"recommended": 1,
|
|
19
|
+
"max": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"mode": "dynamic",
|
|
23
|
+
"roleId": "verifier",
|
|
24
|
+
"dutyId": "reverification-worker",
|
|
25
|
+
"sourceRoleIds": [
|
|
26
|
+
"analyser"
|
|
27
|
+
],
|
|
28
|
+
"activation": "per-selected-source"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
# Change Impact Analysis Profile
|
|
2
2
|
|
|
3
|
-
```yaml
|
|
4
|
-
roles:
|
|
5
|
-
- role: analyser
|
|
6
|
-
min: 2
|
|
7
|
-
recommended: 3
|
|
8
|
-
max: 5
|
|
9
|
-
duty: analysis-worker
|
|
10
|
-
- role: report-writer
|
|
11
|
-
min: 1
|
|
12
|
-
recommended: 1
|
|
13
|
-
max: 1
|
|
14
|
-
duty: report-writer
|
|
15
|
-
- role: verifier
|
|
16
|
-
min: 0
|
|
17
|
-
recommended: 0
|
|
18
|
-
max: 0
|
|
19
|
-
duty: reverification-worker
|
|
20
|
-
dynamic: true
|
|
21
|
-
```
|
|
22
|
-
|
|
23
3
|
- Purpose: assess the read-only impact of a proposed change, including preserved behavior, affected dependencies, and constraints that a later planning phase must resolve
|
|
24
4
|
- Required workers:
|
|
25
5
|
- claude
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"id": "error-analysis",
|
|
4
|
+
"roles": [
|
|
5
|
+
{
|
|
6
|
+
"mode": "static",
|
|
7
|
+
"roleId": "analyser",
|
|
8
|
+
"dutyId": "diagnosis-worker",
|
|
9
|
+
"min": 2,
|
|
10
|
+
"recommended": 3,
|
|
11
|
+
"max": 5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"mode": "static",
|
|
15
|
+
"roleId": "critic",
|
|
16
|
+
"dutyId": "scope-critic",
|
|
17
|
+
"min": 0,
|
|
18
|
+
"recommended": 1,
|
|
19
|
+
"max": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"mode": "static",
|
|
23
|
+
"roleId": "report-writer",
|
|
24
|
+
"dutyId": "report-writer",
|
|
25
|
+
"min": 1,
|
|
26
|
+
"recommended": 1,
|
|
27
|
+
"max": 1
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"mode": "dynamic",
|
|
31
|
+
"roleId": "verifier",
|
|
32
|
+
"dutyId": "reverification-worker",
|
|
33
|
+
"sourceRoleIds": [
|
|
34
|
+
"analyser"
|
|
35
|
+
],
|
|
36
|
+
"activation": "per-selected-source"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -1,30 +1,5 @@
|
|
|
1
1
|
# Error Analysis Profile
|
|
2
2
|
|
|
3
|
-
```yaml
|
|
4
|
-
roles:
|
|
5
|
-
- role: analyser
|
|
6
|
-
min: 2
|
|
7
|
-
recommended: 3
|
|
8
|
-
max: 5
|
|
9
|
-
duty: diagnosis-worker
|
|
10
|
-
- role: critic
|
|
11
|
-
min: 0
|
|
12
|
-
recommended: 1
|
|
13
|
-
max: 1
|
|
14
|
-
duty: scope-critic
|
|
15
|
-
- role: report-writer
|
|
16
|
-
min: 1
|
|
17
|
-
recommended: 1
|
|
18
|
-
max: 1
|
|
19
|
-
duty: report-writer
|
|
20
|
-
- role: verifier
|
|
21
|
-
min: 0
|
|
22
|
-
recommended: 0
|
|
23
|
-
max: 0
|
|
24
|
-
duty: reverification-worker
|
|
25
|
-
dynamic: true
|
|
26
|
-
```
|
|
27
|
-
|
|
28
3
|
- Purpose: analyse reported errors or incidents and identify likely causes, missing evidence, and validation paths
|
|
29
4
|
- Required workers:
|
|
30
5
|
- claude
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"id": "feature-analysis",
|
|
4
|
+
"roles": [
|
|
5
|
+
{
|
|
6
|
+
"mode": "static",
|
|
7
|
+
"roleId": "analyser",
|
|
8
|
+
"dutyId": "analysis-worker",
|
|
9
|
+
"min": 2,
|
|
10
|
+
"recommended": 3,
|
|
11
|
+
"max": 5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"mode": "static",
|
|
15
|
+
"roleId": "report-writer",
|
|
16
|
+
"dutyId": "report-writer",
|
|
17
|
+
"min": 1,
|
|
18
|
+
"recommended": 1,
|
|
19
|
+
"max": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"mode": "dynamic",
|
|
23
|
+
"roleId": "verifier",
|
|
24
|
+
"dutyId": "reverification-worker",
|
|
25
|
+
"sourceRoleIds": [
|
|
26
|
+
"analyser"
|
|
27
|
+
],
|
|
28
|
+
"activation": "per-selected-source"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
# Feature Analysis Profile
|
|
2
2
|
|
|
3
|
-
```yaml
|
|
4
|
-
roles:
|
|
5
|
-
- role: analyser
|
|
6
|
-
min: 2
|
|
7
|
-
recommended: 3
|
|
8
|
-
max: 5
|
|
9
|
-
duty: analysis-worker
|
|
10
|
-
- role: report-writer
|
|
11
|
-
min: 1
|
|
12
|
-
recommended: 1
|
|
13
|
-
max: 1
|
|
14
|
-
duty: report-writer
|
|
15
|
-
- role: verifier
|
|
16
|
-
min: 0
|
|
17
|
-
recommended: 0
|
|
18
|
-
max: 0
|
|
19
|
-
duty: reverification-worker
|
|
20
|
-
dynamic: true
|
|
21
|
-
```
|
|
22
|
-
|
|
23
3
|
- Purpose: analyse a confirmed feature target's behavior, rules, state changes, external calls, and test coverage scope without designing or changing an implementation
|
|
24
4
|
- Required workers:
|
|
25
5
|
- claude
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"id": "final-verification",
|
|
4
|
+
"roles": [
|
|
5
|
+
{
|
|
6
|
+
"mode": "static",
|
|
7
|
+
"roleId": "verifier",
|
|
8
|
+
"dutyId": "acceptance-verifier",
|
|
9
|
+
"min": 2,
|
|
10
|
+
"recommended": 2,
|
|
11
|
+
"max": 5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"mode": "static",
|
|
15
|
+
"roleId": "critic",
|
|
16
|
+
"dutyId": "acceptance-critic",
|
|
17
|
+
"min": 0,
|
|
18
|
+
"recommended": 1,
|
|
19
|
+
"max": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"mode": "static",
|
|
23
|
+
"roleId": "report-writer",
|
|
24
|
+
"dutyId": "report-writer",
|
|
25
|
+
"min": 1,
|
|
26
|
+
"recommended": 1,
|
|
27
|
+
"max": 1
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -1,24 +1,5 @@
|
|
|
1
1
|
# Final Verification Profile
|
|
2
2
|
|
|
3
|
-
```yaml
|
|
4
|
-
roles:
|
|
5
|
-
- role: verifier
|
|
6
|
-
min: 2
|
|
7
|
-
recommended: 2
|
|
8
|
-
max: 5
|
|
9
|
-
duty: acceptance-verifier
|
|
10
|
-
- role: critic
|
|
11
|
-
min: 0
|
|
12
|
-
recommended: 1
|
|
13
|
-
max: 1
|
|
14
|
-
duty: acceptance-critic
|
|
15
|
-
- role: report-writer
|
|
16
|
-
min: 1
|
|
17
|
-
recommended: 1
|
|
18
|
-
max: 1
|
|
19
|
-
duty: report-writer
|
|
20
|
-
```
|
|
21
|
-
|
|
22
3
|
- Purpose: judge the delivered implementation on three axes before final acceptance — does it cover every requirement (under-delivery), does it carry work no requirement asked for (over-delivery), and does it actually do what it claims (defects, and tests that verify nothing). Whether the run followed okstra's own procedure is not one of the axes: the runtime and `validators/validate-run.py` own that, and a finding about it is not an acceptance judgement
|
|
23
4
|
- Required workers:
|
|
24
5
|
- claude
|
|
@@ -49,8 +30,8 @@ roles:
|
|
|
49
30
|
- Pre-verification entry gate (resolved & enforced by `okstra render-bundle` prep — the lead does NOT recompute it):
|
|
50
31
|
- the verification target (scope / worktree / base / stages / source reports / diff stat) is injected as the `VERIFICATION_TARGET` block. The lead MUST treat it as authoritative and MUST NOT re-pick a target from the brief.
|
|
51
32
|
- **whole-task scope** (`--stage auto`, default): prep has already verified every Stage Map stage is `status:done` in `consumers.jsonl`, every done stage's `head_commit` is an ancestor of the task worktree HEAD (all stage branches merged), and the worktree is clean outside `.okstra/`. If any check failed the run never started (PrepareError); a started whole-task run is therefore a fully-merged, clean target.
|
|
52
|
-
- **whole-task
|
|
53
|
-
- **single-stage scope** (`--stage N`): prep verified stage N is `status:done` and its isolated stage worktree exists and is clean. Other stages' state is irrelevant. A single-stage run is a partial verification
|
|
33
|
+
- **whole-task mutates only when it has to.** When one stage branch already contains every other done stage's commit — the usual shape of a linear plan, since each stage branches from its predecessor's done commit — that branch IS the whole task, and verification runs in that stage's worktree with no merge at all (`stage_targets.containing_stage`). Only when the stage graph has several tips does entry auto-merge (with `--no-ff`) the done stages into the task branch to create an integration commit; that case is the mutating one. The stage worktrees are NOT removed on entry: they are reclaimed after the verdict, by the Phase 7 `teardown-stages` step, and only when the verdict clears the work for release (`accepted`, or `conditional-accept` with no condition blocking release). A `blocked` verdict therefore leaves every stage worktree in place, so the rework it routes to can start immediately. The stage branches are kept as the reviewable stack (the target of `okstra handoff local-checkout --stage <N>`). If a merge conflict occurs it reports the conflicting files and aborts (the user resolves them manually and retries). A stage worktree with uncommitted changes remaining is preserved. Therefore the "fully-merged, clean target" the entry gate above refers to is the state after this auto-integration step completes, and whole-task final-verification must be treated as a mutating phase that creates the integration commit.
|
|
34
|
+
- **single-stage scope** (`--stage N`): prep verified stage N is `status:done` and its isolated stage worktree exists and is clean. Other stages' state is irrelevant. A single-stage run is a partial verification of one stage, and that is exactly the unit release-handoff ships: an `accepted` verdict here makes the stage PR-eligible, so `release-handoff` is the routing target. It says nothing about any other stage.
|
|
54
35
|
- the lead still captures `git status --short` from the injected worktree to confirm the analysis ran against the delivered work-tree state; an unexpected divergence (dirty tree outside `.okstra/`, missing worktree) is a `tool-failure`, not a silent proceed.
|
|
55
36
|
- Worker verification procedure:
|
|
56
37
|
- **Target confirmation:** analyse the injected target and nothing else. Read `verification-target.md` for the stage/report mapping and the complete diff stat. Prepare fixed that target and `validators/validate-run.py` `_validate_verification_target_match` re-checks the report against its digest, so the procedure to follow here is simply: if the worktree you can see does not match the injected target, record a `tool-failure` — never reselect a target.
|
|
@@ -84,7 +65,7 @@ roles:
|
|
|
84
65
|
- **Validation Evidence**: for every requirement in the originating plan or task brief, cite the artifact (commit SHA, test output, log line, MCP SELECT result) that demonstrates coverage. Paraphrased "verified" claims without an artifact are rejected.
|
|
85
66
|
- **Read-only command log**: any pre-existing test/validation command touched during this run MUST be listed with its exact command line and one honest status — `executed` (ran; carries its exit code) / `advisory` (external Tier 3 did not PASS; carries observed/expected results and remains user-owned) / `env-unavailable` (should run but cannot in this environment — missing replica DB, container, or service; carries the reason, never a faked pass) / `not-configured` (no such qa-command tier) / `rejected` (a mutating/denied token — skipped, carries the denied token). A check that could not run locally is recorded as `env-unavailable` or `advisory` according to the external QA policy — never silently dropped and never reported as `executed` with an invented exit code. Mutating-command prohibition is the shared read-only boundary (see Non-goals); it is not restated per row.
|
|
86
67
|
- **Could-not-verify roll-up (§5.8.9)**: the template mechanically aggregates every not-confirmed check into one scannable list — `gap` requirement-coverage rows, `advisory` / `not-configured` / `env-unavailable` / `rejected` command rows, and `blocked` manual tests. You do not hand-author it, but you MUST give those rows their honest status so nothing unverified hides across sections: a check silently recorded as `executed`/`covered` will not surface in the roll-up. This is okstra's answer to "say what could not be verified this run."
|
|
87
|
-
- **Routing recommendation**: `finalVerification.routingRecommendation` is an **object** with exactly two fields — `target`, one value of the enum below, and `rationale`, the sentence tying that choice to the verdict and the blocker list. Free routing prose is not the field; a target named only in the prose does not route the task, because Phase 7 projects `workflow.nextRecommendedPhase` from `target` alone. The
|
|
68
|
+
- **Routing recommendation**: `finalVerification.routingRecommendation` is an **object** with exactly two fields — `target`, one value of the enum below, and `rationale`, the sentence tying that choice to the verdict and the blocker list. Free routing prose is not the field; a target named only in the prose does not route the task, because Phase 7 projects `workflow.nextRecommendedPhase` from `target` alone. The eight allowed targets are `release-handoff`, `release-handoff(stage-group)`, `final-verification`, `error-analysis`, `implementation-option-selection`, `implementation-planning`, `implementation`, and `done`. `final-verification` re-runs this phase on the same head and is for exactly one situation: every remaining blocker is an environment or configuration fault whose cause this report already names — a `qaCommands` entry pointing at a path that no longer exists, a missing credential, a stale fixture — so nothing in the code, the plan, or the selected direction is being re-decided. Name the repair in the `rationale`. When any blocker needs a code, plan, or direction change, route to the phase that owns that change instead; routing a defect you have not diagnosed back into this phase re-runs the verification that already failed. Both `release-handoff` forms are allowed ONLY when the verdict is release-ready — `accepted`, or `conditional-accept` with every condition declaring `blocksReleaseHandoff: false`. Either verification scope may route there: release-handoff opens one PR per stage, so a release-ready `single-stage` run is the evidence for that stage's PR, and `release-handoff(stage-group)` is only a scope qualifier that projects onto the same phase. `done` ends the lifecycle here. Enforcement: `schemas/final-report-v2.0.schema.json` rejects a `target` outside the enum, a missing `rationale`, and a string in place of the object; `validators/validate-run.py` rejects a missing `target` and a verdict that is not release-ready routed to either `release-handoff` form (naming the condition ids that block it).
|
|
88
69
|
- **Verified-row recording** (single-stage scope only): when the verdict is release-ready, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report.md path> --data-json <final-report data.json path>` and quote the command + exit code in the report. The helper checks the latest verification manifest, task/stage identity, report pointer, prepared target, and recorded implementation commit. It records the captured commit and original verdict, including conditional acceptance conditions. A missing target or mismatched commit requires re-verification. Recording happens before final validation; eligibility is granted only after that verification passes validation. **Enforced:** `okstra_ctl.handoff_verification` validates the evidence, and `validators/validate-run.py` `_validate_verified_row_recorded` requires a `verified` row matching this report, captured commit, and verdict.
|
|
89
70
|
- Clarification request policy (phase-specific addendum — shared policy is in `_common-contract.md`):
|
|
90
71
|
- populate `## 1. Clarification Items` only when a blocker hinges on information only the user can supply (deployment intent, intended target environment, business-rule interpretation); use `Blocks=next-phase` for items that gate continuing to release-handoff
|
|
@@ -75,13 +75,14 @@
|
|
|
75
75
|
],
|
|
76
76
|
"release-handoff": [
|
|
77
77
|
"entering this phase when the cited final-verification `Verdict Token` is `conditional-accept` or `blocked`, or when no final-verification report is cited",
|
|
78
|
-
"local commit commands of any kind (`git add`, `git commit`, `git restore --staged`, `git stash`), and any direct `git merge` / `git rebase` run by the lead. The single exception is the merge commits `okstra handoff
|
|
78
|
+
"local commit commands of any kind (`git add`, `git commit`, `git restore --staged`, `git stash`), and any direct `git merge` / `git rebase` / `git rebase --onto` / `git cherry-pick` / `git commit --amend` run by the lead. The single exception is the merge commits `okstra handoff pr-plan` itself creates on a `merge-base` branch — the lead never merges by hand. Rewriting a stage branch breaks the PR stack that sits on it.",
|
|
79
79
|
"any git push variant that rewrites remote history, regardless of intent or whether the user said \"force it\": `git push --force`, `git push --force-with-lease`, `git push -f`, `git push +<refspec>`, or any other history-rewriting invocation",
|
|
80
|
-
"pushing directly to a base branch — i.e. `git push origin <branch>` where `<branch>` is `main`, `master`, `prod`, `preprod`, `staging`, `dev`, or the branch the user chose as the
|
|
80
|
+
"pushing directly to a release base branch — i.e. `git push origin <branch>` where `<branch>` is `main`, `master`, `prod`, `preprod`, `staging`, `dev`, or the branch the user chose as the release base in this run. The only permitted push targets are the branches `okstra handoff pr-plan` listed for this run (each stage `head_branch`, and any `merge-base` branch).",
|
|
81
81
|
"bypassing repo safeguards: `--no-verify` / `-n` on `git push`, bypassing GPG signing, disabling safeguards via equivalent flags, or any hook bypass.",
|
|
82
82
|
"release-publishing commands: `gh release create`, `gh release edit`, `npm publish`, `cargo publish`, `pip publish`, `twine upload`, `docker push`, `terraform apply`, `kubectl apply` against any non-local cluster.",
|
|
83
83
|
"source-code edits, refactors, or any modification to files outside the run's own artifact directories (`reports/`, `prompts/`, `state/`, `manifests/`, `worker-results/`, `status/`, `sessions/`). The diff being shipped MUST be exactly what the prior `implementation` run produced; release-handoff packages it, it does not re-author it.",
|
|
84
|
-
"executing any mutating command the user did NOT select. Examples: opening a PR when the user picked `local checkout`; pushing when the user picked `skip`; switching the
|
|
84
|
+
"executing any mutating command the user did NOT select. Examples: opening a PR when the user picked `local checkout`; pushing when the user picked `skip`; switching the release base branch silently after the user already chose one; opening a PR for a stage outside `HANDOFF_STAGES`.",
|
|
85
|
+
"squash-merging, or instructing anyone to squash-merge, a stage PR — and `gh pr merge` in any form. A squash replaces the commits the next stage's PR base points at, so the stack breaks; the PR body states merge-commit-or-rebase and the lead never merges.",
|
|
85
86
|
"retrying a failed git / gh command with weaker safety flags. If `git push` fails with non-fast-forward, the lead MUST stop, explain the failure to the user, and ask for instructions — it MUST NOT add `--force`.",
|
|
86
87
|
"worker dispatch of any kind, or any other parallel sub-agent fan-out. This phase runs entirely under the Okstra lead.",
|
|
87
88
|
"silently treating an unrecognised user reply as one of the menu options. If the user's answer does not match a presented choice, re-ask the question verbatim."
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"id": "implementation-option-selection",
|
|
4
|
+
"roles": [
|
|
5
|
+
{
|
|
6
|
+
"mode": "static",
|
|
7
|
+
"roleId": "designer",
|
|
8
|
+
"dutyId": "direction-selection-worker",
|
|
9
|
+
"min": 3,
|
|
10
|
+
"recommended": 3,
|
|
11
|
+
"max": 5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"mode": "static",
|
|
15
|
+
"roleId": "report-writer",
|
|
16
|
+
"dutyId": "report-writer",
|
|
17
|
+
"min": 1,
|
|
18
|
+
"recommended": 1,
|
|
19
|
+
"max": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"mode": "dynamic",
|
|
23
|
+
"roleId": "verifier",
|
|
24
|
+
"dutyId": "reverification-worker",
|
|
25
|
+
"sourceRoleIds": [
|
|
26
|
+
"designer"
|
|
27
|
+
],
|
|
28
|
+
"activation": "per-selected-source"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
# Implementation Option Selection Profile
|
|
2
2
|
|
|
3
|
-
```yaml
|
|
4
|
-
roles:
|
|
5
|
-
- role: designer
|
|
6
|
-
min: 3
|
|
7
|
-
recommended: 3
|
|
8
|
-
max: 5
|
|
9
|
-
duty: direction-selection-worker
|
|
10
|
-
- role: report-writer
|
|
11
|
-
min: 1
|
|
12
|
-
recommended: 1
|
|
13
|
-
max: 1
|
|
14
|
-
duty: report-writer
|
|
15
|
-
- role: verifier
|
|
16
|
-
min: 0
|
|
17
|
-
recommended: 0
|
|
18
|
-
max: 0
|
|
19
|
-
duty: reverification-worker
|
|
20
|
-
dynamic: true
|
|
21
|
-
```
|
|
22
|
-
|
|
23
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
|
|
24
4
|
- Required workers:
|
|
25
5
|
- claude
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0",
|
|
3
|
+
"id": "implementation-planning",
|
|
4
|
+
"roles": [
|
|
5
|
+
{
|
|
6
|
+
"mode": "static",
|
|
7
|
+
"roleId": "planner",
|
|
8
|
+
"dutyId": "planning-worker",
|
|
9
|
+
"min": 2,
|
|
10
|
+
"recommended": 2,
|
|
11
|
+
"max": 5
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"mode": "static",
|
|
15
|
+
"roleId": "critic",
|
|
16
|
+
"dutyId": "scope-critic",
|
|
17
|
+
"min": 0,
|
|
18
|
+
"recommended": 1,
|
|
19
|
+
"max": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"mode": "static",
|
|
23
|
+
"roleId": "report-writer",
|
|
24
|
+
"dutyId": "report-writer",
|
|
25
|
+
"min": 1,
|
|
26
|
+
"recommended": 1,
|
|
27
|
+
"max": 1
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"mode": "dynamic",
|
|
31
|
+
"roleId": "verifier",
|
|
32
|
+
"dutyId": "reverification-worker",
|
|
33
|
+
"sourceRoleIds": [
|
|
34
|
+
"critic",
|
|
35
|
+
"planner"
|
|
36
|
+
],
|
|
37
|
+
"activation": "per-selected-source"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|