okstra 0.185.0 → 0.186.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.
Files changed (41) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/chat/chat.mjs +62 -15
  3. package/dist/commands/chat/chat.mjs.map +1 -1
  4. package/docs/architecture.md +1 -1
  5. package/docs/cli.md +2 -2
  6. package/docs/for-ai/skills/okstra-chat.md +7 -1
  7. package/docs/project-structure-overview.md +1 -1
  8. package/package.json +1 -1
  9. package/runtime/BUILD.json +2 -2
  10. package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
  11. package/runtime/prompts/lead/plan-body-verification.md +8 -7
  12. package/runtime/prompts/profiles/implementation-planning.md +3 -3
  13. package/runtime/python/okstra_ctl/cmux.py +63 -35
  14. package/runtime/python/okstra_ctl/incremental_carry.py +149 -5
  15. package/runtime/python/okstra_ctl/incremental_scope.py +25 -3
  16. package/runtime/python/okstra_ctl/plan_items.py +40 -4
  17. package/runtime/python/okstra_ctl/report_html/common.py +86 -11
  18. package/runtime/python/okstra_ctl/report_html/filters.py +27 -10
  19. package/runtime/python/okstra_ctl/report_html/render.py +1 -0
  20. package/runtime/python/okstra_ctl/report_html/report_index.py +5 -1
  21. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +1 -1
  22. package/runtime/skills/okstra-chat/SKILL.md +25 -13
  23. package/runtime/templates/reports/html/assets/base.css +48 -3
  24. package/runtime/templates/reports/html/base.template.html +7 -4
  25. package/runtime/templates/reports/html/i18n/en.json +86 -8
  26. package/runtime/templates/reports/html/i18n/ko.json +86 -8
  27. package/runtime/templates/reports/html/macros/forms.html +74 -55
  28. package/runtime/templates/reports/html/macros/layout.html +2 -2
  29. package/runtime/templates/reports/html/macros/visualizations.html +1 -1
  30. package/runtime/templates/reports/html/tasks/change-impact-analysis.template.html +2 -2
  31. package/runtime/templates/reports/html/tasks/error-analysis.template.html +3 -3
  32. package/runtime/templates/reports/html/tasks/feature-analysis.template.html +4 -4
  33. package/runtime/templates/reports/html/tasks/final-verification.template.html +3 -3
  34. package/runtime/templates/reports/html/tasks/implementation-option-selection.template.html +9 -9
  35. package/runtime/templates/reports/html/tasks/implementation-planning.template.html +20 -18
  36. package/runtime/templates/reports/html/tasks/implementation.template.html +3 -3
  37. package/runtime/templates/reports/html/tasks/improvement-discovery.template.html +3 -3
  38. package/runtime/templates/reports/html/tasks/project-analysis.template.html +10 -10
  39. package/runtime/templates/reports/html/tasks/release-handoff.template.html +2 -2
  40. package/runtime/templates/reports/html/tasks/requirements-discovery.template.html +4 -4
  41. package/runtime/validators/validate-run.py +19 -19
@@ -13,7 +13,7 @@
13
13
  <section data-report-section="affected-and-unaffected">
14
14
  <h2>{{ t('tasks.change-impact-analysis.what-the-change-touches-and-where-it-stops') }}</h2>
15
15
  {{ render_narrative(narrative.impactExplanation, "changeImpactAnalysis.userNarrative.impactExplanation") }}
16
- <div data-report-field="changeImpactAnalysis.impactItems"><h3>{{ t('tasks.change-impact-analysis.what-it-touches') }}</h3>{% for row in change.impactItems %}{{ summary_card(row.id ~ " · " ~ (row.target | inline_code), row.impactKind ~ " / Impact " ~ row.level ~ " / Confidence " ~ row.confidence, anchor=row.id) }}{% endfor %}</div>
16
+ <div data-report-field="changeImpactAnalysis.impactItems"><h3>{{ t('tasks.change-impact-analysis.what-it-touches') }}</h3>{% for row in change.impactItems %}{{ summary_card(row.id ~ " · " ~ row.target, row.impactKind ~ " / " ~ t('macros.layout.impact') ~ " " ~ row.level ~ " / " ~ t('macros.layout.confidence') ~ " " ~ row.confidence, anchor=row.id) }}{% endfor %}</div>
17
17
  <div data-report-field="changeImpactAnalysis.unaffectedBoundaries"><h3>{{ t('tasks.change-impact-analysis.where-the-change-stops') }}</h3>{{ render_narrative(narrative.unaffectedExplanation, "changeImpactAnalysis.userNarrative.unaffectedExplanation") }}<ul>{% for row in change.unaffectedBoundaries %}<li>{{ row.summary | inline_code }}</li>{% endfor %}</ul></div>
18
18
  </section>
19
19
 
@@ -33,7 +33,7 @@
33
33
  <section data-report-section="planning-readiness" data-report-field="changeImpactAnalysis.planningInputs">
34
34
  <h2>{{ t('tasks.change-impact-analysis.plan-readiness') }}</h2>
35
35
  {{ render_narrative(narrative.planningReadiness, "changeImpactAnalysis.userNarrative.planningReadiness") }}
36
- <ul>{% for row in change.planningInputs %}<li>{{ row.constraint | inline_code }}{% if row.unknown %} — Unsettled{% endif %}</li>{% endfor %}</ul>
36
+ <ul>{% for row in change.planningInputs %}<li>{{ row.constraint | inline_code }}{% if row.unknown %} — {{ t('tasks.change-impact-analysis.unsettled') }}{% endif %}</li>{% endfor %}</ul>
37
37
  </section>
38
38
 
39
39
  <section data-report-section="preserved-behaviors" data-report-field="changeImpactAnalysis.preservedBehaviors">
@@ -21,19 +21,19 @@
21
21
  <h2>{{ t('tasks.error-analysis.cause-candidates') }}</h2>
22
22
  {{ render_narrative(narrative.causeExplanation, "errorAnalysis.userNarrative.causeExplanation") }}
23
23
  {{ figure(causeFigure) }}
24
- <div class="summary-grid">{% for row in error.causeCandidates %}<article class="summary-card tone-{{ row.confidence }}" id="id-{{ row.id }}"><p class="eyebrow">{{ row.id }} · Confidence {{ row.confidence }}</p><h3>{{ row.statement | inline_code }}</h3><p class="evidence-refs">Supporting evidence: {{ row.supportingEvidence | evidence_refs }}</p></article>{% else %}<p>{{ t('tasks.error-analysis.no-cause-candidate-has-been-established-yet') }}</p>{% endfor %}</div>
24
+ <div class="summary-grid">{% for row in error.causeCandidates %}<article class="summary-card tone-{{ row.confidence }}" id="id-{{ row.id }}"><p class="eyebrow">{{ row.id | inline_code }} · {{ t('macros.layout.confidence') }} {{ row.confidence }}</p><h3>{{ row.statement | inline_code }}</h3><p class="evidence-refs">{{ t('macros.layout.supporting-evidence') }} {{ row.supportingEvidence | evidence_refs }}</p></article>{% else %}<p>{{ t('tasks.error-analysis.no-cause-candidate-has-been-established-yet') }}</p>{% endfor %}</div>
25
25
  </section>
26
26
 
27
27
  <section data-report-section="uncertainty">
28
28
  <h2>{{ t('tasks.error-analysis.what-cannot-be-settled-yet') }}</h2>
29
29
  {{ render_narrative(narrative.uncertaintyExplanation, "errorAnalysis.userNarrative.uncertaintyExplanation") }}
