@davidorex/pi-workflows 0.26.0 → 0.28.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/CHANGELOG.md +199 -0
- package/agents/requirements-gatherer.agent.yaml +1 -1
- package/dist/auth-required.d.ts +10 -0
- package/dist/auth-required.d.ts.map +1 -0
- package/dist/auth-required.js +10 -0
- package/dist/auth-required.js.map +1 -0
- package/dist/bundled-dirs.d.ts +1 -1
- package/dist/bundled-dirs.d.ts.map +1 -1
- package/dist/bundled-dirs.js +8 -3
- package/dist/bundled-dirs.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -8
- package/dist/index.js.map +1 -1
- package/dist/render-by-id.d.ts.map +1 -1
- package/dist/render-by-id.js +7 -4
- package/dist/render-by-id.js.map +1 -1
- package/dist/template-validation.js +3 -3
- package/dist/template-validation.js.map +1 -1
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +2 -2
- package/dist/template.js.map +1 -1
- package/dist/test-helpers.d.ts.map +1 -1
- package/dist/test-helpers.js +4 -5
- package/dist/test-helpers.js.map +1 -1
- package/dist/workflow-sdk.d.ts.map +1 -1
- package/dist/workflow-sdk.js +6 -5
- package/dist/workflow-sdk.js.map +1 -1
- package/package.json +11 -5
- package/skill-narrative.md +3 -3
- package/skills/pi-workflows/SKILL.md +6 -6
- package/skills/pi-workflows/references/bundled-resources.md +0 -51
- package/templates/analyzers/base-analyzer.md +0 -9
- package/templates/analyzers/patterns-task.md +0 -11
- package/templates/analyzers/patterns.md +0 -15
- package/templates/analyzers/quality-task.md +0 -11
- package/templates/analyzers/quality.md +0 -15
- package/templates/analyzers/structure-task.md +0 -17
- package/templates/analyzers/structure.md +0 -15
- package/templates/architecture-designer/task.md +0 -117
- package/templates/architecture-inferrer/task.md +0 -61
- package/templates/audit-finding-verifier/task.md +0 -59
- package/templates/audit-fixer/task.md +0 -67
- package/templates/audit-results-router/task.md +0 -37
- package/templates/decomposer/task.md +0 -56
- package/templates/explorer/system.md +0 -3
- package/templates/explorer/task.md +0 -9
- package/templates/gap-identifier/task.md +0 -103
- package/templates/gap-resolution-assessor/task.md +0 -48
- package/templates/handoff-writer/task.md +0 -101
- package/templates/investigator/task.md +0 -30
- package/templates/items/architecture.md +0 -33
- package/templates/items/conformance.md +0 -26
- package/templates/items/conventions.md +0 -19
- package/templates/items/decisions.md +0 -47
- package/templates/items/domain.md +0 -21
- package/templates/items/features.md +0 -63
- package/templates/items/framework-gaps.md +0 -43
- package/templates/items/issues.md +0 -21
- package/templates/items/layer-plans.md +0 -50
- package/templates/items/project.md +0 -48
- package/templates/items/requirements.md +0 -20
- package/templates/items/research.md +0 -57
- package/templates/items/spec-reviews.md +0 -51
- package/templates/items/tasks.md +0 -29
- package/templates/phase-author/task.md +0 -82
- package/templates/plan-creator/task.md +0 -143
- package/templates/plan-decomposer/task.md +0 -46
- package/templates/project-definer/task.md +0 -67
- package/templates/project-inferrer/task.md +0 -56
- package/templates/requirements-gatherer/task.md +0 -90
- package/templates/researcher/task.md +0 -26
- package/templates/shared/macros.md +0 -137
- package/templates/shared/render-helpers.md +0 -106
- package/templates/spec-implementer/task.md +0 -53
- package/templates/synthesizer/system.md +0 -3
- package/templates/synthesizer/task.md +0 -38
- package/templates/task-verifier/task.md +0 -44
- package/templates/task-worker/task.md +0 -52
- package/templates/verifier/task.md +0 -57
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
Capture a handoff snapshot for the project at `{{ path }}`.
|
|
2
|
-
|
|
3
|
-
## Current Project State
|
|
4
|
-
|
|
5
|
-
{% if project_state.blocks_status %}
|
|
6
|
-
### Block Availability
|
|
7
|
-
|
|
8
|
-
| Block | Available |
|
|
9
|
-
|-------|-----------|
|
|
10
|
-
{% for name, available in project_state.blocks_status %}
|
|
11
|
-
| {{ name }} | {{ "yes" if available else "NO — absent" }} |
|
|
12
|
-
{% endfor %}
|
|
13
|
-
{% endif %}
|
|
14
|
-
|
|
15
|
-
{% if project_state.project %}
|
|
16
|
-
### Project
|
|
17
|
-
**{{ project_state.project.name | default("unnamed") }}** — {{ project_state.project.description | default("no description") }}
|
|
18
|
-
Status: {{ project_state.project.status | default("unknown") }}
|
|
19
|
-
{% endif %}
|
|
20
|
-
|
|
21
|
-
{% if project_state.phases and project_state.phases | length > 0 %}
|
|
22
|
-
### Phases
|
|
23
|
-
{% for phase in project_state.phases %}
|
|
24
|
-
- Phase {{ phase.number | default(loop.index) }}: {{ phase.name | default("unnamed") }} ({{ phase.status | default("unknown") }})
|
|
25
|
-
{% endfor %}
|
|
26
|
-
{% endif %}
|
|
27
|
-
|
|
28
|
-
{% if project_state.blockSummaries %}
|
|
29
|
-
### Block Summaries
|
|
30
|
-
{% for block in project_state.blockSummaries %}
|
|
31
|
-
- **{{ block.name }}**: {{ block.count | default("?") }} entries
|
|
32
|
-
{% endfor %}
|
|
33
|
-
{% endif %}
|
|
34
|
-
|
|
35
|
-
{% if project_state.gaps %}
|
|
36
|
-
### Open Gaps
|
|
37
|
-
{% for gap in project_state.gaps %}
|
|
38
|
-
{% if gap.status == "open" %}
|
|
39
|
-
- [{{ gap.priority }}] {{ gap.id }}: {{ gap.description }}
|
|
40
|
-
{% endif %}
|
|
41
|
-
{% endfor %}
|
|
42
|
-
{% endif %}
|
|
43
|
-
|
|
44
|
-
{% if project_state.decisions %}
|
|
45
|
-
### Recent Decisions
|
|
46
|
-
{% for decision in project_state.decisions %}
|
|
47
|
-
- {{ decision.id | default("?") }}: {{ decision.description | default(decision.title | default("no description")) }}
|
|
48
|
-
{% endfor %}
|
|
49
|
-
{% endif %}
|
|
50
|
-
|
|
51
|
-
{% if project_state.recentCommits %}
|
|
52
|
-
### Recent Commits
|
|
53
|
-
{% for commit in project_state.recentCommits %}
|
|
54
|
-
- `{{ commit.sha | default("?") | truncate(7, true, "") }}` {{ commit.message | default("no message") }}
|
|
55
|
-
{% endfor %}
|
|
56
|
-
{% endif %}
|
|
57
|
-
|
|
58
|
-
## Instructions
|
|
59
|
-
|
|
60
|
-
Synthesize the project state above into a handoff block that enables a future agent or human to resume work seamlessly.
|
|
61
|
-
|
|
62
|
-
1. **context** — Write a paragraph capturing:
|
|
63
|
-
- What was being worked on (current phase, recent commits, active changes)
|
|
64
|
-
- The current state of thinking (what decisions were made, what approach is being taken)
|
|
65
|
-
- Any momentum or direction that should be preserved
|
|
66
|
-
|
|
67
|
-
2. **timestamp** — Current datetime in ISO 8601 format (e.g., 2026-03-18T14:30:00Z)
|
|
68
|
-
|
|
69
|
-
3. **current_phase** — The phase currently being worked on (number or name)
|
|
70
|
-
|
|
71
|
-
4. **current_tasks** — Task IDs currently in progress (from project state if available, otherwise infer from recent activity)
|
|
72
|
-
|
|
73
|
-
5. **blockers** — Anything preventing progress:
|
|
74
|
-
- Unresolved decisions that block implementation
|
|
75
|
-
- Failing tests or broken builds
|
|
76
|
-
- Missing dependencies or external requirements
|
|
77
|
-
- Only include genuine blockers, not wishes
|
|
78
|
-
|
|
79
|
-
6. **next_actions** — Concrete next steps, ordered by priority:
|
|
80
|
-
- What should the next session do first?
|
|
81
|
-
- What's the next logical step in the current phase?
|
|
82
|
-
- Keep to 3-5 actionable items
|
|
83
|
-
|
|
84
|
-
7. **open_questions** — Genuine unknowns requiring input:
|
|
85
|
-
- Design decisions that need human judgment
|
|
86
|
-
- Ambiguities discovered during development
|
|
87
|
-
- Technical choices with trade-offs that haven't been resolved
|
|
88
|
-
|
|
89
|
-
8. **key_decisions_pending** — Decision IDs from the project state that need resolution
|
|
90
|
-
|
|
91
|
-
9. **files_in_flux** — Files with incomplete or in-progress changes (NOT every recently committed file — only files that have partial work)
|
|
92
|
-
|
|
93
|
-
Read project blocks if needed to get more detail than the summary provides. Focus on in-flight state, not project overview.
|
|
94
|
-
|
|
95
|
-
## Required Output Schema
|
|
96
|
-
|
|
97
|
-
You MUST produce JSON conforming exactly to this schema. Every required field must be present.
|
|
98
|
-
|
|
99
|
-
```json
|
|
100
|
-
{{ output_schema }}
|
|
101
|
-
```
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
## Gap to Investigate
|
|
2
|
-
|
|
3
|
-
**ID:** {{ gap.id }}
|
|
4
|
-
**Description:** {{ gap.description }}
|
|
5
|
-
**Category:** {{ gap.category }}
|
|
6
|
-
**Priority:** {{ gap.priority }}
|
|
7
|
-
{% if gap.details %}
|
|
8
|
-
**Details:** {{ gap.details }}
|
|
9
|
-
{% endif %}
|
|
10
|
-
|
|
11
|
-
## Instructions
|
|
12
|
-
|
|
13
|
-
Produce structured findings for this gap. Scope your investigation to the minimum needed:
|
|
14
|
-
|
|
15
|
-
1. If the gap names specific files, read those. If not, use `find` or `ls` to identify candidates — don't read file contents unless you need to confirm behavior.
|
|
16
|
-
2. For each affected file: what it does, what needs to change.
|
|
17
|
-
3. List hard constraints (existing tests, interfaces, conventions that must not break).
|
|
18
|
-
4. Note risks only if non-obvious.
|
|
19
|
-
5. Set `needs_research` to true only if the solution requires knowledge you don't have. Most gaps don't.
|
|
20
|
-
6. Complexity: `low` = single concern, mechanical. `medium` = multiple files, design choices. `high` = architectural.
|
|
21
|
-
|
|
22
|
-
Match your depth to the gap's category and priority. A `cleanup/low` gap needs a few lines of findings, not a codebase survey.
|
|
23
|
-
|
|
24
|
-
## Required Output Schema
|
|
25
|
-
|
|
26
|
-
You MUST produce JSON conforming exactly to this schema. Every required field must be present.
|
|
27
|
-
|
|
28
|
-
```json
|
|
29
|
-
{{ output_schema }}
|
|
30
|
-
```
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `architecture` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Singleton kind: architecture holds one record per repository describing
|
|
5
|
-
modules, patterns, boundaries, and (optionally) compilation_pipeline /
|
|
6
|
-
execution_model / dispatch_design. The "per-item" rendering operates on
|
|
7
|
-
the whole block payload as a single record; the whole-block delegator in
|
|
8
|
-
shared/macros.md passes its data argument straight through.
|
|
9
|
-
|
|
10
|
-
No cross-block references — depth parameter accepted for shape-uniformity
|
|
11
|
-
with the renderer-registry call convention; no helpers from
|
|
12
|
-
shared/render-helpers.md are needed.
|
|
13
|
-
-#}
|
|
14
|
-
|
|
15
|
-
{% macro render_architecture_item(a, depth=0) %}
|
|
16
|
-
{% if a %}
|
|
17
|
-
## Architecture
|
|
18
|
-
{% if a.overview %}{{ a.overview }}
|
|
19
|
-
{% endif %}
|
|
20
|
-
{% if a.modules %}
|
|
21
|
-
### Modules
|
|
22
|
-
{% for m in a.modules %}- **{{ m.name }}** (`{{ m.file }}`{% if m.lines %}, {{ m.lines }} lines{% endif %}): {{ enforceBudget(m.responsibility, "architecture", "modules.items.responsibility") }}{% if m.dependencies %} — deps: {{ m.dependencies | join(", ") }}{% endif %}
|
|
23
|
-
{% endfor %}{% endif %}
|
|
24
|
-
{% if a.patterns %}
|
|
25
|
-
### Patterns
|
|
26
|
-
{% for p in a.patterns %}- **{{ p.name }}**: {{ enforceBudget(p.description, "architecture", "patterns.items.description") }}{% if p.used_in %} — used in: {{ p.used_in | join(", ") }}{% endif %}
|
|
27
|
-
{% endfor %}{% endif %}
|
|
28
|
-
{% if a.boundaries %}
|
|
29
|
-
### Boundaries
|
|
30
|
-
{% for b in a.boundaries %}- {{ b }}
|
|
31
|
-
{% endfor %}{% endif %}
|
|
32
|
-
{% endif %}
|
|
33
|
-
{% endmacro %}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `conformance-reference` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/conformance-reference.schema.json. The
|
|
5
|
-
block holds a name, scope, and principles[]. Each principle has nested
|
|
6
|
-
rules[]. The "per-item" granularity here is one principle (with its
|
|
7
|
-
rules) — the natural unit for prompt injection per the substrate spec.
|
|
8
|
-
|
|
9
|
-
No cross-block references — references are to source material (sources[]
|
|
10
|
-
at the block level), not to other block items. Depth parameter accepted
|
|
11
|
-
for renderer-registry shape-uniformity.
|
|
12
|
-
|
|
13
|
-
Companion whole-block macro:
|
|
14
|
-
render_conformance(data) in shared/macros.md emits the block-level
|
|
15
|
-
name + scope header, then iterates principles through this macro.
|
|
16
|
-
-#}
|
|
17
|
-
|
|
18
|
-
{% macro render_conformance_principle(p, depth=0) %}
|
|
19
|
-
{% if p %}
|
|
20
|
-
### {{ p.id }}: {{ p.name }}
|
|
21
|
-
{% if p.description %}{{ enforceBudget(p.description, "conformance-reference", "principles.items.description") }}{% endif %}
|
|
22
|
-
{% for r in p.rules %}- **{{ r.id }}**: {{ enforceBudget(r.rule, "conformance-reference", "principles.items.rules.items.rule") }}{% if r.severity %} [{{ r.severity }}]{% endif %}{% if r.check_method %} — check: {{ r.check_method }}{% endif %}
|
|
23
|
-
{% if r.anti_patterns %} Anti-patterns: {{ r.anti_patterns | join("; ") }}
|
|
24
|
-
{% endif %}{% endfor %}
|
|
25
|
-
{% endif %}
|
|
26
|
-
{% endmacro %}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `conventions` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/conventions.schema.json. Each item is one
|
|
5
|
-
rule object inside data.rules[] (id, description, enforcement, severity).
|
|
6
|
-
|
|
7
|
-
No cross-block references — conventions are leaf rules. Depth parameter
|
|
8
|
-
accepted for shape-uniformity; reserved for future schema additions.
|
|
9
|
-
|
|
10
|
-
Companion whole-block macro:
|
|
11
|
-
render_conventions(data) in shared/macros.md emits the test_conventions
|
|
12
|
-
and lint_command/lint_scope header fields once, then iterates rules
|
|
13
|
-
through this macro.
|
|
14
|
-
-#}
|
|
15
|
-
|
|
16
|
-
{% macro render_convention(rule, depth=0) %}
|
|
17
|
-
{% if rule %}- **{{ rule.id }}** [{{ rule.severity }}, {{ rule.enforcement }}]: {{ enforceBudget(rule.description, "conventions", "rules.items.description") }}
|
|
18
|
-
{% endif %}
|
|
19
|
-
{% endmacro %}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `decisions` block.
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/decisions.schema.json (Plan 6 / per-item-macros wave 3).
|
|
5
|
-
|
|
6
|
-
Macro signature:
|
|
7
|
-
render_decision(dec, depth=0)
|
|
8
|
-
dec — single decision object matching .decisions[*] in the schema
|
|
9
|
-
depth — integer recursion budget for cross-block reference inlining
|
|
10
|
-
|
|
11
|
-
Cross-block reference recursion (supersedes, superseded_by, related_findings,
|
|
12
|
-
related_features, related_gaps) is delegated to shared/render-helpers.md —
|
|
13
|
-
see that file for the depth contract, ambient globals, and empty-array
|
|
14
|
-
convention shared across all per-item macros.
|
|
15
|
-
|
|
16
|
-
References array (`references[]`):
|
|
17
|
-
Labelled pointers (label + optional path/lines/commit). NOT recursable —
|
|
18
|
-
references point to code paths, research docs, commit SHAs, external specs,
|
|
19
|
-
none of which are project blocks. Rendered inline as one bullet per ref.
|
|
20
|
-
-#}
|
|
21
|
-
{% from "shared/render-helpers.md" import render_id_list_block, render_id_single_block, render_optional_scalar %}
|
|
22
|
-
|
|
23
|
-
{% macro render_decision(dec, depth=0) %}
|
|
24
|
-
ID: {{ dec.id }}
|
|
25
|
-
Title: {{ dec.title }}
|
|
26
|
-
Status: {{ dec.status }}
|
|
27
|
-
Created by: {{ dec.created_by }}
|
|
28
|
-
Created at: {{ dec.created_at }}
|
|
29
|
-
{{ render_optional_scalar("Enacted by", dec.enacted_by) }}{{ render_optional_scalar("Enacted at", dec.enacted_at) }}
|
|
30
|
-
Context:
|
|
31
|
-
{{ enforceBudget(dec.context, "decisions", "decisions.items.context") }}
|
|
32
|
-
|
|
33
|
-
Decision:
|
|
34
|
-
{{ enforceBudget(dec.decision, "decisions", "decisions.items.decision") }}
|
|
35
|
-
|
|
36
|
-
Consequences:
|
|
37
|
-
{% if dec.consequences and dec.consequences | length > 0 %}{% for c in dec.consequences %} - {{ enforceBudget(c, "decisions", "decisions.items.consequences.items") }}
|
|
38
|
-
{% endfor %}{% else %} (none)
|
|
39
|
-
{% endif %}{% if dec.options_considered is defined %}Options considered:
|
|
40
|
-
{% if dec.options_considered | length > 0 %}{% for opt in dec.options_considered %} - {{ opt.label }}: {{ opt.description }}
|
|
41
|
-
{% if opt.tradeoffs %} Tradeoffs: {{ opt.tradeoffs }}
|
|
42
|
-
{% endif %}{% if opt.rejected_reason %} Rejected reason: {{ opt.rejected_reason }}
|
|
43
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
44
|
-
{% endif %}{% endif %}{{ render_id_list_block("Supersedes", dec.supersedes, depth) }}{{ render_id_single_block("Superseded by", dec.superseded_by, depth) }}{{ render_id_list_block("Related findings", dec.related_findings, depth) }}{{ render_id_list_block("Related features", dec.related_features, depth) }}{{ render_id_list_block("Related gaps", dec.related_gaps, depth) }}{% if dec.references is defined %}References:
|
|
45
|
-
{% if dec.references | length > 0 %}{% for ref in dec.references %} - {{ ref.label }}{% if ref.path %} — path: {{ ref.path }}{% if ref.lines %}:{{ ref.lines }}{% endif %}{% endif %}{% if ref.commit %} — commit: {{ ref.commit }}{% endif %}
|
|
46
|
-
{% endfor %}{% else %} (none)
|
|
47
|
-
{% endif %}{% endif %}{% endmacro %}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `domain` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/domain.schema.json. Each item is one
|
|
5
|
-
knowledge entry inside data.entries[]. Required: id, title, content,
|
|
6
|
-
category. Optional: source, confidence, related_requirements (array of
|
|
7
|
-
REQ- IDs), tags.
|
|
8
|
-
|
|
9
|
-
Cross-block reference recursion (related_requirements) is delegated to
|
|
10
|
-
shared/render-helpers.md — see that file for the depth contract, ambient
|
|
11
|
-
globals, and empty-array convention.
|
|
12
|
-
-#}
|
|
13
|
-
{% from "shared/render-helpers.md" import render_id_list_inline %}
|
|
14
|
-
|
|
15
|
-
{% macro render_domain_entry(e, depth=0) %}
|
|
16
|
-
{% if e %}- **{{ e.id }}** [{{ e.category }}]: {{ e.title }}
|
|
17
|
-
{{ enforceBudget(e.content, "domain", "entries.items.content") }}{% if e.tags %} — tags: {{ e.tags | join(", ") }}{% endif %}
|
|
18
|
-
{% if e.source %} Source: {{ e.source }}
|
|
19
|
-
{% endif %}{% if e.confidence %} Confidence: {{ e.confidence }}
|
|
20
|
-
{% endif %}{{ render_id_list_inline("Related requirements", e.related_requirements, depth) }}{% endif %}
|
|
21
|
-
{% endmacro %}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `features` block.
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/features.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
-
|
|
6
|
-
Cross-block reference recursion (dependencies, gates, blocks_resolved,
|
|
7
|
-
decisions) is delegated to shared/render-helpers.md — see that file for
|
|
8
|
-
the depth contract, ambient globals, and empty-array convention.
|
|
9
|
-
|
|
10
|
-
Nested embedded structures:
|
|
11
|
-
Each feature carries nested `stories[]` (with embedded `tasks[]`) and
|
|
12
|
-
`findings[]` (scoped-finding shape). These are NOT separate block kinds
|
|
13
|
-
— they are sub-shapes on the feature schema and have no per-item macro
|
|
14
|
-
of their own. They are rendered inline as sub-lists under the feature
|
|
15
|
-
body. Story-level `depends_on`/`gates` are rendered as bare-ID lists
|
|
16
|
-
(story IDs are scoped to the feature, not in the global index) and stay
|
|
17
|
-
inline because they use a deeper indent (4 spaces) than the helper
|
|
18
|
-
convention assumes.
|
|
19
|
-
-#}
|
|
20
|
-
{% from "shared/render-helpers.md" import render_id_list_block, render_optional_scalar %}
|
|
21
|
-
|
|
22
|
-
{% macro render_feature(feat, depth=0) %}
|
|
23
|
-
ID: {{ feat.id }}
|
|
24
|
-
Title: {{ feat.title }}
|
|
25
|
-
Status: {{ feat.status }}
|
|
26
|
-
Layer: {{ feat.layer }}
|
|
27
|
-
Created by: {{ feat.created_by }}
|
|
28
|
-
Created at: {{ feat.created_at }}
|
|
29
|
-
{{ render_optional_scalar("Modified by", feat.modified_by) }}{{ render_optional_scalar("Modified at", feat.modified_at) }}{{ render_optional_scalar("Approved by", feat.approved_by) }}{{ render_optional_scalar("Approved at", feat.approved_at) }}
|
|
30
|
-
Description:
|
|
31
|
-
{{ enforceBudget(feat.description, "features", "features.items.description") }}
|
|
32
|
-
|
|
33
|
-
{% if feat.motivation %}Motivation:
|
|
34
|
-
{{ enforceBudget(feat.motivation, "features", "features.items.motivation") }}
|
|
35
|
-
|
|
36
|
-
{% endif %}Acceptance criteria:
|
|
37
|
-
{% if feat.acceptance_criteria and feat.acceptance_criteria | length > 0 %}{% for ac in feat.acceptance_criteria %} - {{ ac }}
|
|
38
|
-
{% endfor %}{% else %} (none)
|
|
39
|
-
{% endif %}{{ render_id_list_block("Dependencies", feat.dependencies, depth) }}{{ render_id_list_block("Gates", feat.gates, depth) }}{{ render_id_list_block("Blocks resolved", feat.blocks_resolved, depth) }}{{ render_id_list_block("Decisions", feat.decisions, depth) }}Stories:
|
|
40
|
-
{% if feat.stories and feat.stories | length > 0 %}{% for s in feat.stories %} - {{ s.id }} [{{ s.status }}] {{ s.title }}
|
|
41
|
-
{% if s.description %} Description: {{ enforceBudget(s.description, "features", "features.items.stories.items.description") }}
|
|
42
|
-
{% endif %}{% if s.acceptance_criteria is defined %} Acceptance criteria: {% if s.acceptance_criteria | length > 0 %}{% for ac in s.acceptance_criteria %}{{ ac }}{% if not loop.last %}; {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
43
|
-
{% endif %}{% if s.depends_on is defined %} Depends on: {% if s.depends_on | length > 0 %}{% for dep in s.depends_on %}{{ dep }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
44
|
-
{% endif %}{% if s.gates is defined %} Gates: {% if s.gates | length > 0 %}{% for g in s.gates %}{{ g }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
45
|
-
{% endif %} Tasks:
|
|
46
|
-
{% if s.tasks and s.tasks | length > 0 %}{% for t in s.tasks %} - {{ t.id }} [{{ t.status }}] {{ t.title }}
|
|
47
|
-
{% if t.description %} Description: {{ t.description }}
|
|
48
|
-
{% endif %}{% if t.files is defined %} Files: {% if t.files | length > 0 %}{% for f in t.files %}{{ f }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
49
|
-
{% endif %}{% if t.acceptance %} Acceptance: {{ t.acceptance }}
|
|
50
|
-
{% endif %}{% if t.depends_on is defined %} Depends on: {% if t.depends_on | length > 0 %}{% for dep in t.depends_on %}{{ dep }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
51
|
-
{% endif %}{% if t.assigned_to %} Assigned to: {{ t.assigned_to }}
|
|
52
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
53
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
54
|
-
{% endif %}Findings:
|
|
55
|
-
{% if feat.findings and feat.findings | length > 0 %}{% for f in feat.findings %} - {{ f.id }} [{{ f.severity }}/{{ f.state }}] reporter={{ f.reporter }} at={{ f.created_at }}
|
|
56
|
-
Description: {{ enforceBudget(f.description, "features", "features.items.findings.items.description") }}
|
|
57
|
-
{% if f.evidence %} Evidence: {{ f.evidence }}
|
|
58
|
-
{% endif %}{% if f.category %} Category: {{ f.category }}
|
|
59
|
-
{% endif %}{% if f.resolution %} Resolution: {{ f.resolution }}
|
|
60
|
-
{% endif %}{% if f.resolved_by %} Resolved by: {{ f.resolved_by }}
|
|
61
|
-
{% endif %}{% if f.resolved_at %} Resolved at: {{ f.resolved_at }}
|
|
62
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
63
|
-
{% endif %}{% endmacro %}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `framework-gaps` block.
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/framework-gaps.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
-
|
|
6
|
-
Cross-block reference recursion (related_features, related_decisions,
|
|
7
|
-
related_issues) is delegated to shared/render-helpers.md — see that file
|
|
8
|
-
for the depth contract, ambient globals, and empty-array convention.
|
|
9
|
-
|
|
10
|
-
Naming note:
|
|
11
|
-
The canonical macro name is `render_framework_gap`. The legacy
|
|
12
|
-
`render_gap` macro lives in templates/shared/macros.md and retires
|
|
13
|
-
under Plan 8 (parallel). Plan 7 deliberately does NOT author
|
|
14
|
-
`render_gap` here.
|
|
15
|
-
|
|
16
|
-
Evidence array:
|
|
17
|
-
Each gap carries an embedded `evidence[]` of {file, lines, reference}
|
|
18
|
-
triples. These are file pointers, NOT block IDs — rendered inline as
|
|
19
|
-
sub-list, never recursed.
|
|
20
|
-
-#}
|
|
21
|
-
{% from "shared/render-helpers.md" import render_id_list_block, render_optional_scalar %}
|
|
22
|
-
|
|
23
|
-
{% macro render_framework_gap(gap, depth=0) %}
|
|
24
|
-
ID: {{ gap.id }}
|
|
25
|
-
Title: {{ gap.title }}
|
|
26
|
-
Status: {{ gap.status }}
|
|
27
|
-
Package: {{ gap.package }}
|
|
28
|
-
Created by: {{ gap.created_by }}
|
|
29
|
-
Created at: {{ gap.created_at }}
|
|
30
|
-
{{ render_optional_scalar("Priority", gap.priority) }}{{ render_optional_scalar("Layer", gap.layer) }}{{ render_optional_scalar("Canonical vocabulary", gap.canonical_vocabulary) }}{{ render_optional_scalar("Closed by", gap.closed_by) }}{{ render_optional_scalar("Closed at", gap.closed_at) }}
|
|
31
|
-
Description:
|
|
32
|
-
{{ enforceBudget(gap.description, "framework-gaps", "gaps.items.description") }}
|
|
33
|
-
|
|
34
|
-
Impact:
|
|
35
|
-
{{ enforceBudget(gap.impact, "framework-gaps", "gaps.items.impact") }}
|
|
36
|
-
|
|
37
|
-
Proposed resolution:
|
|
38
|
-
{{ enforceBudget(gap.proposed_resolution, "framework-gaps", "gaps.items.proposed_resolution") }}
|
|
39
|
-
|
|
40
|
-
Evidence:
|
|
41
|
-
{% if gap.evidence and gap.evidence | length > 0 %}{% for e in gap.evidence %} - {{ e.file }}{% if e.lines %}:{{ e.lines }}{% endif %} — {{ enforceBudget(e.reference, "framework-gaps", "gaps.items.evidence.items.reference") }}
|
|
42
|
-
{% endfor %}{% else %} (none)
|
|
43
|
-
{% endif %}{{ render_id_list_block("Related features", gap.related_features, depth) }}{{ render_id_list_block("Related decisions", gap.related_decisions, depth) }}{{ render_id_list_block("Related issues", gap.related_issues, depth) }}{% endmacro %}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `issues` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/issues.schema.json. Each item is one issue
|
|
5
|
-
inside data.issues[]. Required: id (^issue-\d{3}$), title, body, location,
|
|
6
|
-
status, category, priority, package. Optional: source, resolved_by.
|
|
7
|
-
|
|
8
|
-
No cross-block references in current schema — resolved_by is a free-form
|
|
9
|
-
commit reference, not a project-block ID. Depth parameter accepted for
|
|
10
|
-
renderer-registry shape-uniformity; reserved for future schema additions
|
|
11
|
-
(e.g., resolved_by_pr or related_decisions[]).
|
|
12
|
-
-#}
|
|
13
|
-
|
|
14
|
-
{% macro render_issue(i, depth=0) %}
|
|
15
|
-
{% if i %}- **{{ i.id }}** [{{ i.priority }}, {{ i.status }}]: {{ i.title }}
|
|
16
|
-
{{ enforceBudget(i.body, "issues", "issues.items.body") }}{% if i.location %} — {{ i.location }}{% endif %}{% if i.package %} ({{ i.package }}){% endif %}
|
|
17
|
-
{% if i.category %} Category: {{ i.category }}
|
|
18
|
-
{% endif %}{% if i.source %} Source: {{ i.source }}
|
|
19
|
-
{% endif %}{% if i.resolved_by %} Resolved by: {{ i.resolved_by }}
|
|
20
|
-
{% endif %}{% endif %}
|
|
21
|
-
{% endmacro %}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `layer-plans` block.
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/layer-plans.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
-
|
|
6
|
-
Cross-block reference recursion (related_gaps, related_features,
|
|
7
|
-
related_decisions) is delegated to shared/render-helpers.md — see that
|
|
8
|
-
file for the depth contract, ambient globals, and empty-array convention.
|
|
9
|
-
|
|
10
|
-
Nested embedded structures:
|
|
11
|
-
Each plan carries `layers[]` (each with current_blocks/target_blocks
|
|
12
|
-
sub-arrays) and `migration_phases[]`. These are NOT separate block kinds
|
|
13
|
-
— they are sub-shapes on the plan schema and rendered inline. Phase
|
|
14
|
-
`depends_on` references are scoped to phase IDs within the same plan and
|
|
15
|
-
rendered as bare-ID lists (no recursion).
|
|
16
|
-
-#}
|
|
17
|
-
{% from "shared/render-helpers.md" import render_id_list_block %}
|
|
18
|
-
|
|
19
|
-
{% macro render_layer_plan(plan, depth=0) %}
|
|
20
|
-
ID: {{ plan.id }}
|
|
21
|
-
Title: {{ plan.title }}
|
|
22
|
-
Status: {{ plan.status }}
|
|
23
|
-
Model: {{ plan.model }}
|
|
24
|
-
Created by: {{ plan.created_by }}
|
|
25
|
-
Created at: {{ plan.created_at }}
|
|
26
|
-
{% if plan.description %}
|
|
27
|
-
Description:
|
|
28
|
-
{{ enforceBudget(plan.description, "layer-plans", "plans.items.description") }}
|
|
29
|
-
|
|
30
|
-
{% endif %}Layers:
|
|
31
|
-
{% if plan.layers and plan.layers | length > 0 %}{% for l in plan.layers %} - {{ l.id }}: {{ l.name }}
|
|
32
|
-
Purpose: {{ enforceBudget(l.purpose, "layer-plans", "plans.items.layers.items.purpose") }}
|
|
33
|
-
{% if l.canonical_vocabulary %} Canonical vocabulary: {{ l.canonical_vocabulary }}
|
|
34
|
-
{% endif %}{% if l.lifetime %} Lifetime: {{ l.lifetime }}
|
|
35
|
-
{% endif %}{% if l.ownership_principle %} Ownership principle: {{ enforceBudget(l.ownership_principle, "layer-plans", "plans.items.layers.items.ownership_principle") }}
|
|
36
|
-
{% endif %} Current blocks: {% if l.current_blocks | length > 0 %}{% for cb in l.current_blocks %}{{ cb }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
37
|
-
Target blocks:
|
|
38
|
-
{% if l.target_blocks and l.target_blocks | length > 0 %}{% for tb in l.target_blocks %} - {{ tb.name }} (shape: {{ tb.shape }}){% if tb.notes %} — {{ tb.notes }}{% endif %}
|
|
39
|
-
{% endfor %}{% else %} (none)
|
|
40
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
41
|
-
{% endif %}Migration phases:
|
|
42
|
-
{% if plan.migration_phases and plan.migration_phases | length > 0 %}{% for p in plan.migration_phases %} - {{ p.id }}: {{ p.name }}{% if p.status %} [{{ p.status }}]{% endif %}
|
|
43
|
-
Description: {{ enforceBudget(p.description, "layer-plans", "plans.items.migration_phases.items.description") }}
|
|
44
|
-
Depends on: {% if p.depends_on | length > 0 %}{% for dep in p.depends_on %}{{ dep }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
45
|
-
Exit criteria:
|
|
46
|
-
{% if p.exit_criteria | length > 0 %}{% for ec in p.exit_criteria %} - {{ enforceBudget(ec, "layer-plans", "plans.items.migration_phases.items.exit_criteria.items") }}
|
|
47
|
-
{% endfor %}{% else %} (none)
|
|
48
|
-
{% endif %}{% if p.produces is defined %} Produces: {% if p.produces | length > 0 %}{% for pr in p.produces %}{{ pr }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
49
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
50
|
-
{% endif %}{{ render_id_list_block("Related gaps", plan.related_gaps, depth) }}{{ render_id_list_block("Related features", plan.related_features, depth) }}{{ render_id_list_block("Related decisions", plan.related_decisions, depth) }}{% endmacro %}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `project` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Singleton kind: the project block holds one record per repository (no
|
|
5
|
-
homogeneous items[] array). The "per-item" rendering thus operates on the
|
|
6
|
-
whole block payload as a single record. The whole-block delegator in
|
|
7
|
-
shared/macros.md passes its data argument straight through.
|
|
8
|
-
|
|
9
|
-
No cross-block references — depth parameter accepted for shape-uniformity
|
|
10
|
-
with other per-item macros; no helpers from shared/render-helpers.md are
|
|
11
|
-
needed at present.
|
|
12
|
-
|
|
13
|
-
Empty-array convention:
|
|
14
|
-
Optional list/object fields render their label only when populated. The
|
|
15
|
-
project schema makes `name`, `description`, and `core_value` required and
|
|
16
|
-
the rest optional; bare-required output is the predictable shape for
|
|
17
|
-
minimal records.
|
|
18
|
-
-#}
|
|
19
|
-
|
|
20
|
-
{% macro render_project_item(p, depth=0) %}
|
|
21
|
-
{% if p %}
|
|
22
|
-
## Project
|
|
23
|
-
**{{ p.name }}** — {{ enforceBudget(p.description, "project", "description") }}
|
|
24
|
-
{% if p.core_value %}Core value: {{ enforceBudget(p.core_value, "project", "core_value") }}{% endif %}
|
|
25
|
-
{% if p.vision %}
|
|
26
|
-
Vision: {{ enforceBudget(p.vision, "project", "vision") }}{% endif %}
|
|
27
|
-
{% if p.status %}Status: {{ p.status }}{% endif %}
|
|
28
|
-
{% if p.target_users %}
|
|
29
|
-
Target users: {{ p.target_users | join(", ") }}{% endif %}
|
|
30
|
-
{% if p.constraints %}
|
|
31
|
-
### Constraints
|
|
32
|
-
{% for c in p.constraints %}- [{{ c.type }}] {{ enforceBudget(c.description, "project", "constraints.items.description") }}
|
|
33
|
-
{% endfor %}{% endif %}
|
|
34
|
-
{% if p.scope_boundaries %}
|
|
35
|
-
### Scope
|
|
36
|
-
**In:** {% for s in p.scope_boundaries.in %}{{ s }}{% if not loop.last %}, {% endif %}{% endfor %}
|
|
37
|
-
|
|
38
|
-
**Out:** {% for s in p.scope_boundaries.out %}{{ s }}{% if not loop.last %}, {% endif %}{% endfor %}
|
|
39
|
-
{% endif %}
|
|
40
|
-
{% if p.goals %}
|
|
41
|
-
### Goals
|
|
42
|
-
{% for g in p.goals %}- **{{ g.id }}**: {{ enforceBudget(g.description, "project", "goals.items.description") }}{% if g.success_criteria %} — criteria: {% for sc in g.success_criteria %}{{ enforceBudget(sc, "project", "goals.items.success_criteria.items") }}{% if not loop.last %}; {% endif %}{% endfor %}{% endif %}
|
|
43
|
-
{% endfor %}{% endif %}
|
|
44
|
-
{% if p.repository %}Repository: {{ p.repository }}
|
|
45
|
-
{% endif %}{% if p.stack %}Stack: {{ p.stack | join(", ") }}
|
|
46
|
-
{% endif %}
|
|
47
|
-
{% endif %}
|
|
48
|
-
{% endmacro %}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `requirements` block (Plan 8 / per-item-macros wave 4).
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/requirements.schema.json. Each item is one
|
|
5
|
-
requirement inside data.requirements[]. Required: id (^REQ-\d{3,}$),
|
|
6
|
-
description, type, status, priority. Optional: acceptance_criteria,
|
|
7
|
-
source, traces_to (phase/task IDs), depends_on (other requirement IDs).
|
|
8
|
-
|
|
9
|
-
Cross-block reference recursion (traces_to, depends_on) is delegated to
|
|
10
|
-
shared/render-helpers.md — see that file for the depth contract, ambient
|
|
11
|
-
globals, and empty-array convention shared across all per-item macros.
|
|
12
|
-
-#}
|
|
13
|
-
{% from "shared/render-helpers.md" import render_id_list_inline %}
|
|
14
|
-
|
|
15
|
-
{% macro render_requirement(req, depth=0) %}
|
|
16
|
-
{% if req %}- **{{ req.id }}** [{{ req.priority }}] ({{ req.type }}, {{ req.status }}): {{ enforceBudget(req.description, "requirements", "requirements.items.description") }}{% if req.acceptance_criteria %}
|
|
17
|
-
Criteria: {% for ac in req.acceptance_criteria %}{{ enforceBudget(ac, "requirements", "requirements.items.acceptance_criteria.items") }}{% if not loop.last %}; {% endif %}{% endfor %}{% endif %}
|
|
18
|
-
{% if req.source %} Source: {{ req.source }}
|
|
19
|
-
{% endif %}{{ render_id_list_inline("Traces to", req.traces_to, depth) }}{{ render_id_list_inline("Depends on", req.depends_on, depth) }}{% endif %}
|
|
20
|
-
{% endmacro %}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `research` block.
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/research.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
-
|
|
6
|
-
Cross-block reference recursion (informs, informed_by, related_research,
|
|
7
|
-
produces_findings, supersedes, superseded_by) is delegated to
|
|
8
|
-
shared/render-helpers.md — see that file for the depth contract, ambient
|
|
9
|
-
globals, and empty-array convention.
|
|
10
|
-
|
|
11
|
-
Embedded substructures:
|
|
12
|
-
`grounding` is an object with dependencies/revisions/external_refs
|
|
13
|
-
string arrays — rendered inline as labelled sub-lists, never recursed.
|
|
14
|
-
`citations[]` carries label/path/lines/url/retrieved_at — labelled
|
|
15
|
-
pointers to source material, not block IDs; rendered inline.
|
|
16
|
-
`stale_conditions[]` and `scope[]` are simple string arrays rendered as
|
|
17
|
-
bullet sub-lists.
|
|
18
|
-
|
|
19
|
-
x-prompt-budget integration:
|
|
20
|
-
The schema annotates `findings_summary`, `question`, `method` with
|
|
21
|
-
`x-prompt-budget`. enforceBudget is wired for these per Plan 5.
|
|
22
|
-
-#}
|
|
23
|
-
{% from "shared/render-helpers.md" import render_id_list_block, render_id_single_block, render_optional_scalar %}
|
|
24
|
-
|
|
25
|
-
{% macro render_research(r, depth=0) %}
|
|
26
|
-
ID: {{ r.id }}
|
|
27
|
-
Title: {{ r.title }}
|
|
28
|
-
Status: {{ r.status }}
|
|
29
|
-
Layer: {{ r.layer }}
|
|
30
|
-
Type: {{ r.type }}
|
|
31
|
-
Created by: {{ r.created_by }}
|
|
32
|
-
Created at: {{ r.created_at }}
|
|
33
|
-
{{ render_optional_scalar("Modified by", r.modified_by) }}{{ render_optional_scalar("Modified at", r.modified_at) }}{{ render_optional_scalar("Conducted by", r.conducted_by) }}{{ render_optional_scalar("Conducted at", r.conducted_at) }}{{ render_optional_scalar("Grounded at", r.grounded_at) }}
|
|
34
|
-
Question:
|
|
35
|
-
{{ enforceBudget(r.question, "research", "research.items.question") }}
|
|
36
|
-
|
|
37
|
-
Method:
|
|
38
|
-
{{ enforceBudget(r.method, "research", "research.items.method") }}
|
|
39
|
-
|
|
40
|
-
{% if r.scope is defined %}Scope:
|
|
41
|
-
{% if r.scope | length > 0 %}{% for s in r.scope %} - {{ s }}
|
|
42
|
-
{% endfor %}{% else %} (none)
|
|
43
|
-
{% endif %}{% endif %}Findings summary:
|
|
44
|
-
{{ enforceBudget(r.findings_summary, "research", "research.items.findings_summary") }}
|
|
45
|
-
|
|
46
|
-
{% if r.findings_document %}Findings document: {{ r.findings_document }}
|
|
47
|
-
{% endif %}{% if r.grounding is defined %}Grounding:
|
|
48
|
-
{% if r.grounding.dependencies is defined %} Dependencies: {% if r.grounding.dependencies | length > 0 %}{% for d in r.grounding.dependencies %}{{ d }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
49
|
-
{% endif %}{% if r.grounding.revisions is defined %} Revisions: {% if r.grounding.revisions | length > 0 %}{% for rv in r.grounding.revisions %}{{ rv }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
50
|
-
{% endif %}{% if r.grounding.external_refs is defined %} External refs: {% if r.grounding.external_refs | length > 0 %}{% for er in r.grounding.external_refs %}{{ er }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
51
|
-
{% endif %}{% endif %}{% if r.stale_conditions is defined %}Stale conditions:
|
|
52
|
-
{% if r.stale_conditions | length > 0 %}{% for sc in r.stale_conditions %} - {{ sc }}
|
|
53
|
-
{% endfor %}{% else %} (none)
|
|
54
|
-
{% endif %}{% endif %}{% if r.citations is defined %}Citations:
|
|
55
|
-
{% if r.citations | length > 0 %}{% for c in r.citations %} - {{ c.label }}{% if c.path %} — path: {{ c.path }}{% if c.lines %}:{{ c.lines }}{% endif %}{% endif %}{% if c.url %} — url: {{ c.url }}{% endif %}{% if c.retrieved_at %} — retrieved_at: {{ c.retrieved_at }}{% endif %}
|
|
56
|
-
{% endfor %}{% else %} (none)
|
|
57
|
-
{% endif %}{% endif %}{{ render_id_list_block("Informs", r.informs, depth) }}{{ render_id_list_block("Informed by", r.informed_by, depth) }}{{ render_id_list_block("Related research", r.related_research, depth) }}{{ render_id_list_block("Produces findings", r.produces_findings, depth) }}{{ render_id_list_block("Supersedes", r.supersedes, depth) }}{{ render_id_single_block("Superseded by", r.superseded_by, depth) }}{% endmacro %}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{#-
|
|
2
|
-
Per-item macro for the `spec-reviews` block.
|
|
3
|
-
|
|
4
|
-
Block schema: .project/schemas/spec-reviews.schema.json (Plan 7 / per-item-macros wave 4).
|
|
5
|
-
|
|
6
|
-
Findings:
|
|
7
|
-
Each review carries an embedded findings registry (definitions/finding
|
|
8
|
-
in the schema). Findings are rendered inline as a sub-list under the
|
|
9
|
-
review body — they are not block items in their own right and have no
|
|
10
|
-
per-item macro of their own. Each finding's `produces_decision` (when
|
|
11
|
-
present and depth > 0) recurses into the decisions block via
|
|
12
|
-
resolve/render_recursive — that pattern stays inline because it has a
|
|
13
|
-
deeper indent (4 spaces) than the helper convention assumes and is
|
|
14
|
-
embedded in a finding-iteration loop rather than a top-level field.
|
|
15
|
-
`related_findings` on a finding refer to sibling findings within the
|
|
16
|
-
same review by their string ids; they are emitted as bare IDs (no
|
|
17
|
-
recursion — finding IDs are scoped to the review and not in the global
|
|
18
|
-
ID index).
|
|
19
|
-
|
|
20
|
-
Optional review-level scalars (target_revision, reviewer, completed_at,
|
|
21
|
-
clean) and the method body delegate to shared/render-helpers.md
|
|
22
|
-
render_optional_scalar where the shape matches.
|
|
23
|
-
-#}
|
|
24
|
-
{% from "shared/render-helpers.md" import render_optional_scalar %}
|
|
25
|
-
|
|
26
|
-
{% macro render_spec_review(rev, depth=0) %}
|
|
27
|
-
ID: {{ rev.id }}
|
|
28
|
-
Target: {{ rev.target }}
|
|
29
|
-
Status: {{ rev.status }}
|
|
30
|
-
Created by: {{ rev.created_by }}
|
|
31
|
-
Created at: {{ rev.created_at }}
|
|
32
|
-
{{ render_optional_scalar("Target revision", rev.target_revision) }}{{ render_optional_scalar("Reviewer", rev.reviewer) }}{{ render_optional_scalar("Completed at", rev.completed_at) }}{% if rev.clean is defined %}Clean: {{ rev.clean }}
|
|
33
|
-
{% endif %}{% if rev.method %}Method:
|
|
34
|
-
{{ enforceBudget(rev.method, "spec-reviews", "reviews.items.method") }}
|
|
35
|
-
|
|
36
|
-
{% endif %}{% if rev.scope is defined %}Scope:
|
|
37
|
-
{% if rev.scope | length > 0 %}{% for s in rev.scope %} - {{ s }}
|
|
38
|
-
{% endfor %}{% else %} (none)
|
|
39
|
-
{% endif %}{% endif %}Findings:
|
|
40
|
-
{% if rev.findings and rev.findings | length > 0 %}{% for f in rev.findings %} - {{ f.id }} [{{ f.severity }}/{{ f.category }}/{{ f.state }}] reporter={{ f.reporter }} at={{ f.created_at }}
|
|
41
|
-
Description: {{ enforceBudget(f.description, "spec-reviews", "reviews.items.findings.items.description") }}
|
|
42
|
-
{% if f.evidence %} Evidence: {{ f.evidence }}
|
|
43
|
-
{% endif %}{% if f.location %} Location: {{ f.location }}
|
|
44
|
-
{% endif %}{% if f.resolution %} Resolution: {{ f.resolution }}
|
|
45
|
-
{% endif %}{% if f.resolved_by %} Resolved by: {{ f.resolved_by }}
|
|
46
|
-
{% endif %}{% if f.resolved_at %} Resolved at: {{ f.resolved_at }}
|
|
47
|
-
{% endif %}{% if f.produces_decision %} Produces decision: {% if depth > 0 %}{% set loc = resolve(f.produces_decision) %}{% if loc %}
|
|
48
|
-
{{ render_recursive(loc, depth - 1) }}{% else %}{{ f.produces_decision }}{% endif %}{% else %}{{ f.produces_decision }}{% endif %}
|
|
49
|
-
{% endif %}{% if f.related_findings is defined %} Related findings: {% if f.related_findings | length > 0 %}{% for rf in f.related_findings %}{{ rf }}{% if not loop.last %}, {% endif %}{% endfor %}{% else %}(none){% endif %}
|
|
50
|
-
{% endif %}{% endfor %}{% else %} (none)
|
|
51
|
-
{% endif %}{% endmacro %}
|