okstra 0.171.0 → 0.173.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 +8 -6
- package/docs/architecture/storage-model.md +11 -0
- package/docs/architecture.md +29 -14
- package/docs/cli.md +40 -7
- package/docs/for-ai/skills/okstra-user-response.md +2 -2
- package/docs/performance-improvement-plan-v2.md +6 -5
- package/docs/project-structure-overview.md +24 -14
- package/docs/task-process/README.md +5 -3
- package/docs/task-process/error-analysis.md +2 -2
- package/docs/task-process/final-verification.md +2 -2
- package/docs/task-process/implementation-option-selection.md +70 -0
- package/docs/task-process/implementation-planning.md +23 -15
- package/docs/task-process/requirements-discovery.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +30 -6
- package/runtime/bin/lib/okstra/cli.sh +5 -1
- package/runtime/bin/lib/okstra/globals.sh +1 -0
- package/runtime/bin/lib/okstra/usage.sh +3 -0
- package/runtime/bin/okstra.sh +2 -0
- package/runtime/prompts/duties/direction-selection-worker.md +44 -0
- package/runtime/prompts/duties/planning-worker.md +12 -4
- package/runtime/prompts/launch.template.md +4 -0
- package/runtime/prompts/lead/adapters/cmux.md +1 -1
- package/runtime/prompts/lead/context-loader.md +1 -1
- package/runtime/prompts/lead/convergence.md +5 -5
- package/runtime/prompts/lead/okstra-lead-contract.md +42 -17
- package/runtime/prompts/lead/plan-body-verification.md +42 -14
- package/runtime/prompts/lead/report-writer.md +38 -15
- package/runtime/prompts/lead/team-contract.md +2 -0
- package/runtime/prompts/profiles/_clarification-recommendation.md +3 -1
- package/runtime/prompts/profiles/_common-contract.md +3 -2
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
- package/runtime/prompts/profiles/error-analysis.md +3 -3
- package/runtime/prompts/profiles/final-verification.md +3 -3
- package/runtime/prompts/profiles/forbidden-actions.json +7 -0
- package/runtime/prompts/profiles/implementation-option-selection.md +35 -0
- package/runtime/prompts/profiles/implementation-planning.md +56 -37
- package/runtime/prompts/profiles/implementation.md +2 -1
- package/runtime/prompts/profiles/improvement-discovery.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +3 -3
- package/runtime/prompts/wizard/prompts.ko.json +9 -1
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +1 -1
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +1 -1
- package/runtime/python/okstra_ctl/agent_activity.py +306 -0
- package/runtime/python/okstra_ctl/agent_invocation.py +1 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +6 -0
- package/runtime/python/okstra_ctl/clarification_items.py +37 -20
- package/runtime/python/okstra_ctl/exact_coverage.py +128 -0
- package/runtime/python/okstra_ctl/fix_cycles.py +3 -1
- package/runtime/python/okstra_ctl/implementation_direction.py +836 -0
- package/runtime/python/okstra_ctl/implementation_options.py +479 -0
- package/runtime/python/okstra_ctl/lead_events.py +47 -4
- package/runtime/python/okstra_ctl/plan_items.py +51 -3
- package/runtime/python/okstra_ctl/render.py +12 -3
- package/runtime/python/okstra_ctl/render_final_report.py +1 -0
- package/runtime/python/okstra_ctl/report_contract.py +45 -13
- package/runtime/python/okstra_ctl/report_finalize.py +51 -14
- package/runtime/python/okstra_ctl/report_html/common.py +5 -3
- package/runtime/python/okstra_ctl/report_html/render.py +4 -2
- package/runtime/python/okstra_ctl/report_html/router.py +4 -0
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_option_selection.py +32 -0
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +42 -11
- package/runtime/python/okstra_ctl/report_translation.py +14 -0
- package/runtime/python/okstra_ctl/report_views.py +148 -12
- package/runtime/python/okstra_ctl/run.py +350 -2
- package/runtime/python/okstra_ctl/scope_provenance.py +15 -9
- package/runtime/python/okstra_ctl/user_response.py +75 -0
- package/runtime/python/okstra_ctl/wizard.py +144 -0
- package/runtime/python/okstra_ctl/worker_audit_ledger.py +150 -0
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +2 -0
- package/runtime/python/okstra_ctl/workflow.py +29 -7
- package/runtime/schemas/final-report-v2.0.schema.json +1623 -143
- package/runtime/skills/okstra-user-response/SKILL.md +2 -2
- package/runtime/templates/reports/final-report-v2.template.md +12 -0
- package/runtime/templates/reports/final-verification-input.template.md +1 -1
- package/runtime/templates/reports/html/assets/base.css +7 -0
- package/runtime/templates/reports/html/base.template.html +3 -2
- package/runtime/templates/reports/html/i18n/en.json +27 -2
- package/runtime/templates/reports/html/i18n/ko.json +27 -2
- package/runtime/templates/reports/html/macros/forms.html +42 -4
- package/runtime/templates/reports/html/tasks/implementation-option-selection.template.html +49 -0
- package/runtime/templates/reports/html/tasks/implementation-planning.template.html +61 -2
- package/runtime/templates/reports/i18n/en.json +17 -0
- package/runtime/templates/reports/implementation-input.template.md +4 -2
- package/runtime/templates/reports/implementation-planning-input.template.md +18 -4
- package/runtime/templates/reports/improvement-discovery-input.template.md +1 -1
- package/runtime/templates/reports/md/tasks/implementation-option-selection.template.md +13 -0
- package/runtime/templates/reports/md/tasks/implementation-planning.template.md +17 -0
- package/runtime/templates/reports/report.js +137 -21
- package/runtime/templates/reports/task-brief.template.md +9 -3
- package/runtime/templates/reports/user-response.template.md +28 -5
- package/runtime/templates/worker-prompt-preamble.md +16 -0
- package/runtime/validators/validate-implementation-plan-stages.py +106 -1
- package/runtime/validators/validate-report-views.py +2 -2
- package/runtime/validators/validate-run.py +1124 -54
- package/runtime/validators/validate_improvement_report.py +5 -1
- package/runtime/validators/validate_session_conformance.py +523 -35
- package/src/cli-registry.mjs +7 -0
- package/src/commands/execute/codex-run.mjs +1 -0
- package/src/commands/execute/render-bundle.mjs +1 -0
- package/src/commands/report/agent-activity.mjs +21 -0
|
@@ -73,7 +73,7 @@ okstra user-response show --report <reportPath>
|
|
|
73
73
|
|
|
74
74
|
Returns `{reportPath, rows: [{id, kind, blocks, status, statement, expectedForm, options, contextRefs, resolvedRefs}]}`.
|
|
75
75
|
|
|
76
|
-
Each entry of `options[]` is `{role, answer, rationale, scopeImpact, addedWork, directionChange}`. `role` is `recommended` for exactly one entry and `alternative` for the rest; `scopeImpact` is a token list drawn from `in-repo` / `cross-repo` / `new-schema` / `deferrable`; `addedWork` and `directionChange` are one sentence each. A schema-v1 report has nowhere to record impact, so those
|
|
76
|
+
Each entry of `options[]` is `{role, answer, rationale, scopeImpact, addedWork, directionChange, disposition}`. `role` is `recommended` for exactly one entry and `alternative` for the rest; `scopeImpact` is a token list drawn from `in-repo` / `cross-repo` / `new-schema` / `deferrable`; `addedWork` and `directionChange` are one sentence each. Activity-contract v1 approval options also carry the gate action in `disposition`. A legacy schema-v1 report has nowhere to record impact or a gate action, so those fields arrive empty — the CLI reconstructs only the answers from the report's `Expected form` cell.
|
|
77
77
|
|
|
78
78
|
`resolvedRefs` is `[{ref, definition}]` — the CLI has already looked up what each internal token (`RB-002`, `FU-001`, `§4.7`, …) means in the report body; `definition` is `null` only when the report text alone could not resolve it (e.g. a `path:line` pointer).
|
|
79
79
|
|
|
@@ -127,7 +127,7 @@ Record one entry — `{id, kind, value, rationale?, disposition}`, `kind` copied
|
|
|
127
127
|
|
|
128
128
|
| The user picks | `value` | `disposition` |
|
|
129
129
|
|---|---|---|
|
|
130
|
-
| One of the `options[]` entries | that option's `answer` text, not its short label | `answer` |
|
|
130
|
+
| One of the `options[]` entries | that option's `answer` text, not its short label | that option's `disposition` (`answer` only when absent on a legacy option) |
|
|
131
131
|
| `Enter directly` → their own answer | the user's utterance verbatim (rationale into `rationale`) | `answer` |
|
|
132
132
|
| Free text asking for the item to be re-asked | what the user wants re-asked, verbatim (empty → the raw statement) | `reframe` |
|
|
133
133
|
|
|
@@ -11,7 +11,11 @@ project-id: {{ frontmatter.projectId | yaml_scalar }}
|
|
|
11
11
|
task-type: {{ frontmatter.taskType | yaml_scalar }}
|
|
12
12
|
worker-id: {{ frontmatter.workerId | yaml_scalar }}
|
|
13
13
|
approved: {{ "true" if frontmatter.approved else "false" }}
|
|
14
|
+
{% if implementationPlanning is defined and implementationPlanning.get("planningContract") == "selected-direction" -%}
|
|
15
|
+
selected-direction-ref: {{ frontmatter.selectedDirectionRef | yaml_scalar }}
|
|
16
|
+
{% else -%}
|
|
14
17
|
implementation-option: {{ frontmatter.implementationOption | default("") | yaml_scalar }}
|
|
18
|
+
{% endif -%}
|
|
15
19
|
schema-version: {{ schemaVersion | yaml_scalar }}
|
|
16
20
|
---
|
|
17
21
|
{#
|
|
@@ -110,6 +114,14 @@ schema-version: {{ schemaVersion | yaml_scalar }}
|
|
|
110
114
|
{{ md_rest(aiTaskProperty, 3) }}
|
|
111
115
|
{% endif %}
|
|
112
116
|
|
|
117
|
+
{% if md_has("agentActivity") %}
|
|
118
|
+
## {{ t("agentActivity.heading") }}
|
|
119
|
+
|
|
120
|
+
{{ t("agentActivity.intro") }}
|
|
121
|
+
|
|
122
|
+
{{ md("agentActivity", 3) }}
|
|
123
|
+
{% endif %}
|
|
124
|
+
|
|
113
125
|
## Cross Verification Audit
|
|
114
126
|
|
|
115
127
|
{{ md("crossVerification", 3) }}
|
|
@@ -40,7 +40,7 @@ taskType: "{{FM_TASK_TYPE}}"
|
|
|
40
40
|
- Path (project-relative) to the originating `implementation` final-report:
|
|
41
41
|
- Quoted `Commit list` / `Diff summary` excerpt from the implementation report:
|
|
42
42
|
|
|
43
|
-
> If the report path is empty or points to a missing report, final-verification ends with status `blocked`
|
|
43
|
+
> If the report path is empty or points to a missing report, final-verification ends with status `blocked`. Cause defects route to `error-analysis`, direction defects route to `implementation-option-selection`, and detailed-plan defects route to `implementation-planning`. The verification target (worktree/base) is resolved automatically by okstra, so a mismatched manual entry cannot cause a block.
|
|
44
44
|
|
|
45
45
|
## Requirement Coverage Source
|
|
46
46
|
|
|
@@ -108,6 +108,13 @@ textarea, select { width: 100%; max-width: 60rem; padding: .55rem; font: inherit
|
|
|
108
108
|
.clarification-expected dt { font-weight: 600; margin-bottom: .3rem; }
|
|
109
109
|
.clarification-expected dd { margin: 0; }
|
|
110
110
|
.clarification-item label { font-weight: 600; margin-bottom: .3rem; }
|
|
111
|
+
.activity-list { display: grid; gap: .8rem; }
|
|
112
|
+
.activity-card { padding: 1rem; border: 1px solid color-mix(in srgb, CanvasText 14%, transparent); border-radius: 12px; }
|
|
113
|
+
.activity-card > :first-child, .approval-context > :first-child { margin-top: 0; }
|
|
114
|
+
.activity-card > :last-child, .approval-context > :last-child { margin-bottom: 0; }
|
|
115
|
+
.activity-card details { margin-top: .8rem; }
|
|
116
|
+
.approval-context { margin: .8rem 0; padding: .8rem 1rem; border-left: 4px solid color-mix(in srgb, Highlight 55%, GrayText); background: color-mix(in srgb, Highlight 7%, Canvas); }
|
|
117
|
+
.clarification-option-disposition { color: GrayText; font-size: .85rem; }
|
|
111
118
|
.user-response-hint { flex-basis: 100%; margin: 0; color: GrayText; font-size: .9rem; }
|
|
112
119
|
button { padding: .5rem 1rem; border-radius: 8px; border: 1px solid color-mix(in srgb, CanvasText 28%, transparent); background: color-mix(in srgb, CanvasText 5%, Canvas); color: CanvasText; font: inherit; cursor: pointer; }
|
|
113
120
|
button:hover { background: color-mix(in srgb, CanvasText 12%, Canvas); }
|
|
@@ -87,18 +87,19 @@
|
|
|
87
87
|
</section>
|
|
88
88
|
{% endif %}
|
|
89
89
|
</main>
|
|
90
|
-
<footer class="human-report-footer">
|
|
90
|
+
{% if approval is not defined or not (approval and approval.reentry_command) %}<footer class="human-report-footer">
|
|
91
91
|
<button type="button" data-action="export-user-response">{{ t('base.export-my-answers') }}</button>
|
|
92
92
|
<button type="button" data-action="copy-user-response">{{ t('base.copy') }}</button>
|
|
93
93
|
<button type="button" data-action="dismiss-user-response" hidden>{{ t('base.dismiss') }}</button>
|
|
94
94
|
<p class="user-response-hint">{{ t('base.export-downloads') }} <code>user-response-{{ runMeta.task_type }}-{{ runMeta.seq }}.md</code>{{ t('base.drop-that-file-into') }} <code>runs/{{ runMeta.task_type }}/user-responses/</code> {{ t('base.and-the-next-run-picks-your-answers-up-on-it') }}</p>
|
|
95
95
|
<pre id="user-response-output" aria-live="polite"></pre>
|
|
96
|
-
</footer>
|
|
96
|
+
</footer>{% endif %}
|
|
97
97
|
<script id="run-meta" type="application/json">{{ {
|
|
98
98
|
"task-key": runMeta.task_key,
|
|
99
99
|
"task-type": runMeta.task_type,
|
|
100
100
|
"seq": runMeta.seq,
|
|
101
101
|
"source-report": runMeta.source_report,
|
|
102
|
+
"source-data": sourceData,
|
|
102
103
|
"source-data-sha256": dataSha256,
|
|
103
104
|
"source-md-sha256": markdownSha256
|
|
104
105
|
} | tojson }}</script>
|
|
@@ -150,6 +150,7 @@
|
|
|
150
150
|
"questions-waiting-on-you": "Questions waiting on you",
|
|
151
151
|
"count-questions-waiting-on-you": "{count} questions waiting on you",
|
|
152
152
|
"your-answer-to-id": "Your answer to {id}",
|
|
153
|
+
"choose-one": "Choose one",
|
|
153
154
|
"recommended": "Recommended",
|
|
154
155
|
"scope-impact": "Scope",
|
|
155
156
|
"added-work": "Added work",
|
|
@@ -158,7 +159,9 @@
|
|
|
158
159
|
"request-changes-to-this-plan": "Send it back for changes",
|
|
159
160
|
"reject-this-plan": "Reject this plan",
|
|
160
161
|
"why-required-for-changes-or-rejection": "Why — required when you send it back or reject it",
|
|
161
|
-
"answer-the-blockers-then-regenerate": "Answer {ids}, export your answers, then regenerate the report with the clarification resume command."
|
|
162
|
+
"answer-the-blockers-then-regenerate": "Answer {ids}, export your answers, then regenerate the report with the clarification resume command.",
|
|
163
|
+
"selected-direction-invalidated": "Selected direction invalidated",
|
|
164
|
+
"return-to-option-selection": "This plan cannot be approved. Re-enter implementation option selection with:"
|
|
162
165
|
},
|
|
163
166
|
"visualizations": {
|
|
164
167
|
"component": "Component",
|
|
@@ -249,6 +252,24 @@
|
|
|
249
252
|
"release-path": "Release path",
|
|
250
253
|
"the-current-verdict-does-not-allow-release-h": "The current verdict does not allow release-handoff to start. Clear the blocker or the condition first."
|
|
251
254
|
},
|
|
255
|
+
"implementation-option-selection": {
|
|
256
|
+
"original-requirements": "Original requirement coverage",
|
|
257
|
+
"requirement-ids": "Requirement IDs:",
|
|
258
|
+
"leading-causes": "Leading causes:",
|
|
259
|
+
"ranked-options": "Ranked implementation directions",
|
|
260
|
+
"weighted-score": "Weighted score:",
|
|
261
|
+
"requirement": "Requirement",
|
|
262
|
+
"satisfaction": "How it is satisfied",
|
|
263
|
+
"verification": "Expected verification",
|
|
264
|
+
"no-valid-options": "No valid implementation direction is available.",
|
|
265
|
+
"recommended-direction": "Recommended direction",
|
|
266
|
+
"no-recommendation": "No direction can be recommended.",
|
|
267
|
+
"candidate-audit": "Candidate audit",
|
|
268
|
+
"candidate": "Candidate",
|
|
269
|
+
"disposition": "Disposition",
|
|
270
|
+
"reason": "Reason",
|
|
271
|
+
"no-audit-entries": "No candidate was merged or rejected."
|
|
272
|
+
},
|
|
252
273
|
"implementation-planning": {
|
|
253
274
|
"what-the-plan-is-for": "What the plan is for",
|
|
254
275
|
"implementation-options-compared": "Implementation options compared",
|
|
@@ -322,7 +343,11 @@
|
|
|
322
343
|
"open-decisions-before-approval": "Open decisions before approval",
|
|
323
344
|
"no-open-decision-is-holding-approval": "No open decision is holding approval.",
|
|
324
345
|
"uniform-verifier-label": "Uniform verifier",
|
|
325
|
-
"uniform-verifier-legend": "This verifier answered the same verdict to every item it voted on, so this round's refutation signal came from its peers alone — the gate above reads as a wider cross-check than it was. A unanimous round is a legitimate outcome; confirm from the worker's audit sidecar that it actually opened the cited evidence."
|
|
346
|
+
"uniform-verifier-legend": "This verifier answered the same verdict to every item it voted on, so this round's refutation signal came from its peers alone — the gate above reads as a wider cross-check than it was. A unanimous round is a legitimate outcome; confirm from the worker's audit sidecar that it actually opened the cited evidence.",
|
|
347
|
+
"what-each-agent-did": "What each agent did",
|
|
348
|
+
"commands-and-evidence": "Commands and evidence",
|
|
349
|
+
"unblock-condition": "Unblock condition:",
|
|
350
|
+
"agent-evidence": "Agent evidence:"
|
|
326
351
|
},
|
|
327
352
|
"implementation": {
|
|
328
353
|
"what-was-delivered": "What was delivered",
|
|
@@ -150,6 +150,7 @@
|
|
|
150
150
|
"questions-waiting-on-you": "답변을 기다리는 질문",
|
|
151
151
|
"count-questions-waiting-on-you": "답변을 기다리는 질문 {count}건",
|
|
152
152
|
"your-answer-to-id": "{id}에 대한 답변",
|
|
153
|
+
"choose-one": "하나를 선택하세요",
|
|
153
154
|
"recommended": "권장",
|
|
154
155
|
"scope-impact": "범위",
|
|
155
156
|
"added-work": "추가 작업",
|
|
@@ -158,7 +159,9 @@
|
|
|
158
159
|
"request-changes-to-this-plan": "고쳐서 다시 가져오게 합니다",
|
|
159
160
|
"reject-this-plan": "이 계획을 반려합니다",
|
|
160
161
|
"why-required-for-changes-or-rejection": "사유 — 반려하거나 다시 고치게 할 때는 반드시 적어야 합니다",
|
|
161
|
-
"answer-the-blockers-then-regenerate": "{ids}에 답한 뒤 답변을 내보내고, clarification resume 명령으로 리포트를 다시 만드세요."
|
|
162
|
+
"answer-the-blockers-then-regenerate": "{ids}에 답한 뒤 답변을 내보내고, clarification resume 명령으로 리포트를 다시 만드세요.",
|
|
163
|
+
"selected-direction-invalidated": "선택 방향 무효화",
|
|
164
|
+
"return-to-option-selection": "이 계획은 승인할 수 없습니다. 다음 명령으로 구현 방향 선택 단계에 다시 진입하세요:"
|
|
162
165
|
},
|
|
163
166
|
"visualizations": {
|
|
164
167
|
"component": "구성 요소",
|
|
@@ -249,6 +252,24 @@
|
|
|
249
252
|
"release-path": "릴리스 경로",
|
|
250
253
|
"the-current-verdict-does-not-allow-release-h": "현재 판정으로는 release-handoff 를 시작할 수 없습니다. 차단 항목이나 조건을 먼저 해소하세요."
|
|
251
254
|
},
|
|
255
|
+
"implementation-option-selection": {
|
|
256
|
+
"original-requirements": "원본 요구사항 커버리지",
|
|
257
|
+
"requirement-ids": "요구사항 ID:",
|
|
258
|
+
"leading-causes": "주요 원인:",
|
|
259
|
+
"ranked-options": "구현 방향 순위",
|
|
260
|
+
"weighted-score": "가중 점수:",
|
|
261
|
+
"requirement": "요구사항",
|
|
262
|
+
"satisfaction": "충족 방식",
|
|
263
|
+
"verification": "예상 검증",
|
|
264
|
+
"no-valid-options": "유효한 구현 방향이 없습니다.",
|
|
265
|
+
"recommended-direction": "권장 방향",
|
|
266
|
+
"no-recommendation": "권장할 수 있는 방향이 없습니다.",
|
|
267
|
+
"candidate-audit": "후보 감사 기록",
|
|
268
|
+
"candidate": "후보",
|
|
269
|
+
"disposition": "처리",
|
|
270
|
+
"reason": "이유",
|
|
271
|
+
"no-audit-entries": "병합되거나 탈락한 후보가 없습니다."
|
|
272
|
+
},
|
|
252
273
|
"implementation-planning": {
|
|
253
274
|
"what-the-plan-is-for": "이 계획이 하려는 것",
|
|
254
275
|
"implementation-options-compared": "구현 방식 비교",
|
|
@@ -322,7 +343,11 @@
|
|
|
322
343
|
"open-decisions-before-approval": "승인 전에 남은 결정",
|
|
323
344
|
"no-open-decision-is-holding-approval": "승인을 막는 미결 결정이 없습니다.",
|
|
324
345
|
"uniform-verifier-label": "단일 판정 검증자",
|
|
325
|
-
"uniform-verifier-legend": "이 검증자는 자기가 투표한 모든 항목에 같은 판정을 냈습니다. 그래서 이번 라운드의 반증 신호는 나머지 검증자에게서만 나왔고, 위의 게이트 값은 실제보다 넓은 교차 검증처럼 읽힙니다. 만장일치도 정당한 결과이므로, 그 워커의 audit 사이드카에서 인용한 근거를 실제로 열어봤는지 확인하십시오."
|
|
346
|
+
"uniform-verifier-legend": "이 검증자는 자기가 투표한 모든 항목에 같은 판정을 냈습니다. 그래서 이번 라운드의 반증 신호는 나머지 검증자에게서만 나왔고, 위의 게이트 값은 실제보다 넓은 교차 검증처럼 읽힙니다. 만장일치도 정당한 결과이므로, 그 워커의 audit 사이드카에서 인용한 근거를 실제로 열어봤는지 확인하십시오.",
|
|
347
|
+
"what-each-agent-did": "에이전트별 수행 내용",
|
|
348
|
+
"commands-and-evidence": "명령과 근거",
|
|
349
|
+
"unblock-condition": "승인 해제 조건:",
|
|
350
|
+
"agent-evidence": "에이전트 근거:"
|
|
326
351
|
},
|
|
327
352
|
"implementation": {
|
|
328
353
|
"what-was-delivered": "무엇을 만들었나",
|
|
@@ -18,21 +18,40 @@
|
|
|
18
18
|
|
|
19
19
|
{% macro plan_approval(state) -%}
|
|
20
20
|
<section id="plan-approval" data-report-section="plan-approval">
|
|
21
|
+
{% if state.reentry_command %}
|
|
22
|
+
<h2>{{ t('macros.forms.selected-direction-invalidated') }}</h2>
|
|
23
|
+
<p class="approval-disabled-reason">{{ t('macros.forms.return-to-option-selection') }} <code>{{ state.reentry_command }}</code></p>
|
|
24
|
+
{% else %}
|
|
21
25
|
<h2>{{ t('macros.forms.decide-on-this-plan') }}</h2>
|
|
22
26
|
<fieldset id="plan-decision"><legend>{{ t('macros.forms.verdict') }}</legend>
|
|
23
27
|
<input id="plan-decision-approved" type="radio" name="plan-decision-status" value="approved"{% if state.disabled_reason %} disabled{% endif %}><label for="plan-decision-approved">{{ t('macros.forms.i-approve-this-plan') }}</label>
|
|
24
28
|
<input id="plan-decision-revision-requested" type="radio" name="plan-decision-status" value="revision-requested"><label for="plan-decision-revision-requested">{{ t('macros.forms.request-changes-to-this-plan') }}</label>
|
|
25
29
|
<input id="plan-decision-rejected" type="radio" name="plan-decision-status" value="rejected"><label for="plan-decision-rejected">{{ t('macros.forms.reject-this-plan') }}</label>
|
|
26
30
|
</fieldset>
|
|
27
|
-
<label for="approval-option">{{ t('macros.forms.implementation-option') }}</label>
|
|
31
|
+
{% if state.show_option_selector %}<label for="approval-option">{{ t('macros.forms.implementation-option') }}</label>
|
|
28
32
|
<select id="approval-option"{% if state.disabled_reason %} disabled{% endif %}>
|
|
29
33
|
{% for name in state.option_names %}
|
|
30
34
|
{% if name == state.recommended_option %}<option data-recommended="true" selected value="{{ name }}">{{ name | inline_code }} (recommended)</option>{% else %}<option value="{{ name }}">{{ name | inline_code }}</option>{% endif %}
|
|
31
35
|
{% endfor %}
|
|
32
|
-
</select>
|
|
36
|
+
</select>{% endif %}
|
|
33
37
|
<label for="plan-decision-reason">{{ t('macros.forms.why-required-for-changes-or-rejection') }}</label>
|
|
34
38
|
<textarea id="plan-decision-reason" rows="4"></textarea>
|
|
35
39
|
{% if state.disabled_reason %}<div class="approval-disabled-reason"><p>{{ t('macros.forms.approval-is-held') }} <strong>{{ state.disabled_reason }}</strong>.</p><p>{{ t('macros.forms.answer-the-blockers-then-regenerate') | replace('{ids}', state.blocker_ids | join(', ')) }}</p></div>{% endif %}
|
|
40
|
+
{% endif %}
|
|
41
|
+
</section>
|
|
42
|
+
{%- endmacro %}
|
|
43
|
+
|
|
44
|
+
{% macro direction_selection(state) -%}
|
|
45
|
+
<section id="direction-selection" data-report-section="direction-selection">
|
|
46
|
+
<h2>Select an implementation direction</h2>
|
|
47
|
+
<fieldset><legend>Direction</legend>
|
|
48
|
+
{% for option in state.rankedOptions %}
|
|
49
|
+
<input id="direction-selection-{{ option.id }}" type="radio" name="direction-selection-option" value="{{ option.id }}" data-option-name="{{ option.name }}" required><label for="direction-selection-{{ option.id }}">{{ option.id }} · {{ option.name | inline_code }}{% if option.id == state.recommendedOptionId %} (recommended){% endif %}</label>
|
|
50
|
+
{% endfor %}
|
|
51
|
+
</fieldset>
|
|
52
|
+
<input id="direction-selection-confirmed" type="checkbox" required><label for="direction-selection-confirmed">Confirmed</label>
|
|
53
|
+
<label for="direction-selection-note">Selection note</label><textarea id="direction-selection-note" rows="3"></textarea>
|
|
54
|
+
<label for="direction-selection-constraints">Constraints</label><textarea id="direction-selection-constraints" rows="3"></textarea>
|
|
36
55
|
</section>
|
|
37
56
|
{%- endmacro %}
|
|
38
57
|
|
|
@@ -42,15 +61,27 @@
|
|
|
42
61
|
<h2>{{ t('macros.forms.count-questions-waiting-on-you') | replace('{count}', items | length) }}</h2>
|
|
43
62
|
<p class="clarification-lede">{{ t('macros.forms.the-code-alone-could-not-settle-these-fill-i') }} <strong>{{ t('macros.forms.export-my-answers') }}</strong> {{ t('macros.forms.at-the-foot-of-the-page') }}</p>
|
|
44
63
|
{% for row in items %}
|
|
45
|
-
|
|
64
|
+
{% set is_closed = row.status in ['resolved', 'obsolete'] %}
|
|
65
|
+
{% set approval_context = row.approvalContext | default(None) %}
|
|
66
|
+
<article class="clarification-item" id="id-{{ row.id }}" data-response-id="{{ row.id }}" data-kind="{{ row.kind }}" data-status="{{ row.status }}">
|
|
46
67
|
<p class="eyebrow">{{ row.id }} · {{ row.kind }}</p>
|
|
47
68
|
{{ row.statement | paragraphs }}
|
|
48
69
|
<dl class="clarification-expected"><dt>{{ t('macros.forms.answer-as') }}</dt><dd>{{ row.expectedForm | inline_code }}</dd></dl>
|
|
70
|
+
{% if approval_context %}
|
|
71
|
+
<div class="approval-context" data-approval-classification="{{ approval_context.classification }}">
|
|
72
|
+
<p class="eyebrow">{{ approval_context.classification }}</p>
|
|
73
|
+
<p><strong>{{ t('tasks.implementation-planning.unblock-condition') }}</strong> {{ approval_context.unblockCondition | inline_code }}</p>
|
|
74
|
+
<p><strong>{{ t('tasks.implementation-planning.agent-evidence') }}</strong>
|
|
75
|
+
{% for activity_id in approval_context.activityIds %}<a href="#id-{{ activity_id }}">{{ activity_id }}</a>{% if not loop.last %}, {% endif %}{% endfor %}
|
|
76
|
+
</p>
|
|
77
|
+
</div>
|
|
78
|
+
{% endif %}
|
|
49
79
|
{% if row.options %}
|
|
50
80
|
<ol class="clarification-options">
|
|
51
81
|
{% for option in row.options %}
|
|
52
82
|
<li class="clarification-option{% if option.role == 'recommended' %} is-recommended{% endif %}">
|
|
53
83
|
<p class="clarification-option-answer">{{ option.answer }}{% if option.role == 'recommended' %} <span class="badge">{{ t('macros.forms.recommended') }}</span>{% endif %}</p>
|
|
84
|
+
{% if option.disposition | default(None) %}<p class="clarification-option-disposition"><code>{{ option.disposition }}</code></p>{% endif %}
|
|
54
85
|
<p class="clarification-option-rationale">{{ option.rationale }}</p>
|
|
55
86
|
<dl class="clarification-option-impact">
|
|
56
87
|
<dt>{{ t('macros.forms.scope-impact') }}</dt><dd>{{ option.scopeImpact | join(', ') }}</dd>
|
|
@@ -62,7 +93,14 @@
|
|
|
62
93
|
</ol>
|
|
63
94
|
{% endif %}
|
|
64
95
|
<label for="response-{{ row.id }}">{{ t('macros.forms.your-answer-to-id') | replace('{id}', row.id) }}</label>
|
|
65
|
-
|
|
96
|
+
{% if row.kind == 'decision' and approval_context and row.options %}
|
|
97
|
+
<select id="response-{{ row.id }}" data-response-id="{{ row.id }}"{% if is_closed %} disabled{% endif %}>
|
|
98
|
+
<option value="">{{ t('macros.forms.choose-one') }}</option>
|
|
99
|
+
{% for option in row.options %}<option value="{{ option.answer }}" data-disposition="{{ option.disposition }}"{% if option.role == 'recommended' %} data-recommended="true"{% endif %}{% if row.userInput | default('') == option.answer %} selected{% endif %}>{{ option.answer }}</option>{% endfor %}
|
|
100
|
+
</select>
|
|
101
|
+
{% else %}
|
|
102
|
+
<textarea id="response-{{ row.id }}" data-response-id="{{ row.id }}" rows="4"{% if is_closed %} disabled{% endif %}>{{ row.userInput | default('') }}</textarea>
|
|
103
|
+
{% endif %}
|
|
66
104
|
</article>
|
|
67
105
|
{% endfor %}
|
|
68
106
|
</section>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{% extends "html/base.template.html" %}
|
|
2
|
+
{% from "html/macros/layout.html" import narrative as render_narrative, summary_card, row_key %}
|
|
3
|
+
{% from "html/macros/forms.html" import direction_selection %}
|
|
4
|
+
|
|
5
|
+
{% block human_content %}
|
|
6
|
+
<section data-report-section="selection-status">
|
|
7
|
+
<h2>Selection status</h2>
|
|
8
|
+
<dl><dt>Mode</dt><dd>{{ selection.mode }}</dd><dt>Routing</dt><dd>{{ selection.routing }}</dd></dl>
|
|
9
|
+
{{ render_narrative(narrative.selectionGuidance, "implementationOptionSelection.userNarrative.selectionGuidance") }}
|
|
10
|
+
{% if selection.mode == "preselected-validation" %}
|
|
11
|
+
<h3>Preselected direction</h3>
|
|
12
|
+
<dl><dt>Option ID</dt><dd>{{ selection.preselectedDirection.optionId }}</dd><dt>Direction</dt><dd>{{ selection.preselectedDirection.direction | inline_code }}</dd><dt>Confirmation evidence</dt><dd>{{ selection.preselectedDirection.confirmationEvidence | inline_code }}</dd><dt>Citation</dt><dd>{{ selection.preselectedDirection.citation | inline_code }}</dd></dl>
|
|
13
|
+
{% endif %}
|
|
14
|
+
</section>
|
|
15
|
+
|
|
16
|
+
{% if directionSelection %}{{ direction_selection(directionSelection) }}{% endif %}
|
|
17
|
+
|
|
18
|
+
<section data-report-section="decision-context">
|
|
19
|
+
<h2>{{ t('tasks.implementation-option-selection.original-requirements') }}</h2>
|
|
20
|
+
<p>{{ humanSummary.outcome | inline_code }}</p>
|
|
21
|
+
{{ render_narrative(narrative.comparisonOverview, "implementationOptionSelection.userNarrative.comparisonOverview") }}
|
|
22
|
+
<p data-report-field="implementationOptionSelection.decisionContext.originalRequirementIds"><strong>{{ t('tasks.implementation-option-selection.requirement-ids') }}</strong> {{ selection.decisionContext.originalRequirementIds | join(", ") | inline_code }}</p>
|
|
23
|
+
{% if selection.decisionContext.leadingCauseRefs %}<p><strong>{{ t('tasks.implementation-option-selection.leading-causes') }}</strong> {{ selection.decisionContext.leadingCauseRefs | join(", ") | inline_code }}</p>{% endif %}
|
|
24
|
+
</section>
|
|
25
|
+
|
|
26
|
+
<section data-report-section="ranked-options" data-report-field="implementationOptionSelection.rankedOptions">
|
|
27
|
+
<h2>{{ t('tasks.implementation-option-selection.ranked-options') }}</h2>
|
|
28
|
+
{{ render_narrative(narrative.rankingExplanation, "implementationOptionSelection.userNarrative.rankingExplanation") }}
|
|
29
|
+
<div class="summary-grid">{% for row in selection.rankedOptions %}<article class="summary-card" id="id-{{ row.id }}">
|
|
30
|
+
<p class="eyebrow">#{{ loop.index }} · {{ row.id }}</p>
|
|
31
|
+
<h3>{{ row.name | inline_code }}</h3>
|
|
32
|
+
<p>{{ row.goal | inline_code }}</p>
|
|
33
|
+
<div data-report-field="implementationOptionSelection.rankedOptions.coverageSummary"><p><strong>coveragePercent</strong> <span data-report-metric="coveragePercent">{{ row.coverageSummary.coveragePercent }}</span></p>
|
|
34
|
+
<p><strong>scopePrecisionPercent</strong> <span data-report-metric="scopePrecisionPercent">{{ row.coverageSummary.scopePrecisionPercent }}</span></p></div>
|
|
35
|
+
<p><strong>{{ t('tasks.implementation-option-selection.weighted-score') }}</strong> {{ row.weightedScore }}</p>
|
|
36
|
+
<table data-report-field="implementationOptionSelection.rankedOptions.requirementCoverage"><thead><tr><th>{{ t('tasks.implementation-option-selection.requirement') }}</th><th>{{ t('tasks.implementation-option-selection.satisfaction') }}</th><th>{{ t('tasks.implementation-option-selection.verification') }}</th></tr></thead><tbody>{% for coverage in row.requirementCoverage %}<tr>{{ row_key(pairs=[("ID", coverage.requirementId), ("Status", coverage.status)]) }}<td>{{ coverage.satisfaction | inline_code }}</td><td>{{ coverage.expectedVerification | inline_code }}</td></tr>{% endfor %}</tbody></table>
|
|
37
|
+
</article>{% else %}<p>{{ t('tasks.implementation-option-selection.no-valid-options') }}</p>{% endfor %}</div>
|
|
38
|
+
</section>
|
|
39
|
+
|
|
40
|
+
<section data-report-section="recommendation" data-report-field="implementationOptionSelection.recommendedOptionId">
|
|
41
|
+
<h2>{{ t('tasks.implementation-option-selection.recommended-direction') }}</h2>
|
|
42
|
+
{% if recommendedOption %}{{ summary_card(recommendedOption.id ~ " · " ~ recommendedOption.name, recommendedOption.coreMechanism, "important") }}{% else %}<p>{{ t('tasks.implementation-option-selection.no-recommendation') }}</p>{% endif %}
|
|
43
|
+
</section>
|
|
44
|
+
|
|
45
|
+
<section data-report-section="candidate-audit" data-report-field="implementationOptionSelection.candidateAudit">
|
|
46
|
+
<h2>{{ t('tasks.implementation-option-selection.candidate-audit') }}</h2>
|
|
47
|
+
<table><thead><tr><th>{{ t('tasks.implementation-option-selection.candidate') }}</th><th>{{ t('tasks.implementation-option-selection.disposition') }}</th><th>{{ t('tasks.implementation-option-selection.reason') }}</th><th>coveragePercent</th><th>scopePrecisionPercent</th></tr></thead><tbody>{% for row in selection.candidateAudit %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[("ID", row.id), ("Proposed by", row.proposedBy)]) }}<td>{{ row.disposition }}</td><td>{{ row.reason | inline_code }}</td><td>{{ row.coverageSummary.coveragePercent }}</td><td>{{ row.coverageSummary.scopePrecisionPercent }}</td></tr>{% else %}<tr><td colspan="6">{{ t('tasks.implementation-option-selection.no-audit-entries') }}</td></tr>{% endfor %}</tbody></table>
|
|
48
|
+
</section>
|
|
49
|
+
{% endblock %}
|
|
@@ -4,12 +4,37 @@
|
|
|
4
4
|
{% from "html/macros/visualizations.html" import figure %}
|
|
5
5
|
|
|
6
6
|
{% block human_content %}
|
|
7
|
-
<section data-report-section="planning-goal">
|
|
7
|
+
<section data-report-section="planning-goal" data-report-field="implementationPlanning">
|
|
8
8
|
<h2>{{ t('tasks.implementation-planning.what-the-plan-is-for') }}</h2>
|
|
9
9
|
<p>{{ humanSummary.outcome | inline_code }}</p>
|
|
10
10
|
<div class="summary-grid">{% for reason in humanSummary.whyItMatters %}{{ summary_card("", reason, "important") }}{% endfor %}</div>
|
|
11
11
|
</section>
|
|
12
12
|
|
|
13
|
+
{% if planning.get("planningContract") == "selected-direction" %}
|
|
14
|
+
<section data-report-section="selected-direction" data-report-field="implementationPlanning.selectedDirectionRef">
|
|
15
|
+
<h2>Selected direction</h2>
|
|
16
|
+
<article class="summary-card tone-important"><h3>{{ planning.selectedDirectionRef.optionId | inline_code }}</h3><p><strong>Source report</strong> {{ planning.selectedDirectionRef.sourceReport | inline_code }}</p><p><strong>Snapshot</strong> {{ planning.selectedDirectionRef.snapshotPath | inline_code }}</p></article>
|
|
17
|
+
</section>
|
|
18
|
+
{% if planning.outcome == "plan-ready" %}
|
|
19
|
+
<section data-report-section="direction-realization" data-report-field="implementationPlanning.directionRealization">
|
|
20
|
+
<h2>Direction realization</h2>
|
|
21
|
+
<article class="summary-card"><h3>{{ planning.directionRealization.goal | inline_code }}</h3><p><strong>Core mechanism</strong> {{ planning.directionRealization.coreMechanism | inline_code }}</p><p><strong>Interfaces</strong> {{ planning.directionRealization.interfaces | inline_code }}</p><p><strong>Blast radius</strong> {{ planning.directionRealization.blastRadius | inline_code }}</p><ul>{% for file in planning.directionRealization.fileStructure %}<li id="id-{{ file.id }}">{{ file.action }} <code>{{ file.path }}</code> — {{ file.summary | inline_code }}</li>{% endfor %}</ul></article>
|
|
22
|
+
</section>
|
|
23
|
+
<section data-report-section="plan-coverage" data-report-field="implementationPlanning.coverageSummary">
|
|
24
|
+
<h2>Plan coverage</h2>
|
|
25
|
+
<p><strong>coveragePercent</strong> <span data-report-metric="coveragePercent">{{ planning.coverageSummary.coveragePercent }}</span></p>
|
|
26
|
+
<p><strong>scopePrecisionPercent</strong> <span data-report-metric="scopePrecisionPercent">{{ planning.coverageSummary.scopePrecisionPercent }}</span></p>
|
|
27
|
+
</section>
|
|
28
|
+
{% else %}
|
|
29
|
+
<section data-report-section="direction-invalidation" data-report-field="implementationPlanning.directionInvalidation">
|
|
30
|
+
<h2>Direction invalidated</h2>
|
|
31
|
+
<ul>{% for reason in planning.directionInvalidation.reasons %}<li>{{ reason | inline_code }}</li>{% endfor %}</ul>
|
|
32
|
+
<p><strong>Code evidence</strong></p>
|
|
33
|
+
<ul>{% for evidence in planning.directionInvalidation.codeEvidence %}<li>{{ evidence | inline_code }}</li>{% endfor %}</ul>
|
|
34
|
+
<p data-report-field="implementationPlanning.routing"><strong>Re-entry route</strong> {{ planning.routing | inline_code }}</p>
|
|
35
|
+
</section>
|
|
36
|
+
{% endif %}
|
|
37
|
+
{% else %}
|
|
13
38
|
<section data-report-section="option-comparison">
|
|
14
39
|
<h2>{{ t('tasks.implementation-planning.implementation-options-compared') }}</h2>
|
|
15
40
|
{{ render_narrative(narrative.optionExplanation, "implementationPlanning.userNarrative.optionExplanation") }}
|
|
@@ -22,10 +47,14 @@
|
|
|
22
47
|
{{ render_narrative(narrative.recommendationExplanation, "implementationPlanning.userNarrative.recommendationExplanation") }}
|
|
23
48
|
<article class="summary-card tone-important"><h3>{{ planning.recommendedOption.name | inline_code }}</h3><p>{{ planning.recommendedOption.coreReason | inline_code }}</p><p>{{ planning.recommendedOption.rationale | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.options-not-taken') }}</strong> {{ planning.recommendedOption.rejectedSummary | inline_code }}</p></article>
|
|
24
49
|
</section>
|
|
50
|
+
{% endif %}
|
|
25
51
|
|
|
52
|
+
{% if planning.get("outcome") != "direction-invalidated" %}
|
|
26
53
|
<section data-report-section="stage-map" data-report-field="implementationPlanning.stageMap">
|
|
27
54
|
<h2>{{ t('tasks.implementation-planning.stage-map') }}</h2>
|
|
55
|
+
{% if narrative.get("stageStrategy") %}
|
|
28
56
|
{{ render_narrative(narrative.stageStrategy, "implementationPlanning.userNarrative.stageStrategy") }}
|
|
57
|
+
{% endif %}
|
|
29
58
|
{{ figure(stageFigure) }}
|
|
30
59
|
<div class="summary-grid">{% for row in planning.stages %}<article class="summary-card"><h3>Stage {{ row.stage }} · {{ row.title | inline_code }}</h3><p>{{ row.sliceValue | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.exit-contract') }}</strong> {{ row.acceptance | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.verification') }}</strong> {{ row.stageValidation | inline_code }}</p></article>{% endfor %}</div>
|
|
31
60
|
</section>
|
|
@@ -64,7 +93,11 @@
|
|
|
64
93
|
actually do what the brief asked" is the approval question itself. #}
|
|
65
94
|
<section data-report-section="requirement-coverage" data-report-field="implementationPlanning.requirementCoverage">
|
|
66
95
|
<h2>{{ t('tasks.implementation-planning.how-each-requirement-gets-met') }}</h2>
|
|
96
|
+
{% if planning.get("planningContract") == "selected-direction" %}
|
|
97
|
+
<table><thead><tr><th>Original requirement</th><th>Stages</th><th>Status</th></tr></thead><tbody>{% for row in planning.requirementCoverage %}<tr><td>{{ row.originalRequirementId | inline_code }}</td><td>{{ row.stageRefs | join(", ") | inline_code }}</td><td>{{ row.status | inline_code }}</td></tr>{% endfor %}</tbody></table>
|
|
98
|
+
{% else %}
|
|
67
99
|
<table><thead><tr><th>{{ t('tasks.implementation-planning.requirement') }}</th><th>{{ t('tasks.implementation-planning.body') }}</th><th>{{ t('tasks.implementation-planning.covered-by') }}</th></tr></thead><tbody>{% for row in planning.requirementCoverage %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[("ID", row.id), ("Source", row.source)], status_name="Status", status_raw=row.status, status_text=row.status) }}<td>{{ row.requirement | inline_code }}</td><td>{{ row.coveredBy | inline_code }}</td></tr>{% endfor %}</tbody></table>
|
|
100
|
+
{% endif %}
|
|
68
101
|
</section>
|
|
69
102
|
|
|
70
103
|
{% if planning.get("supersessionLedger") is not none %}
|
|
@@ -90,12 +123,38 @@
|
|
|
90
123
|
|
|
91
124
|
<section data-report-section="decision-drafts" data-report-field="implementationPlanning.decisionDrafts">
|
|
92
125
|
<h2>{{ t('tasks.implementation-planning.decision-record-draft') }}</h2>
|
|
93
|
-
{% for row in planning.decisionDrafts %}
|
|
126
|
+
{% for row in planning.get("decisionDrafts", []) %}
|
|
94
127
|
<article class="summary-card"><h3>{{ row.number }} · {{ row.slug | inline_code }} ({{ row.status | inline_code }})</h3><p><strong>{{ t('tasks.implementation-planning.context') }}</strong> — {{ row.context | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.decision') }}</strong> — {{ row.decision | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.result') }}</strong> — {{ row.consequences | inline_code }}</p></article>
|
|
95
128
|
{% else %}<p>{{ t('tasks.implementation-planning.there-is-no-decision-draft-to-record') }}</p>{% endfor %}
|
|
96
129
|
{% if planning.get("skippedAdrCandidates") %}<h3>{{ t('tasks.implementation-planning.what-was-deliberately-not-recorded') }}</h3>
|
|
97
130
|
<table data-report-field="implementationPlanning.skippedAdrCandidates"><thead><tr><th>{{ t('tasks.implementation-planning.topic') }}</th><th>{{ t('tasks.implementation-planning.why') }}</th></tr></thead><tbody>{% for row in planning.skippedAdrCandidates %}<tr><td>{{ row.topic | inline_code }}</td><td>{{ row.reason | inline_code }}</td></tr>{% endfor %}</tbody></table>{% endif %}
|
|
98
131
|
</section>
|
|
132
|
+
{% endif %}
|
|
133
|
+
|
|
134
|
+
{% if agentActivities %}
|
|
135
|
+
<section data-report-section="agent-activity">
|
|
136
|
+
<h2>{{ t('tasks.implementation-planning.what-each-agent-did') }}</h2>
|
|
137
|
+
<div class="activity-list">
|
|
138
|
+
{% for row in agentActivities %}
|
|
139
|
+
<article class="activity-card" id="id-{{ row.activityId }}">
|
|
140
|
+
<p class="eyebrow">{{ row.activityId }} · {{ row.agent }}</p>
|
|
141
|
+
<h3>{{ row.summary | inline_code }}</h3>
|
|
142
|
+
<p>{{ t('tasks.implementation-planning.result') }}: {{ row.outcome | inline_code }}</p>
|
|
143
|
+
<details>
|
|
144
|
+
<summary>{{ t('tasks.implementation-planning.commands-and-evidence') }}</summary>
|
|
145
|
+
<p><code>{{ row.kind }}</code></p>
|
|
146
|
+
{% if row.planItemIds %}<p>{{ row.planItemIds | join(', ') | inline_code }}</p>{% endif %}
|
|
147
|
+
{% for command in row.commands %}
|
|
148
|
+
<p><code>{{ command.command }}</code> · exit {{ command.exitCode }} · {{ command.outputSummary | inline_code }}</p>
|
|
149
|
+
{% endfor %}
|
|
150
|
+
{% if row.evidenceRefs %}<p>{{ row.evidenceRefs | join(', ') | inline_code }}</p>{% endif %}
|
|
151
|
+
{% if row.resultPath %}<p><code>{{ row.resultPath }}</code></p>{% endif %}
|
|
152
|
+
</details>
|
|
153
|
+
</article>
|
|
154
|
+
{% endfor %}
|
|
155
|
+
</div>
|
|
156
|
+
</section>
|
|
157
|
+
{% endif %}
|
|
99
158
|
|
|
100
159
|
<section data-report-section="open-decisions">
|
|
101
160
|
<h2>{{ t('tasks.implementation-planning.open-decisions-before-approval') }}</h2>
|
|
@@ -60,6 +60,10 @@
|
|
|
60
60
|
"readerSummary": "The shortest reader path: what was decided, what a human must do next, and which audit details can wait until a deeper review.",
|
|
61
61
|
"endStateCoverage": "One row per end-state id the brief pinned, and how this phase accounted for it. A row that is not `addressed` must say why."
|
|
62
62
|
},
|
|
63
|
+
"agentActivity": {
|
|
64
|
+
"heading": "Agent Activity Audit",
|
|
65
|
+
"intro": "Structured lead activity projected from this run's canonical event log."
|
|
66
|
+
},
|
|
63
67
|
"analysis": {
|
|
64
68
|
"basisIntro": "Immutable run snapshot, bounded scan scope, current-code facts, inferences, unknowns, and review disposition for this analysis.",
|
|
65
69
|
"projectIntro": "Project components, boundaries, entry points, dependencies, stores, external systems, and the shallow feature index.",
|
|
@@ -134,6 +138,19 @@
|
|
|
134
138
|
"singleRoundPrefix": "Single round —",
|
|
135
139
|
"noRoundsNote": "No reverify rounds executed (all findings reached consensus at grouping)."
|
|
136
140
|
},
|
|
141
|
+
"implementationOptionSelection": {
|
|
142
|
+
"decisionContext": "Original Requirement Coverage",
|
|
143
|
+
"evaluationCriteria": "Evaluation Criteria",
|
|
144
|
+
"candidateAudit": "Candidate Audit",
|
|
145
|
+
"rankedOptions": "Ranked Options",
|
|
146
|
+
"recommendedOptionId": "Recommended Option",
|
|
147
|
+
"requirementCoverage": "Requirement Coverage",
|
|
148
|
+
"scopeCommitments": "Scope Commitments",
|
|
149
|
+
"coverageSummary": "Coverage Summary",
|
|
150
|
+
"criterionScores": "Criterion Scores",
|
|
151
|
+
"feasibilityVotes": "Feasibility Votes",
|
|
152
|
+
"planningInvariants": "Planning Invariants"
|
|
153
|
+
},
|
|
137
154
|
"implementationPlanning": {
|
|
138
155
|
"planBodyGateLegend": "Gate values — `passed`: agreed, no dissent · `passed-with-dissent`: a minority dissent remains but the gate passes (a majority dissent would block approval) · `blocked-by-disagreement`: majority dissent blocks approval · `aborted-non-result`: verification itself produced no result.",
|
|
139
156
|
"planBodyBlockedByLegend": "Which input blocked the gate — `majority-disagree`: a worker majority dissent · `coverage-gap`: a Requirement Coverage gap / blocked row, independent of worker votes · `non-result`: verification produced no result. Absent means nothing blocked.",
|
|
@@ -28,10 +28,12 @@ taskType: "{{FM_TASK_TYPE}}"
|
|
|
28
28
|
|
|
29
29
|
- Approved plan path: `runs/implementation-planning/<run-id>/reports/final-report.md`
|
|
30
30
|
- Approval evidence (quoted exactly from the plan's YAML frontmatter, e.g. `approved: true`):
|
|
31
|
-
-
|
|
31
|
+
- Planning contract: `selected-direction` or `legacy-option-candidates`
|
|
32
|
+
- Selected-direction reference and snapshot digest (required for `selected-direction`):
|
|
33
|
+
- Legacy implementation option name (legacy plans only):
|
|
32
34
|
- Plan's bite-sized step list (paste or reference by anchor):
|
|
33
35
|
|
|
34
|
-
> The run MUST refuse to start (status `contract-violated`) if the approved plan path does not exist or does not contain an explicit user approval marker.
|
|
36
|
+
> The run MUST refuse to start (status `contract-violated`) if the approved plan path does not exist or does not contain an explicit user approval marker. A selected-direction plan also requires `outcome: plan-ready`, exact plan coverage, and a valid selected-direction reference. It rejects `--implementation-option`; an existing approved legacy plan keeps that option-selection path.
|
|
35
37
|
|
|
36
38
|
## Scope From Plan
|
|
37
39
|
|
|
@@ -55,8 +55,8 @@ taskType: "{{FM_TASK_TYPE}}"
|
|
|
55
55
|
|
|
56
56
|
## Planning Concerns
|
|
57
57
|
|
|
58
|
-
-
|
|
59
|
-
-
|
|
58
|
+
- Selected direction realization concerns:
|
|
59
|
+
- Legacy-only implementation options and trade-offs:
|
|
60
60
|
- Dependencies or migrations:
|
|
61
61
|
- Validation approach:
|
|
62
62
|
- Rollback approach:
|
|
@@ -76,6 +76,14 @@ taskType: "{{FM_TASK_TYPE}}"
|
|
|
76
76
|
|
|
77
77
|
## Questions for Analysers
|
|
78
78
|
|
|
79
|
+
When `selected-direction.json` is present:
|
|
80
|
+
|
|
81
|
+
1. Which files, interfaces, and stages realize the snapshot without changing its direction?
|
|
82
|
+
2. How does every file, stage, validation, and rollback link to the original requirements?
|
|
83
|
+
3. Does current evidence require `direction-invalidated`?
|
|
84
|
+
|
|
85
|
+
Legacy candidate-comparison questions apply only when the snapshot is absent:
|
|
86
|
+
|
|
79
87
|
1. What is the safest implementation direction?
|
|
80
88
|
2. What are the main trade-offs between options?
|
|
81
89
|
3. What should be validated before, during, and after implementation?
|
|
@@ -84,7 +92,13 @@ taskType: "{{FM_TASK_TYPE}}"
|
|
|
84
92
|
|
|
85
93
|
## Required Plan Deliverable
|
|
86
94
|
|
|
87
|
-
|
|
95
|
+
### Selected-direction input contract
|
|
96
|
+
|
|
97
|
+
When `instruction-set/selected-direction.json` is present, read it and the original requirements first. Concretize only the selected direction's files, interfaces, stages, validation, and rollback. Link every file and stage bidirectionally to the original requirements. If code evidence invalidates the direction, return `direction-invalidated` and stop. Candidate comparison and user selection are outside this contract.
|
|
98
|
+
|
|
99
|
+
### Legacy candidate-comparison input contract
|
|
100
|
+
|
|
101
|
+
When no selected-direction snapshot exists on a compatibility rerun, the final report retains every section below.
|
|
88
102
|
|
|
89
103
|
1. **Option Candidates** — at least two viable options, each with the exact list of files to create or modify and the principal change per file.
|
|
90
104
|
2. **Trade-off Matrix** — comparison of the candidates across complexity, risk, reversibility, performance impact, scope, and required test surface.
|
|
@@ -94,7 +108,7 @@ The final report of an `implementation-planning` run MUST contain every section
|
|
|
94
108
|
6. **Validation Checklist** — pre-execution, mid-execution, and post-execution checks (commands, expected outputs, observability points).
|
|
95
109
|
7. **Rollback Strategy** — exact reverse procedure or compensating action for each significant step.
|
|
96
110
|
8. **Scope Boundary** — an explicit list of adjacent areas, files, refactors, or quality improvements that this plan **does NOT** cover, each with a one-line reason (deferred, separate owner, separate decision, out of requirement). Any item the analysers were tempted to fold in but chose to exclude MUST appear here. An empty list is allowed only when the analysers explicitly state "no adjacent expansion was considered" — silence is not acceptable.
|
|
97
|
-
9. **Approval frontmatter** — the final report's YAML frontmatter MUST emit `approved: false` and `implementation-option:`. Do NOT create a `User Approval Request` body block; the next `implementation` run reads only the frontmatter gate.
|
|
111
|
+
9. **Approval frontmatter** — the legacy final report's YAML frontmatter MUST emit `approved: false` and `implementation-option:`. Do NOT create a `User Approval Request` body block; the next `implementation` run reads only the frontmatter gate.
|
|
98
112
|
|
|
99
113
|
## Phase Boundary
|
|
100
114
|
|
|
@@ -69,7 +69,7 @@ Workers MUST read the resolved values from the log the lead points to via the
|
|
|
69
69
|
|
|
70
70
|
1. Within the resolved scope and priority lenses, what are the highest-impact improvement candidates?
|
|
71
71
|
2. Which candidates have full cross-worker consensus, and which are worker-unique?
|
|
72
|
-
3. For each candidate, what is the safest next phase (requirements-discovery / implementation-
|
|
72
|
+
3. For each candidate, what is the safest next phase (requirements-discovery / implementation-option-selection / error-analysis)?
|
|
73
73
|
4. Which candidates would you intentionally exclude despite being technically valid, and why?
|
|
74
74
|
5. Are there any signals that the scope itself is mis-defined (and should be re-narrowed before discovery proceeds)?
|
|
75
75
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{% import "md/macros/sections.md" as s with context -%}
|
|
2
|
+
{# Coverage denominator and every selectable direction precede the recommendation. #}
|
|
3
|
+
{{ s.section("implementationOptionSelection.decisionContext", "Original Requirement Coverage") }}
|
|
4
|
+
|
|
5
|
+
Coverage metrics: `coveragePercent` and `scopePrecisionPercent`.
|
|
6
|
+
|
|
7
|
+
{{ s.section("implementationOptionSelection.rankedOptions", "Ranked Options") }}
|
|
8
|
+
{{ s.section("implementationOptionSelection.recommendedOptionId", "Recommended Option") }}
|
|
9
|
+
{{ s.section("implementationOptionSelection.evaluationCriteria", "Evaluation Criteria") }}
|
|
10
|
+
{{ s.section("implementationOptionSelection.candidateAudit", "Candidate Audit") }}
|
|
11
|
+
{{ s.section("implementationOptionSelection.preselectedDirection", "Preselected Direction") }}
|
|
12
|
+
{{ s.section("implementationOptionSelection.routing", "Routing") }}
|
|
13
|
+
{{ md_rest("implementationOptionSelection", 3) }}
|