30
- {% for row in error.causeCandidates %}<article class="summary-card" id="id-{{ row.id }}-detail"><h3>{{ row.id }}</h3><p data-report-field="errorAnalysis.causeCandidates.confidence"><strong>{{ t('tasks.error-analysis.confidence-now') }}</strong> {{ row.confidence }}</p><p data-report-field="errorAnalysis.causeCandidates.falsifyingEvidenceChecked"><strong>{{ t('tasks.error-analysis.disproof-attempted') }}</strong> {{ row.falsifyingEvidenceChecked | join(', ') | inline_code }}</p><p data-report-field="errorAnalysis.causeCandidates.disproveWith"><strong>{{ t('tasks.error-analysis.how-to-disprove-this') }}</strong> {{ row.disproveWith | inline_code }}</p></article>{% endfor %}
30
+ {% for row in error.causeCandidates %}<article class="summary-card" id="id-{{ row.id }}-detail"><h3>{{ row.id | inline_code }}</h3><p data-report-field="errorAnalysis.causeCandidates.confidence"><strong>{{ t('tasks.error-analysis.confidence-now') }}</strong> {{ row.confidence }}</p><p data-report-field="errorAnalysis.causeCandidates.falsifyingEvidenceChecked"><strong>{{ t('tasks.error-analysis.disproof-attempted') }}</strong> {{ row.falsifyingEvidenceChecked | join(', ') | inline_code }}</p><p data-report-field="errorAnalysis.causeCandidates.disproveWith"><strong>{{ t('tasks.error-analysis.how-to-disprove-this') }}</strong> {{ row.disproveWith | inline_code }}</p></article>{% endfor %}
31
31
  </section>
32
32
 
33
33
  <section data-report-section="next-diagnostic">
34
34
  <h2>{{ t('tasks.error-analysis.the-one-diagnostic-to-run-next') }}</h2>
35
35
  {{ render_narrative(narrative.diagnosticGuidance, "errorAnalysis.userNarrative.diagnosticGuidance") }}
36
- {{ summary_card("Run", error.nextDiagnostic.action, "important") }}
36
+ {{ summary_card(t('tasks.error-analysis.run'), error.nextDiagnostic.action, "important") }}
37
37
  <p><strong>{{ t('tasks.error-analysis.signal-to-check') }}</strong> {{ error.nextDiagnostic.confirmingSignal | inline_code }}</p>
38
38
  <p><strong>{{ t('tasks.error-analysis.signal-that-rejects-it') }}</strong> {{ error.nextDiagnostic.rejectingSignal | inline_code }}</p>
39
39
  </section>
@@ -15,25 +15,25 @@
15
15
  <h2>{{ t('tasks.feature-analysis.how-a-user-moves-through-it') }}</h2>
16
16
  {{ render_narrative(narrative.flowExplanation, "featureAnalysis.userNarrative.flowExplanation") }}
17
17
  {{ figure(flowFigure) }}
18
- <div class="summary-grid">{% for row in feature.flows %}<article class="summary-card" id="id-{{ row.id }}" data-flow-kind="{{ 'alternate' if row.kind == 'alternative' else row.kind }}"><p class="eyebrow">{{ row.id }} · {{ row.kind }}</p><ol>{% for step in row.steps %}<li>{{ step.action | inline_code }}</li>{% endfor %}</ol></article>{% endfor %}</div>
18
+ <div class="summary-grid">{% for row in feature.flows %}<article class="summary-card" id="id-{{ row.id }}" data-flow-kind="{{ 'alternate' if row.kind == 'alternative' else row.kind }}"><p class="eyebrow">{{ row.id | inline_code }} · {{ row.kind }}</p><ol>{% for step in row.steps %}<li>{{ step.action | inline_code }}</li>{% endfor %}</ol></article>{% endfor %}</div>
19
19
  </section>
20
20
 
21
21
  <section data-report-section="rules-and-state">
22
22
  <h2>{{ t('tasks.feature-analysis.rules-and-state-changes') }}</h2>
23
23
  {{ render_narrative(narrative.rulesAndStateExplanation, "featureAnalysis.userNarrative.rulesAndStateExplanation") }}
24
- <div data-report-field="featureAnalysis.domainRules"><h3>{{ t('tasks.feature-analysis.domain-rules') }}</h3>{% for row in feature.domainRules %}{{ summary_card(row.id ~ " · " ~ (row.condition | inline_code), row.outcome, anchor=row.id) }}{% endfor %}</div>
24
+ <div data-report-field="featureAnalysis.domainRules"><h3>{{ t('tasks.feature-analysis.domain-rules') }}</h3>{% for row in feature.domainRules %}{{ summary_card(row.id ~ " · " ~ row.condition, row.outcome, anchor=row.id) }}{% endfor %}</div>
25
25
  <div data-report-field="featureAnalysis.stateChanges"><h3>{{ t('tasks.feature-analysis.state-change') }}</h3>{% for row in feature.stateChanges %}{{ summary_card(row.id ~ " · " ~ row.field, row.change, anchor=row.id) }}{% endfor %}</div>
26
26
  </section>
27
27
 
28
28
  <section data-report-section="external-interactions" data-report-field="featureAnalysis.externalInteractions">
29
29
  <h2>{{ t('tasks.feature-analysis.external-interactions') }}</h2>
30
- {% for row in feature.externalInteractions %}{{ summary_card(row.target | inline_code, row.input ~ " → " ~ row.output ~ ". On failure: " ~ row.failureHandling) }}{% endfor %}
30
+ {% for row in feature.externalInteractions %}{{ summary_card(row.target, row.input ~ " → " ~ row.output ~ ". " ~ t('tasks.feature-analysis.on-failure') ~ " " ~ row.failureHandling) }}{% endfor %}
31
31
  </section>
32
32
 
33
33
  <section data-report-section="test-gaps" data-report-field="featureAnalysis.testCoverage">
34
34
  <h2>{{ t('tasks.feature-analysis.tests-and-gaps') }}</h2>
35
35
  {{ render_narrative(narrative.testGapExplanation, "featureAnalysis.userNarrative.testGapExplanation") }}
36
- {% for row in feature.testCoverage %}{{ summary_card(row.id, "Tests: " ~ (row.testPaths | join(', ')) ~ "; Gaps: " ~ ((row.gaps | join(', ')) or 'none'), anchor=row.id) }}{% endfor %}
36
+ {% for row in feature.testCoverage %}{{ summary_card(row.id, t('tasks.feature-analysis.tests') ~ " " ~ (row.testPaths | join(', ')) ~ "; " ~ t('tasks.feature-analysis.gaps') ~ " " ~ ((row.gaps | join(', ')) or t('macros.layout.none')), anchor=row.id) }}{% endfor %}
37
37
  </section>
38
38
 
39
39
  <section data-report-section="preconditions" data-report-field="featureAnalysis.preconditions">
@@ -17,8 +17,8 @@
17
17
 
18
18
  <section data-report-section="added-surface" data-report-field="finalVerification.addedSurfaceAudit">
19
19
  <h2>{{ t('tasks.final-verification.what-the-change-added') }}</h2>
20
- <div class="table-scroll"><table><thead><tr><th>ID</th><th>{{ t('tasks.final-verification.what-the-change-added') }}</th><th>{{ t('tasks.final-verification.callers') }}</th><th>{{ t('tasks.final-verification.traced-to') }}</th><th>{{ t('tasks.final-verification.result-per-requirement') }}</th></tr></thead>
21
- <tbody>{% for row in final.addedSurfaceAudit %}<tr id="id-{{ row.id }}"><td>{{ row.id }}</td><td>{{ row.surface | inline_code }}</td><td>{{ row.callers | inline_code }}</td><td>{{ row.requirement | inline_code }}</td><td><span class="status status-{{ row.disposition }}">{{ row.disposition }}</span> {{ row.note | inline_code }}</td></tr>{% else %}<tr><td colspan="5">{{ t('tasks.final-verification.the-change-added-no-new-surface') }}</td></tr>{% endfor %}</tbody></table></div>
20
+ <div class="table-scroll"><table><thead><tr><th>{{ t('macros.layout.id') }}</th><th>{{ t('tasks.final-verification.what-the-change-added') }}</th><th>{{ t('tasks.final-verification.callers') }}</th><th>{{ t('tasks.final-verification.traced-to') }}</th><th>{{ t('tasks.final-verification.result-per-requirement') }}</th></tr></thead>
21
+ <tbody>{% for row in final.addedSurfaceAudit %}<tr id="id-{{ row.id }}"><td>{{ row.id | inline_code }}</td><td>{{ row.surface | inline_code }}</td><td>{{ row.callers | inline_code }}</td><td>{{ row.requirement | inline_code }}</td><td><span class="status status-{{ row.disposition }}">{{ row.disposition }}</span> {{ row.note | inline_code }}</td></tr>{% else %}<tr><td colspan="5">{{ t('tasks.final-verification.the-change-added-no-new-surface') }}</td></tr>{% endfor %}</tbody></table></div>
22
22
  </section>
23
23
 
24
24
  <section data-report-section="blockers" data-report-field="finalVerification.acceptanceBlockers">
@@ -29,7 +29,7 @@
29
29
 
30
30
  <section data-report-section="residual-risk" data-report-field="finalVerification.residualRisk">
31
31
  <h2>{{ t('tasks.final-verification.residual-risk') }}</h2>
32
- <div class="summary-grid">{% for row in final.residualRisk %}<article class="summary-card" id="id-{{ row.id }}"><h3>{{ row.id }}</h3><p>{{ row.item | inline_code }}</p><p><strong>{{ t('tasks.final-verification.owner') }}</strong> {{ row.owner | inline_code }}</p><p><strong>{{ t('tasks.final-verification.escalation-condition') }}</strong> {{ row.escalationTrigger | inline_code }}</p></article>{% else %}<p>{{ t('tasks.final-verification.no-residual-risk-was-recorded') }}</p>{% endfor %}</div>
32
+ <div class="summary-grid">{% for row in final.residualRisk %}<article class="summary-card" id="id-{{ row.id }}"><h3>{{ row.id | inline_code }}</h3><p>{{ row.item | inline_code }}</p><p><strong>{{ t('tasks.final-verification.owner') }}</strong> {{ row.owner | inline_code }}</p><p><strong>{{ t('tasks.final-verification.escalation-condition') }}</strong> {{ row.escalationTrigger | inline_code }}</p></article>{% else %}<p>{{ t('tasks.final-verification.no-residual-risk-was-recorded') }}</p>{% endfor %}</div>
33
33
  </section>
34
34
 
35
35
  <section data-report-section="manual-results" data-report-field="finalVerification.manualUserTest">
@@ -4,12 +4,12 @@
4
4
 
5
5
  {% block human_content %}
6
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>
7
+ <h2>{{ t('tasks.implementation-option-selection.selection-status') }}</h2>
8
+ <dl><dt>{{ t('tasks.implementation-option-selection.mode') }}</dt><dd>{{ selection.mode }}</dd><dt>{{ t('tasks.implementation-option-selection.routing') }}</dt><dd>{{ selection.routing }}</dd></dl>
9
9
  {{ render_narrative(narrative.selectionGuidance, "implementationOptionSelection.userNarrative.selectionGuidance") }}
10
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>
11
+ <h3>{{ t('tasks.implementation-option-selection.preselected-direction') }}</h3>
12
+ <dl><dt>{{ t('tasks.implementation-option-selection.option-id') }}</dt><dd>{{ selection.preselectedDirection.optionId | inline_code }}</dd><dt>{{ t('tasks.implementation-option-selection.direction') }}</dt><dd>{{ selection.preselectedDirection.direction | inline_code }}</dd><dt>{{ t('tasks.implementation-option-selection.confirmation-evidence') }}</dt><dd>{{ selection.preselectedDirection.confirmationEvidence | inline_code }}</dd><dt>{{ t('tasks.implementation-option-selection.citation') }}</dt><dd>{{ selection.preselectedDirection.citation | inline_code }}</dd></dl>
13
13
  {% endif %}
14
14
  </section>
15
15
 
@@ -27,13 +27,13 @@
27
27
  <h2>{{ t('tasks.implementation-option-selection.ranked-options') }}</h2>
28
28
  {{ render_narrative(narrative.rankingExplanation, "implementationOptionSelection.userNarrative.rankingExplanation") }}
29
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>
30
+ <p class="eyebrow">#{{ loop.index }} · {{ row.id | inline_code }}</p>
31
31
  <h3>{{ row.name | inline_code }}</h3>
32
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>
33
+ <div data-report-field="implementationOptionSelection.rankedOptions.coverageSummary"><p><strong>{{ t('macros.layout.coverage-percent') }}</strong> <span data-report-metric="coveragePercent">{{ row.coverageSummary.coveragePercent }}</span></p>
34
+ <p><strong>{{ t('macros.layout.scope-precision-percent') }}</strong> <span data-report-metric="scopePrecisionPercent">{{ row.coverageSummary.scopePrecisionPercent }}</span></p></div>
35
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>
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=[(t('macros.layout.id'), coverage.requirementId), (t('macros.layout.status'), coverage.status)]) }}<td>{{ coverage.satisfaction | inline_code }}</td><td>{{ coverage.expectedVerification | inline_code }}</td></tr>{% endfor %}</tbody></table>
37
37
  </article>{% else %}<p>{{ t('tasks.implementation-option-selection.no-valid-options') }}</p>{% endfor %}</div>
38
38
  </section>
39
39
 
@@ -44,6 +44,6 @@
44
44
 
45
45
  <section data-report-section="candidate-audit" data-report-field="implementationOptionSelection.candidateAudit">
46
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>
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>{{ t('macros.layout.coverage-percent') }}</th><th>{{ t('macros.layout.scope-precision-percent') }}</th></tr></thead><tbody>{% for row in selection.candidateAudit %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[(t('macros.layout.id'), row.id), (t('macros.layout.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
48
  </section>
49
49
  {% endblock %}
@@ -12,26 +12,26 @@
12
12
 
13
13
  {% if planning.get("planningContract") == "selected-direction" %}
14
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>
15
+ <h2>{{ t('tasks.implementation-planning.selected-direction') }}</h2>
16
+ <article class="summary-card tone-important"><h3>{{ planning.selectedDirectionRef.optionId | inline_code }}</h3><p><strong>{{ t('tasks.implementation-planning.source-report') }}</strong> {{ planning.selectedDirectionRef.sourceReport | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.snapshot') }}</strong> {{ planning.selectedDirectionRef.snapshotPath | inline_code }}</p></article>
17
17
  </section>
18
18
  {% if planning.outcome == "plan-ready" %}
19
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>
20
+ <h2>{{ t('tasks.implementation-planning.direction-realization') }}</h2>
21
+ <article class="summary-card"><h3>{{ planning.directionRealization.goal | inline_code }}</h3><p><strong>{{ t('tasks.implementation-planning.core-mechanism') }}</strong> {{ planning.directionRealization.coreMechanism | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.interfaces') }}</strong> {{ planning.directionRealization.interfaces | inline_code }}</p><p><strong>{{ t('tasks.implementation-planning.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
22
  </section>
23
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>
24
+ <h2>{{ t('tasks.implementation-planning.plan-coverage') }}</h2>
25
+ <p><strong>{{ t('tasks.implementation-planning.coverage-percent') }}</strong> <span data-report-metric="coveragePercent">{{ planning.coverageSummary.coveragePercent }}</span></p>
26
+ <p><strong>{{ t('tasks.implementation-planning.scope-precision-percent') }}</strong> <span data-report-metric="scopePrecisionPercent">{{ planning.coverageSummary.scopePrecisionPercent }}</span></p>
27
27
  </section>
28
28
  {% else %}
29
29
  <section data-report-section="direction-invalidation" data-report-field="implementationPlanning.directionInvalidation">
30
- <h2>Direction invalidated</h2>
30
+ <h2>{{ t('tasks.implementation-planning.direction-invalidated') }}</h2>
31
31
  <ul>{% for reason in planning.directionInvalidation.reasons %}<li>{{ reason | inline_code }}</li>{% endfor %}</ul>
32
- <p><strong>Code evidence</strong></p>
32
+ <p><strong>{{ t('tasks.implementation-planning.code-evidence') }}</strong></p>
33
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>
34
+ <p data-report-field="implementationPlanning.routing"><strong>{{ t('tasks.implementation-planning.re-entry-route') }}</strong> {{ planning.routing | inline_code }}</p>
35
35
  </section>
36
36
  {% endif %}
37
37
  {% else %}
@@ -56,7 +56,7 @@
56
56
  {{ render_narrative(narrative.stageStrategy, "implementationPlanning.userNarrative.stageStrategy") }}
57
57
  {% endif %}
58
58
  {{ figure(stageFigure) }}
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>
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></article>{% endfor %}</div>
60
60
  </section>
61
61
 
62
62
  {% if planning.get("designPreparation") %}
@@ -65,7 +65,7 @@
65
65
  {% if planning.designPreparation.mode == "no-design-inputs" %}
66
66
  <p>{{ planning.designPreparation.reason | inline_code }}</p>
67
67
  {% else %}
68
- <table><thead><tr><th>{{ t('tasks.implementation-planning.design-item') }}</th><th>{{ t('tasks.implementation-planning.what-it-needs') }}</th><th>{{ t('tasks.implementation-planning.open-questions') }}</th></tr></thead><tbody>{% for row in planning.designPreparation["items"] %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[("ID", row.id), ("Subject", row.title), ("Kind", row.kind)], status_name="Status", status_raw=row.status, status_text=row.status) }}<td>{{ row.need | inline_code }}</td><td>{{ row.openQuestions | default([]) | join(" · ") | inline_code }}</td></tr>{% endfor %}</tbody></table>
68
+ <table><thead><tr><th>{{ t('tasks.implementation-planning.design-item') }}</th><th>{{ t('tasks.implementation-planning.what-it-needs') }}</th><th>{{ t('tasks.implementation-planning.open-questions') }}</th></tr></thead><tbody>{% for row in planning.designPreparation["items"] %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[(t('macros.layout.id'), row.id), (t('macros.layout.subject'), row.title), (t('macros.layout.kind'), row.kind)], status_name=t('macros.layout.status'), status_raw=row.status, status_text=row.status) }}<td>{{ row.need | inline_code }}</td><td>{{ row.openQuestions | default([]) | join(" · ") | inline_code }}</td></tr>{% endfor %}</tbody></table>
69
69
  {% endif %}
70
70
  </section>
71
71
  {% endif %}
@@ -73,14 +73,14 @@
73
73
  <section data-report-section="variation-points" data-report-field="implementationPlanning.variationPointAnalysis">
74
74
  <h2>{{ t('tasks.implementation-planning.where-implementations-diverge') }}</h2>
75
75
  {% if planning.variationPointAnalysis.hasMultipleImplementations %}
76
- <table><thead><tr><th>{{ t('tasks.implementation-planning.action') }}</th><th>{{ t('tasks.implementation-planning.implementations') }}</th><th>{{ t('tasks.implementation-planning.extraction-call') }}</th><th>{{ t('tasks.implementation-planning.evidence') }}</th></tr></thead><tbody>{% for row in planning.variationPointAnalysis.points %}<tr><td>{{ row.behavior | inline_code }}</td><td>{{ row.implementations | default([]) | join(" · ") | inline_code }}</td><td>{{ row.extractionDecision | inline_code }}</td><td>{{ row.evidence | inline_code }}</td></tr>{% endfor %}</tbody></table>
76
+ <table><thead><tr><th>{{ t('tasks.implementation-planning.action') }}</th><th>{{ t('tasks.implementation-planning.implementations') }}</th><th>{{ t('tasks.implementation-planning.extraction-call') }}</th><th>{{ t('tasks.implementation-planning.evidence') }}</th></tr></thead><tbody>{% for row in planning.variationPointAnalysis.points %}{% set decision = row.extractionDecision %}<tr><td>{{ row.behavior | inline_code }}</td><td>{{ row.implementations | default([]) | join(" · ") | inline_code }}</td><td>{% if decision is mapping %}{{ t('tasks.implementation-planning.extract') if decision.extract else t('tasks.implementation-planning.keep') }} · {{ decision.interfaceKind | enum_label('interfaceKind') }} · {{ decision.coveredBy | inline_code }} — {{ decision.rationale | inline_code }}{% else %}{{ decision | inline_code }}{% endif %}</td><td>{{ row.evidence | inline_code }}</td></tr>{% endfor %}</tbody></table>
77
77
  {% else %}<p>{{ planning.variationPointAnalysis.noVariationRationale | inline_code }}</p>{% endif %}
78
78
  </section>
79
79
 
80
80
  {% if planning.get("stepwiseExecution") %}
81
81
  <section data-report-section="stepwise-execution" data-report-field="implementationPlanning.stepwiseExecution">
82
82
  <h2>{{ t('tasks.implementation-planning.step-by-step-execution') }}</h2>
83
- <table><thead><tr><th>#</th><th>{{ t('tasks.implementation-planning.action') }}</th><th>{{ t('tasks.implementation-planning.files') }}</th><th>{{ t('tasks.implementation-planning.command-test') }}</th><th>{{ t('tasks.implementation-planning.expected') }}</th></tr></thead><tbody>{% for row in planning.stepwiseExecution %}<tr><td>{{ row.step }}</td><td>{{ row.action | inline_code }}</td><td>{% for file in row.files %}<code>{{ file }}</code>{% if not loop.last %} {% endif %}{% endfor %}</td><td><code>{{ row.commandOrTest }}</code></td><td>{{ row.expectedOutcome | inline_code }}</td></tr>{% endfor %}</tbody></table>
83
+ <table><thead><tr><th>#</th><th>{{ t('tasks.implementation-planning.action') }}</th><th>{{ t('tasks.implementation-planning.files') }}</th><th>{{ t('tasks.implementation-planning.command-test') }}</th><th>{{ t('tasks.implementation-planning.expected') }}</th></tr></thead><tbody>{% for row in planning.stepwiseExecution %}<tr><td>{{ row.step }}</td><td>{{ row.action | inline_code }}</td><td><code>{{ row.files if row.files is string else row.files | join(" ") }}</code></td><td><code>{{ row.commandOrTest }}</code></td><td>{{ row.expectedOutcome | inline_code }}</td></tr>{% endfor %}</tbody></table>
84
84
  </section>
85
85
  {% endif %}
86
86
 
@@ -94,9 +94,9 @@
94
94
  <section data-report-section="requirement-coverage" data-report-field="implementationPlanning.requirementCoverage">
95
95
  <h2>{{ t('tasks.implementation-planning.how-each-requirement-gets-met') }}</h2>
96
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>
97
+ <table><thead><tr><th>{{ t('tasks.implementation-planning.original-requirement') }}</th><th>{{ t('tasks.implementation-planning.stages') }}</th><th>{{ t('tasks.implementation-planning.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
98
  {% else %}
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>
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=[(t('macros.layout.id'), row.id), (t('macros.layout.source'), row.source)], status_name=t('macros.layout.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
100
  {% endif %}
101
101
  </section>
102
102
 
@@ -108,7 +108,7 @@
108
108
  `no-dependent-statement` row legitimately carries neither. Referencing them
109
109
  unconditionally under StrictUndefined meant a schema-valid report killed the
110
110
  renderer. #}
111
- <table><thead><tr><th>{{ t('tasks.implementation-planning.answer') }}</th><th>{{ t('tasks.implementation-planning.statement-overturned') }}</th><th>{{ t('tasks.implementation-planning.replaced-with') }}</th></tr></thead><tbody>{% for row in planning.supersessionLedger %}<tr>{{ row_key(pairs=[("Answer", row.clarificationId), ("Disposition", row.disposition)]) }}<td>{{ row.get("supersededStatement") | inline_code }}</td><td>{{ row.get("replacedWith") | inline_code }}</td></tr>{% else %}<tr><td colspan="4">{{ t('tasks.implementation-planning.no-answer-overturned-anything') }}</td></tr>{% endfor %}</tbody></table>
111
+ <table><thead><tr><th>{{ t('tasks.implementation-planning.answer') }}</th><th>{{ t('tasks.implementation-planning.statement-overturned') }}</th><th>{{ t('tasks.implementation-planning.replaced-with') }}</th></tr></thead><tbody>{% set answered_ids = clarificationItems | map(attribute='id') | list %}{% for row in planning.supersessionLedger %}<tr{% if row.clarificationId not in answered_ids %} id="id-{{ row.clarificationId }}"{% endif %}>{{ row_key(pairs=[(t('macros.layout.answer'), row.clarificationId), (t('macros.layout.disposition'), row.disposition)]) }}<td>{{ row.get("supersededStatement") | inline_code }}</td><td>{{ row.get("replacedWith") | inline_code }}</td></tr>{% else %}<tr><td colspan="4">{{ t('tasks.implementation-planning.no-answer-overturned-anything') }}</td></tr>{% endfor %}</tbody></table>
112
112
  </section>
113
113
  {% endif %}
114
114
 
@@ -121,6 +121,7 @@
121
121
  {% endif %}
122
122
  </section>{% endif %}
123
123
 
124
+ {% if planning.get("decisionDrafts") or planning.get("skippedAdrCandidates") %}
124
125
  <section data-report-section="decision-drafts" data-report-field="implementationPlanning.decisionDrafts">
125
126
  <h2>{{ t('tasks.implementation-planning.decision-record-draft') }}</h2>
126
127
  {% for row in planning.get("decisionDrafts", []) %}
@@ -130,6 +131,7 @@
130
131
  <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 %}
131
132
  </section>
132
133
  {% endif %}
134
+ {% endif %}
133
135
 
134
136
  {% if agentActivities %}
135
137
  <section data-report-section="agent-activity">
@@ -137,7 +139,7 @@
137
139
  <div class="activity-list">
138
140
  {% for row in agentActivities %}
139
141
  <article class="activity-card" id="id-{{ row.activityId }}">
140
- <p class="eyebrow">{{ row.activityId }} · {{ row.agent }}</p>
142
+ <p class="eyebrow">{{ row.activityId | inline_code }} · {{ row.agent }}</p>
141
143
  <h3>{{ row.summary | inline_code }}</h3>
142
144
  <p>{{ t('tasks.implementation-planning.result') }}: {{ row.outcome | inline_code }}</p>
143
145
  <details>
@@ -17,13 +17,13 @@
17
17
 
18
18
  <section data-report-section="requirement-coverage">
19
19
  <h2>{{ t('tasks.implementation.requirement-coverage') }}</h2>
20
- <table data-report-field="implementation.requirementCoverage"><thead><tr><th>{{ t('tasks.implementation.requirement') }}</th><th>{{ t('tasks.implementation.body') }}</th><th>{{ t('tasks.implementation.implemented-by') }}</th></tr></thead><tbody>{% for row in implementation.requirementCoverage %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[("ID", row.id)], 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>
20
+ <table data-report-field="implementation.requirementCoverage"><thead><tr><th>{{ t('tasks.implementation.requirement') }}</th><th>{{ t('tasks.implementation.body') }}</th><th>{{ t('tasks.implementation.implemented-by') }}</th></tr></thead><tbody>{% for row in implementation.requirementCoverage %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[(t('macros.layout.id'), row.id)], status_name=t('macros.layout.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>
21
21
  </section>
22
22
 
23
23
  <section data-report-section="validation" data-report-field="implementation.validationEvidence">
24
24
  <h2>{{ t('tasks.implementation.verification-result') }}</h2>
25
25
  {{ render_narrative(narrative.validationExplanation, "implementation.userNarrative.validationExplanation") }}
26
- <div class="summary-grid">{% for row in implementation.validationEvidence %}{{ summary_card(row.phase ~ " · exit code " ~ row.exitCode, row.outputTail, "important" if row.exitCode else "neutral") }}{% endfor %}</div>
26
+ <div class="summary-grid">{% for row in implementation.validationEvidence %}{{ summary_card(row.phase ~ " · " ~ t('tasks.implementation.exit-code') ~ " " ~ row.exitCode, row.outputTail, "important" if row.exitCode else "neutral") }}{% endfor %}</div>
27
27
  <p><strong>{{ t('tasks.implementation.independent-check') }}</strong> {% for row in implementation.verifierResults %}<span class="status status-{{ row.verdict | lower }}">{{ row.verdict }}</span>{% if not loop.last %}, {% endif %}{% endfor %}</p>
28
28
  </section>
29
29
 
@@ -36,7 +36,7 @@
36
36
  <section data-report-section="shipped-commits" data-report-field="implementation.commitList">
37
37
  <h2>{{ t('tasks.implementation.commits-delivered') }}</h2>
38
38
  {% if implementation.commitList is mapping %}<p>{{ t('tasks.implementation.there-are-no-commits') }}</p>{% else %}
39
- <table><thead><tr><th>{{ t('tasks.implementation.commit') }}</th><th>{{ t('tasks.implementation.subject') }}</th><th>{{ t('tasks.implementation.files') }}</th></tr></thead><tbody>{% for row in implementation.commitList %}<tr>{{ row_key(pairs=[("SHA", row.shortSha), ("Order", row.number), ("Plan step", row.planStep)]) }}<td>{{ row.subject | inline_code }}</td><td>{% for file in row.files %}<code>{{ file }}</code>{% if not loop.last %} {% endif %}{% endfor %}</td></tr>{% endfor %}</tbody></table>{% endif %}
39
+ <table><thead><tr><th>{{ t('tasks.implementation.commit') }}</th><th>{{ t('tasks.implementation.subject') }}</th><th>{{ t('tasks.implementation.files') }}</th></tr></thead><tbody>{% for row in implementation.commitList %}<tr>{{ row_key(pairs=[(t('macros.layout.sha'), row.shortSha), (t('macros.layout.order'), row.number), (t('macros.layout.plan-step'), row.planStep)]) }}<td>{{ row.subject | inline_code }}</td><td>{% for file in row.files %}<code>{{ file }}</code>{% if not loop.last %} {% endif %}{% endfor %}</td></tr>{% endfor %}</tbody></table>{% endif %}
40
40
  <table data-report-field="implementation.approvedPlanReference"><tbody><tr><th>{{ t('tasks.implementation.approved-plan') }}</th><td><code>{{ implementation.approvedPlanReference.planFile }}</code></td></tr><tr><th>{{ t('tasks.implementation.approval-evidence') }}</th><td>{{ implementation.approvedPlanReference.approvalEvidence | inline_code }}</td></tr><tr><th>{{ t('tasks.implementation.worktree') }}</th><td><code>{{ implementation.approvedPlanReference.executorWorktreePath }}</code> @ <code>{{ implementation.approvedPlanReference.baseRefSha }}</code></td></tr></tbody></table>
41
41
  </section>
42
42
 
@@ -6,13 +6,13 @@
6
6
  <section data-report-section="opportunities">
7
7
  <h2>{{ t('tasks.improvement-discovery.improvements-found') }}</h2>
8
8
  {{ render_narrative(narrative.opportunityOverview, "improvementDiscovery.userNarrative.opportunityOverview") }}
9
- <table data-report-field="improvementDiscovery.lensCoverage"><thead><tr><th>{{ t('tasks.improvement-discovery.lens') }}</th><th>{{ t('tasks.improvement-discovery.detail') }}</th><th>{{ t('tasks.improvement-discovery.evidence') }}</th></tr></thead><tbody>{% for row in improvement.lensCoverage %}<tr>{{ row_key(pairs=[("Lens", row.lens), ("Result", row.status | enum_label("lens"))]) }}<td>{{ row.rationale | inline_code }}</td><td>{{ row.evidence | evidence_refs }}</td></tr>{% endfor %}</tbody></table>
9
+ <table data-report-field="improvementDiscovery.lensCoverage"><thead><tr><th>{{ t('tasks.improvement-discovery.lens') }}</th><th>{{ t('tasks.improvement-discovery.detail') }}</th><th>{{ t('tasks.improvement-discovery.evidence') }}</th></tr></thead><tbody>{% for row in improvement.lensCoverage %}<tr>{{ row_key(pairs=[(t('macros.layout.lens'), row.lens), (t('macros.layout.result'), row.status | enum_label("lens"))]) }}<td>{{ row.rationale | inline_code }}</td><td>{{ row.evidence | evidence_refs }}</td></tr>{% endfor %}</tbody></table>
10
10
  </section>
11
11
 
12
12
  <section data-report-section="ranked-candidates">
13
13
  <h2>{{ t('tasks.improvement-discovery.ranked-candidates') }}</h2>
14
14
  {{ render_narrative(narrative.prioritizationExplanation, "improvementDiscovery.userNarrative.prioritizationExplanation") }}
15
- <div class="summary-grid" data-report-field="improvementDiscovery.candidates">{% for row in improvement.candidates %}<article class="summary-card tone-{{ row.severity }}" id="id-{{ row.id }}"><p class="eyebrow">#{{ loop.index }} · {{ row.id }} · Impact {{ row.severity }} · Effort {{ row.effort | enum_label("effort") }}</p><h3>{{ row.title | inline_code }}</h3><p>{{ row.expectedBehaviorAfter | inline_code }}</p><p><strong>{{ t('tasks.improvement-discovery.next-step') }}</strong> {{ row.recommendedNextPhase }}</p><p class="evidence-refs">Evidence: {{ row.evidence | evidence_refs }}</p></article>{% else %}<p>{{ t('tasks.improvement-discovery.there-is-no-improvement-candidate-to-pick') }}</p>{% endfor %}</div>
15
+ <div class="summary-grid" data-report-field="improvementDiscovery.candidates">{% for row in improvement.candidates %}<article class="summary-card tone-{{ row.severity }}" id="id-{{ row.id }}"><p class="eyebrow">#{{ loop.index }} · {{ row.id | inline_code }} · {{ t('macros.layout.impact') }} {{ row.severity }} · {{ t('macros.layout.effort') }} {{ row.effort | enum_label("effort") }}</p><h3>{{ row.title | inline_code }}</h3><p>{{ row.expectedBehaviorAfter | inline_code }}</p><p><strong>{{ t('tasks.improvement-discovery.next-step') }}</strong> {{ row.recommendedNextPhase }}</p><p class="evidence-refs">{{ t('macros.layout.evidence') }} {{ row.evidence | evidence_refs }}</p></article>{% else %}<p>{{ t('tasks.improvement-discovery.there-is-no-improvement-candidate-to-pick') }}</p>{% endfor %}</div>
16
16
  </section>
17
17
 
18
18
  <section data-report-section="impact-effort">
@@ -24,6 +24,6 @@
24
24
  <h2>{{ t('tasks.improvement-discovery.how-to-choose') }}</h2>
25
25
  {{ render_narrative(narrative.selectionGuidance, "improvementDiscovery.userNarrative.selectionGuidance") }}
26
26
  <p><strong>{{ t('tasks.improvement-discovery.selection-cap') }}</strong> at most {{ improvement.selectionLimit }}</p>
27
- <ul>{% for row in improvement.candidates %}<li><label><input type="checkbox" name="improvement-candidate" value="{{ row.id }}"> {{ row.id }} · {{ row.title | inline_code }}</label></li>{% endfor %}</ul>
27
+ <ul>{% for row in improvement.candidates %}<li><label><input type="checkbox" name="improvement-candidate" value="{{ row.id }}"> {{ row.id | inline_code }} · {{ row.title | inline_code }}</label></li>{% endfor %}</ul>
28
28
  </section>
29
29
  {% endblock %}
@@ -28,16 +28,16 @@
28
28
  <h3>{{ t('tasks.project-analysis.language') }}</h3>
29
29
  <table><thead><tr><th>{{ t('tasks.project-analysis.language') }}</th><th>{{ t('tasks.project-analysis.version') }}</th><th>{{ t('tasks.project-analysis.version-source') }}</th><th>{{ t('tasks.project-analysis.files') }}</th><th>{{ t('tasks.project-analysis.lines') }}</th></tr></thead><tbody>{% for row in project.techStack.languages %}<tr><td>{{ row.name | inline_code }}</td><td><code>{{ row.version }}</code></td><td>{{ row.versionSource | enum_label("versionSource") }}</td><td>{{ row.get("fileCount") | default("--") }}</td><td>{{ row.get("lineCount") | default("--") }}</td></tr>{% endfor %}</tbody></table>
30
30
  {% if project.techStack.get("frameworks") %}<h3>{{ t('tasks.project-analysis.framework') }}</h3>
31
- <table><thead><tr><th>{{ t('tasks.project-analysis.framework') }}</th><th>{{ t('tasks.project-analysis.role') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.techStack.frameworks %}<tr>{{ row_key(pairs=[("Name", row.name), ("Version", row.version), ("Version source", row.versionSource | enum_label("versionSource"))]) }}<td>{{ row.role | inline_code }}</td><td>{{ row.get("currentCodeEvidence") | default([]) | code_evidence }}</td></tr>{% endfor %}</tbody></table>{% endif %}
31
+ <table><thead><tr><th>{{ t('tasks.project-analysis.framework') }}</th><th>{{ t('tasks.project-analysis.role') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.techStack.frameworks %}<tr>{{ row_key(pairs=[(t('macros.layout.name'), row.name), (t('macros.layout.version'), row.version), (t('macros.layout.version-source'), row.versionSource | enum_label("versionSource"))]) }}<td>{{ row.role | inline_code }}</td><td>{{ row.get("currentCodeEvidence") | default([]) | code_evidence }}</td></tr>{% endfor %}</tbody></table>{% endif %}
32
32
  {% if project.techStack.get("toolchain") %}<h3>{{ t('tasks.project-analysis.tool') }}</h3>
33
- <table><thead><tr><th>{{ t('tasks.project-analysis.tool') }}</th><th>{{ t('tasks.project-analysis.command') }}</th></tr></thead><tbody>{% for row in project.techStack.toolchain %}<tr>{{ row_key(pairs=[("Name", row.name), ("Kind", row.kind | enum_label("toolKind")), ("Version", row.get("version"))]) }}<td>{% if row.get("command") %}<code>{{ row.command }}</code>{% else %}--{% endif %}</td></tr>{% endfor %}</tbody></table>{% endif %}
33
+ <table><thead><tr><th>{{ t('tasks.project-analysis.tool') }}</th><th>{{ t('tasks.project-analysis.command') }}</th></tr></thead><tbody>{% for row in project.techStack.toolchain %}<tr>{{ row_key(pairs=[(t('macros.layout.name'), row.name), (t('macros.layout.kind'), row.kind | enum_label("toolKind")), (t('macros.layout.version'), row.get("version"))]) }}<td>{% if row.get("command") %}<code>{{ row.command }}</code>{% else %}--{% endif %}</td></tr>{% endfor %}</tbody></table>{% endif %}
34
34
  </section>
35
35
  {% endif %}
36
36
 
37
37
  {% if project.get("internalInterfaces") %}
38
38
  <section data-report-section="internal-interfaces" data-report-field="projectAnalysis.internalInterfaces">
39
39
  <h2>{{ t('tasks.project-analysis.internal-interfaces') }}</h2>
40
- <table><thead><tr><th>{{ t('tasks.project-analysis.interface') }}</th><th>{{ t('tasks.project-analysis.signature') }}</th><th>{{ t('tasks.project-analysis.consumers') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.internalInterfaces %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[("ID", row.id), ("Name", row.name), ("Kind", row.kind | enum_label("interfaceKind")), ("Owner", row.ownerComponentId)]) }}<td><code>{{ row.signature }}</code></td><td>{{ (row.get("consumers") | default([])) | join(", ") | inline_code }}</td><td>{{ row.get("currentCodeEvidence") | default([]) | code_evidence }}</td></tr>{% endfor %}</tbody></table>
40
+ <table><thead><tr><th>{{ t('tasks.project-analysis.interface') }}</th><th>{{ t('tasks.project-analysis.signature') }}</th><th>{{ t('tasks.project-analysis.consumers') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.internalInterfaces %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[(t('macros.layout.id'), row.id), (t('macros.layout.name'), row.name), (t('macros.layout.kind'), row.kind | enum_label("interfaceKind")), (t('macros.layout.owner'), row.ownerComponentId)]) }}<td><code>{{ row.signature }}</code></td><td>{{ (row.get("consumers") | default([])) | join(", ") | inline_code }}</td><td>{{ row.get("currentCodeEvidence") | default([]) | code_evidence }}</td></tr>{% endfor %}</tbody></table>
41
41
  </section>
42
42
  {% endif %}
43
43
 
@@ -47,7 +47,7 @@
47
47
  {{ figure(workflowFigure) }}
48
48
  {% for flow in project.workflows %}
49
49
  <article class="workflow" id="id-{{ flow.id }}">
50
- <p class="eyebrow">{{ flow.id }}</p>
50
+ <p class="eyebrow">{{ flow.id | inline_code }}</p>
51
51
  <h3>{{ flow.name | inline_code }}</h3>
52
52
  <p><strong>{{ t('tasks.project-analysis.starts-with') }}</strong> — {{ flow.trigger | inline_code }}{% if flow.get("outcome") %} · <strong>{{ t('tasks.project-analysis.result') }}</strong> — {{ flow.outcome | inline_code }}{% endif %}</p>
53
53
  <table><thead><tr><th>{{ t('tasks.project-analysis.order') }}</th><th>{{ t('tasks.project-analysis.action') }}</th><th>{{ t('tasks.project-analysis.component') }}</th><th>{{ t('tasks.project-analysis.external-system') }}</th></tr></thead><tbody>{% for step in flow.steps %}<tr><td>{{ step.order }}</td><td>{{ step.action | inline_code }}</td><td>{{ step.componentId | inline_code }}</td><td>{% if step.get("externalSystem") %}{{ step.externalSystem | inline_code }}{% else %}--{% endif %}</td></tr>{% endfor %}</tbody></table>
@@ -60,11 +60,11 @@
60
60
  <h2>{{ t('tasks.project-analysis.system-boundaries') }}</h2>
61
61
  <p class="scan-coverage" data-report-field="projectAnalysis.scanCoverage"><strong>{{ project.scanCoverage.scannedPathCount }}</strong> {{ t('tasks.project-analysis.paths-read') }} <strong>{{ project.scanCoverage.unscannedPathCount }}</strong> left unread — {{ project.scanCoverage.reason | inline_code }}</p>
62
62
  <h3>{{ t('tasks.project-analysis.entry-point') }}</h3>
63
- <table data-report-field="projectAnalysis.entryPoints"><thead><tr><th>{{ t('tasks.project-analysis.entry-point') }}</th><th>{{ t('tasks.project-analysis.path') }}</th><th>{{ t('tasks.project-analysis.role') }}</th></tr></thead><tbody>{% for row in project.entryPoints %}<tr>{{ row_key(pairs=[("Symbol", row.symbol), ("Kind", row.kind)]) }}<td><code>{{ row.path }}</code></td><td>{{ row.role | inline_code }}</td></tr>{% endfor %}</tbody></table>
63
+ <table data-report-field="projectAnalysis.entryPoints"><thead><tr><th>{{ t('tasks.project-analysis.entry-point') }}</th><th>{{ t('tasks.project-analysis.path') }}</th><th>{{ t('tasks.project-analysis.role') }}</th></tr></thead><tbody>{% for row in project.entryPoints %}<tr>{{ row_key(pairs=[(t('macros.layout.symbol'), row.symbol), (t('macros.layout.kind'), row.kind)]) }}<td><code>{{ row.path }}</code></td><td>{{ row.role | inline_code }}</td></tr>{% endfor %}</tbody></table>
64
64
  <h3>{{ t('tasks.project-analysis.data-stores') }}</h3>
65
- <table data-report-field="projectAnalysis.dataStores"><thead><tr><th>{{ t('tasks.project-analysis.store') }}</th><th>{{ t('tasks.project-analysis.reads') }}</th><th>{{ t('tasks.project-analysis.writes') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.dataStores %}<tr>{{ row_key(pairs=[("Name", row.name), ("Owner", row.ownerComponentId)]) }}<td>{{ row.readBoundary | inline_code }}</td><td>{{ row.writeBoundary | inline_code }}</td><td>{{ row.currentCodeEvidence | code_evidence }}</td></tr>{% endfor %}</tbody></table>
65
+ <table data-report-field="projectAnalysis.dataStores"><thead><tr><th>{{ t('tasks.project-analysis.store') }}</th><th>{{ t('tasks.project-analysis.reads') }}</th><th>{{ t('tasks.project-analysis.writes') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.dataStores %}<tr>{{ row_key(pairs=[(t('macros.layout.name'), row.name), (t('macros.layout.owner'), row.ownerComponentId)]) }}<td>{{ row.readBoundary | inline_code }}</td><td>{{ row.writeBoundary | inline_code }}</td><td>{{ row.currentCodeEvidence | code_evidence }}</td></tr>{% endfor %}</tbody></table>
66
66
  <h3>{{ t('tasks.project-analysis.external-system') }}</h3>
67
- <table data-report-field="projectAnalysis.externalSystems"><thead><tr><th>{{ t('tasks.project-analysis.external-system') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.externalSystems %}<tr>{{ row_key(pairs=[("Name", row.name), ("Adapter", row.adapter), ("Direction", row.direction)]) }}<td>{{ row.currentCodeEvidence | code_evidence }}</td></tr>{% endfor %}</tbody></table>
67
+ <table data-report-field="projectAnalysis.externalSystems"><thead><tr><th>{{ t('tasks.project-analysis.external-system') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.externalSystems %}<tr>{{ row_key(pairs=[(t('macros.layout.name'), row.name), (t('macros.layout.adapter'), row.adapter), (t('macros.layout.direction'), row.direction)]) }}<td>{{ row.currentCodeEvidence | code_evidence }}</td></tr>{% endfor %}</tbody></table>
68
68
  </section>
69
69
 
70
70
  <section data-report-section="hotspots" data-report-field="projectAnalysis.rankedHotspots">
@@ -72,7 +72,7 @@
72
72
  {{ render_narrative(narrative.hotspotExplanation, "projectAnalysis.userNarrative.hotspotExplanation") }}
73
73
  <div class="summary-grid">
74
74
  {% for row in project.rankedHotspots %}
75
- <article class="summary-card tone-{{ row.risk }}" id="id-{{ row.id }}"><p class="eyebrow">{{ row.id }} · Impact {{ row.impact }} · Risk {{ row.risk }}</p><h3>{{ row.title | inline_code }}</h3><p>{{ row.reason | inline_code }}</p><p class="evidence-refs">Evidence: {{ row.evidenceRefs | evidence_refs }}</p></article>
75
+ <article class="summary-card tone-{{ row.risk }}" id="id-{{ row.id }}"><p class="eyebrow">{{ row.id | inline_code }} · {{ t('macros.layout.impact') }} {{ row.impact }} · {{ t('macros.layout.risk') }} {{ row.risk }}</p><h3>{{ row.title | inline_code }}</h3><p>{{ row.reason | inline_code }}</p><p class="evidence-refs">{{ t('macros.layout.evidence') }} {{ row.evidenceRefs | evidence_refs }}</p></article>
76
76
  {% endfor %}
77
77
  </div>
78
78
  </section>
@@ -80,13 +80,13 @@
80
80
  <section data-report-section="quality-and-tests" data-report-field="projectAnalysis.qualityCoverage">
81
81
  <h2>{{ t('tasks.project-analysis.quality-and-test-coverage') }}</h2>
82
82
  {{ render_narrative(narrative.qualityExplanation, "projectAnalysis.userNarrative.qualityExplanation") }}
83
- <table><thead><tr><th>{{ t('tasks.project-analysis.area') }}</th><th>{{ t('tasks.project-analysis.detail') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.qualityCoverage %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[("ID", row.id), ("Area", row.area)], status_name="Status", status_raw=row.status, status_text=row.status | enum_label("coverage")) }}<td>{{ row.summary | inline_code }}</td><td>{{ row.evidenceRefs | evidence_refs }}</td></tr>{% endfor %}</tbody></table>
83
+ <table><thead><tr><th>{{ t('tasks.project-analysis.area') }}</th><th>{{ t('tasks.project-analysis.detail') }}</th><th>{{ t('tasks.project-analysis.evidence') }}</th></tr></thead><tbody>{% for row in project.qualityCoverage %}<tr id="id-{{ row.id }}">{{ row_key(pairs=[(t('macros.layout.id'), row.id), (t('macros.layout.area'), row.area)], status_name=t('macros.layout.status'), status_raw=row.status, status_text=row.status | enum_label("coverage")) }}<td>{{ row.summary | inline_code }}</td><td>{{ row.evidenceRefs | evidence_refs }}</td></tr>{% endfor %}</tbody></table>
84
84
  <dl class="enum-legend">{% for label, hint in "coverage" | enum_legend %}<dt>{{ label }}</dt><dd>{{ hint }}</dd>{% endfor %}</dl>
85
85
  </section>
86
86
 
87
87
  <section data-report-section="feature-map" data-report-field="projectAnalysis.featureIndex">
88
88
  <h2>{{ t('tasks.project-analysis.feature-map') }}</h2>
89
- <div class="summary-grid">{% for row in project.featureIndex %}{{ summary_card(row.id ~ " · " ~ (row.name | inline_code), row.description, anchor=row.id) }}{% endfor %}</div>
89
+ <div class="summary-grid">{% for row in project.featureIndex %}{{ summary_card(row.id ~ " · " ~ row.name, row.description, anchor=row.id) }}{% endfor %}</div>
90
90
  </section>
91
91
 
92
92
  <section data-report-section="user-actions">
@@ -31,14 +31,14 @@
31
31
  <section data-report-section="conflicts" data-report-field="releaseHandoff.mergeConflictProbe">
32
32
  <h2>{{ t('tasks.release-handoff.conflict-verdict') }}</h2>
33
33
  {{ render_narrative(narrative.conflictExplanation, "releaseHandoff.userNarrative.conflictExplanation") }}
34
- {{ summary_card(handoff.mergeConflictProbe.kind, "Base branch: " ~ (handoff.mergeConflictProbe.baseBranch | default('not-run'))) }}
34
+ {{ summary_card(handoff.mergeConflictProbe.kind, t('tasks.release-handoff.base-branch') ~ " " ~ (handoff.mergeConflictProbe.baseBranch | default('not-run'))) }}
35
35
  {% if handoff.mergeConflictProbe.conflictingPaths %}<ul>{% for path in handoff.mergeConflictProbe.conflictingPaths %}<li>{{ path }}</li>{% endfor %}</ul>{% endif %}
36
36
  </section>
37
37
 
38
38
  <section data-report-section="delivered-commits" data-report-field="releaseHandoff.commitList">
39
39
  <h2>{{ t('tasks.release-handoff.commits-delivered') }}</h2>
40
40
  {% if handoff.commitList is mapping %}<p>{{ t('tasks.release-handoff.there-are-no-commits') }}</p>{% else %}
41
- <table><thead><tr><th>{{ t('tasks.release-handoff.commit') }}</th><th>{{ t('tasks.release-handoff.subject') }}</th><th>{{ t('tasks.release-handoff.files') }}</th></tr></thead><tbody>{% for row in handoff.commitList %}<tr>{{ row_key(pairs=[("SHA", row.shortSha), ("Order", loop.index)]) }}<td>{{ row.subject | inline_code }}</td><td>{% for file in row.files %}<code>{{ file }}</code>{% if not loop.last %} {% endif %}{% endfor %}</td></tr>{% endfor %}</tbody></table>{% endif %}
41
+ <table><thead><tr><th>{{ t('tasks.release-handoff.commit') }}</th><th>{{ t('tasks.release-handoff.subject') }}</th><th>{{ t('tasks.release-handoff.files') }}</th></tr></thead><tbody>{% for row in handoff.commitList %}<tr>{{ row_key(pairs=[(t('macros.layout.sha'), row.shortSha), (t('macros.layout.order'), loop.index)]) }}<td>{{ row.subject | inline_code }}</td><td>{% for file in row.files %}<code>{{ file }}</code>{% if not loop.last %} {% endif %}{% endfor %}</td></tr>{% endfor %}</tbody></table>{% endif %}
42
42
  {% if handoff.sourceVerificationReports %}<p data-report-field="releaseHandoff.sourceVerificationReports"><strong>{{ t('tasks.release-handoff.the-verification-report-this-rests-on') }}</strong>{% for row in handoff.sourceVerificationReports %} — stage {{ row.stage }}: <code>{{ row.path }}</code> · {{ row.verdictTokenQuote | inline_code }}{% endfor %}</p>
43
43
  {% else %}<p data-report-field="releaseHandoff.sourceVerificationReport"><strong>{{ t('tasks.release-handoff.the-verification-report-this-rests-on') }}</strong> — <code>{{ handoff.sourceVerificationReport.path }}</code> · {{ handoff.sourceVerificationReport.verdictTokenQuote | inline_code }}</p>{% endif %}
44
44
  </section>
@@ -20,7 +20,7 @@
20
20
  <p>{{ t('tasks.requirements-discovery.the-requester-left-no-rejection-criteria-eve') }}</p>
21
21
  {% else %}
22
22
  <p>{{ requirements.rejectionCriteria.get("statement") | inline_code }}</p>
23
- <p class="evidence-refs">Source: {{ requirements.rejectionCriteria.source | enum_label("rejectionSource") }}{% if requirements.rejectionCriteria.get("clarificationId") %} · {{ requirements.rejectionCriteria.clarificationId | inline_code }}{% endif %}{% if requirements.rejectionCriteria.get("evidenceRefs") %} · {{ requirements.rejectionCriteria.evidenceRefs | evidence_refs }}{% endif %}</p>
23
+ <p class="evidence-refs">{{ t('macros.layout.source') }} {{ requirements.rejectionCriteria.source | enum_label("rejectionSource") }}{% if requirements.rejectionCriteria.get("clarificationId") %} · {{ requirements.rejectionCriteria.clarificationId | inline_code }}{% endif %}{% if requirements.rejectionCriteria.get("evidenceRefs") %} · {{ requirements.rejectionCriteria.evidenceRefs | evidence_refs }}{% endif %}</p>
24
24
  {% endif %}
25
25
  </section>
26
26
  {% endif %}
@@ -28,7 +28,7 @@
28
28
  {% if requirements.get("domainAlignment") %}
29
29
  <section data-report-section="domain-alignment" data-report-field="requirementsDiscovery.domainAlignment">
30
30
  <h2>{{ t('tasks.requirements-discovery.terms-settled') }}</h2>
31
- <p>Glossary {{ "checked" if requirements.domainAlignment.glossaryConsulted else "none" }} · Decision record {{ "checked" if requirements.domainAlignment.decisionsConsulted else "none" }}</p>
31
+ <p>{{ t('tasks.requirements-discovery.glossary') }} {{ t('macros.layout.checked') if requirements.domainAlignment.glossaryConsulted else t('macros.layout.none') }} · {{ t('tasks.requirements-discovery.decision-record') }} {{ t('macros.layout.checked') if requirements.domainAlignment.decisionsConsulted else t('macros.layout.none') }}</p>
32
32
  <table><thead><tr><th>{{ t('tasks.requirements-discovery.as-the-brief-put-it') }}</th><th>{{ t('tasks.requirements-discovery.settled-term') }}</th><th>{{ t('tasks.requirements-discovery.settled-by') }}</th><th>{{ t('tasks.requirements-discovery.evidence') }}</th></tr></thead><tbody>{% for row in requirements.domainAlignment.terms %}<tr><td>{{ row.raw | inline_code }}</td><td>{{ row.canonical | inline_code }}</td><td>{{ row.resolvedBy | enum_label("termSource") }}</td><td>{{ row.get("evidenceRefs") | default([]) | evidence_refs }}</td></tr>{% else %}<tr><td colspan="4">{{ t('tasks.requirements-discovery.no-term-was-ambiguous') }}</td></tr>{% endfor %}</tbody></table>
33
33
  </section>
34
34
  {% endif %}
@@ -36,9 +36,9 @@
36
36
  <section data-report-section="requirements">
37
37
  <h2>{{ t('tasks.requirements-discovery.settled-and-unsettled-requirements') }}</h2>
38
38
  {{ render_narrative(narrative.confirmedRequirements, "requirementsDiscovery.userNarrative.confirmedRequirements") }}
39
- <div class="summary-grid" data-report-field="requirementsDiscovery.confirmedRequirements">{% for row in requirements.confirmedRequirements %}{{ summary_card(row.id ~ " · Settled", row.statement, anchor=row.id) }}{% endfor %}</div>
39
+ <div class="summary-grid" data-report-field="requirementsDiscovery.confirmedRequirements">{% for row in requirements.confirmedRequirements %}{{ summary_card(row.id ~ " · " ~ t('tasks.requirements-discovery.settled'), row.statement, anchor=row.id) }}{% endfor %}</div>
40
40
  {{ render_narrative(narrative.unresolvedRequirements, "requirementsDiscovery.userNarrative.unresolvedRequirements") }}
41
- <div class="summary-grid" data-report-field="requirementsDiscovery.unresolvedRequirements">{% for row in requirements.unresolvedRequirements %}{{ summary_card(row.id ~ " · Decision needed", row.statement, "important") }}{% else %}<p>{{ t('tasks.requirements-discovery.nothing-is-left-unsettled') }}</p>{% endfor %}</div>
41
+ <div class="summary-grid" data-report-field="requirementsDiscovery.unresolvedRequirements">{% for row in requirements.unresolvedRequirements %}{{ summary_card(row.id ~ " · " ~ t('tasks.requirements-discovery.decision-needed'), row.statement, "important") }}{% else %}<p>{{ t('tasks.requirements-discovery.nothing-is-left-unsettled') }}</p>{% endfor %}</div>
42
42
  </section>
43
43
 
44
44
  <section data-report-section="routing">