product-implement
Generate a full Product Requirements Document (PRD.md) from accepted PDRs using multi-agent DAG orchestration. Reads individual PDR files, generates PRD sections from templates, validates output, and promotes accepted PDRs to memory. Use after /product-clarify.
Install
npx skills add https://github.com/tikalk/adlc-team-skills/tree/main/skills/product/product-implement
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install tikalk-adlc-team-skills@llmmart
git clone https://github.com/tikalk/adlc-team-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole tikalk/adlc-team-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
product-implement
What this skill does
Transforms accepted PDRs into a comprehensive, self-contained PRD.md using a three-phase DAG:
- Plan Agent: Analyze PDRs, detect feature-areas, generate customized DAG, get user approval
- Execute Agent: Generate sections per feature-area with mandatory checkpoint after Requirements
- Summarize Agent: Aggregate sections, resolve conflicts, produce unified
PRD.md
Output:
PRD.md(repo root) — self-contained product requirements{REPO_ROOT}/.adlc/product/sections/{feature-area}/{section}.md— intermediate section files- Accepted PDRs moved to
{REPO_ROOT}/.adlc/memory/pdr/
When to use
- After
/product-clarifyhas approved PDRs - After
/product-initto document existing product - PDR updates requiring PRD regeneration
When NOT to use
- No Accepted PDRs (run
/product-clarifyfirst) - Minor PRD edits (edit
PRD.mddirectly)
Pre-Flight Validation
Before starting, verify prerequisites:
- Check PDRs exist:
{REPO_ROOT}/.adlc/drafts/pdr/PDR-*.md - Check for Accepted PDRs: Count files with status "Accepted"
- If zero: STOP and output:
Cannot proceed: No Accepted PDRs found. Run /product-clarify to review and approve PDRs first. - If ≥1: Proceed
- If zero: STOP and output:
Three-Phase DAG Workflow
┌─────────────────────────────────────────────────────────┐
│ PHASE 1: PLAN (Plan Agent) │
│ Load PDRs → Detect Feature-Areas → Generate DAG → Approve│
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ PHASE 2: EXECUTE (Execute Agent) │
│ Overview → Problem → Goals → Metrics → Personas │
│ → [REQUIREMENTS CHECKPOINT] ← MANDATORY USER APPROVAL │
│ → NFRs → Out-of-Scope → Risks → Roadmap → PDR-Summary │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ PHASE 3: SUMMARIZE (Summarize Agent) │
│ Read sections → Detect conflicts → Resolve → PRD.md │
└─────────────────────────────────────────────────────────┘
Execution Steps
Phase 1: Plan
Step 1.1: Load and Analyze PDRs
- Read all
PDR-*.mdfiles from.adlc/drafts/pdr/ - Filter to Accepted status only
- Parse feature-area from each PDR
- Group PDRs by feature-area
Step 1.2: Detect Feature-Area Characteristics
| Characteristic | Detection Pattern | DAG Customization |
|---|---|---|
| B2B SaaS | Enterprise, admin, SSO | Include compliance sections |
| Consumer App | Mobile, freemium, social | Simplify requirements |
| Platform | API, integrations, developer | Expand NFRs |
| Marketplace | Multi-sided, transaction | Add business model sections |
Step 1.3: Generate Customized DAG
Default DAG (all 15 sections):
Document Information → Executive Summary → Overview → Problem
→ Market Opportunity → Goals → Metrics → Personas
→ [CHECKPOINT: Requirements]
→ NFRs → Out-of-Scope → Risks → Investment
→ Roadmap → Go-to-Market → PDR-Summary
Section numbering (fixed):
-
- Document Information
- 1.5 Executive Summary
-
- Overview
-
- The Problem
- 3.5 Market Opportunity
-
- Goals & Objectives
-
- Success Metrics
-
- Personas
-
- Functional Requirements
-
- Non-Functional Requirements
-
- Out of Scope
-
- Risks & Mitigation
- 10.5 Investment & Resources
-
- Roadmap & Milestones
- 11.5 Go-to-Market Strategy
-
- PDR Summary
Step 1.4: Present Plan for Approval
## DAG Execution Plan
**Feature-Areas detected**: 3
**Total sections**: 15
**Feature-Area: Core**
**PDRs**: PDR-001, PDR-005, PDR-008
**DAG**: Document Info → Executive Summary → Overview → Problem
→ Market Opportunity → Goals → Metrics → Personas
→ [Requirements Checkpoint] → NFRs → Out-of-Scope → Risks
→ Investment → Roadmap → GTM → PDR-Summary
**Approve this plan?** [Yes/Modify/Cancel]
Step 1.5: Write state.json
{
"version": "1.0",
"phase": "plan_approved",
"feature_areas": [
{
"id": "core",
"name": "Core",
"pdrs": ["PDR-001", "PDR-005"],
"dag": ["document-info", "executive-summary", "overview", "problem", ...],
"progress": {}
}
],
"checkpoint": {
"enabled": true,
"after_section": "requirements",
"status": "pending"
}
}
Phase 2: Execute
For each section in the DAG:
- Check dependencies — ensure all prerequisites completed
- Load section template —
../templates/sections/{section}.md - Generate content — fill template with PDR-derived content
- Write section file —
.adlc/product/sections/{feature-area}/{section}.md - Validate — run
scripts/bash/validate-prd.sh {section}.md - Update state.json — mark section as "completed"
Section template usage (MANDATORY):
- Read template FIRST
- Fill ALL [PLACEHOLDERS]
- NEVER generate from scratch
In-section diagrams (MANDATORY):
- Use
```mermaidcode blocks - Use
flowchartkeyword (NOT deprecatedgraph) - ASCII box-drawing characters are PROHIBITED
- Diagrams embedded in their home sections
| Section | Diagram Type | Subsection |
|---|---|---|
| 2. Overview | Feature Hierarchy (flowchart TD) |
2.4 |
| 2. Overview | Architecture (flowchart TB) |
2.5 |
| 6. Personas | User Journey (journey) |
6.4 |
| 7. Requirements | Req Dependencies (flowchart LR) |
7.4 |
| 7. Requirements | Feature Dependencies (flowchart LR) |
7.5 |
| 11. Roadmap | Gantt Chart (gantt) |
11.1 |
Requirements Checkpoint (MANDATORY):
After generating Requirements section:
## CHECKPOINT: Requirements Section Complete
The Requirements section has been generated.
**Why checkpoint here?** Requirements shapes:
- NFRs (how requirements are met)
- Out-of-Scope (what's NOT required)
- Risks (technical feasibility)
- Roadmap (priority and sequencing)
**Options**:
A) Approve — Continue to remaining sections
B) Modify — Edit requirements, then continue
C) Restart — Regenerate from Problem phase
D) Cancel — Stop execution
Phase 3: Summarize
Step 3.1: Read All Sections FROM DISK
CRITICAL: Read each section file from filesystem. Do NOT use content from memory.
- Scan
.adlc/product/sections/for all.mdfiles - Read each file
- Validate: ≥20 lines, proper headers
Step 3.2: Detect Cross-Feature-Area Conflicts
| Conflict Type | Detection | Resolution |
|---|---|---|
| Duplicate requirements | Same requirement, different wording | Standardize to PDR terminology |
| Priority mismatch | Same feature, different priority | Defer to PDR |
| Metric inconsistency | Same metric, different definition | Use PDR definition |
Step 3.3: Aggregate into PRD.md
CRITICAL: PRD.md MUST be SELF-CONTAINED.
- ALL diagrams embedded IN-SECTION
- ZERO reader-facing links to
.adlc/paths- Use in-document anchors only:
[Section 2.4](#24-feature-hierarchy)- PDR references as plain text:
PDR-078(NOT linked)
PRD structure (must match template):
# Product Requirements Document: [Product Name]
## 1. Document Information
[Quick Stats, revision history, approval]
## 1.5 Executive Summary
[Business case, ROI, recommendation]
## 2. Overview
[Product description, scope]
### 2.4 Feature Hierarchy [MERMAID flowchart TD]
### 2.5 Architecture Overview [MERMAID flowchart TB]
## 3. The Problem
[Problem statement, validation evidence]
## 3.5 Market Opportunity
[TAM/SAM/SOM, competitive landscape]
## 4. Goals & Objectives
[Primary, technical, business goals traced to PDRs]
## 5. Success Metrics
[Adoption, engagement, quality]
### 5.5 Business Outcome Metrics
### 5.6 Financial Metrics
## 6. Personas
[Primary, secondary, anti-personas]
### 6.4 User Journey [MERMAID journey]
## 7. Functional Requirements [CHECKPOINT]
[User stories, REQ-XXX IDs, priority matrix]
### 7.4 Requirement Dependencies [MERMAID flowchart LR]
### 7.5 Feature Dependencies [MERMAID flowchart LR]
## 8. Non-Functional Requirements
[Performance, security, reliability, scalability]
## 9. Out of Scope
[Feature, technical, market exclusions]
## 10. Risks & Mitigation
[Risk summary, technical, market, operational]
### 10.4 Business Risks
## 10.5 Investment & Resources
[Team, budget, ROI, go/no-go criteria]
## 11. Roadmap & Milestones
### 11.1 Roadmap Overview [MERMAID gantt]
[Milestone details with demo sentences]
### 11.2 Milestone Gates & Progress
[Per milestone: done-means definition, feature rollup, gate table, issue/evidence status — sourced from milestone PDRs]
## 11.5 Go-to-Market Strategy
[Launch phases, pricing, messaging]
## 12. PDR Summary
[Key decisions, constitution alignment — NO external links]
Phase 4: PDR Lifecycle Management (MANDATORY)
Step 4.1: Move Accepted PDRs to Memory (atomic — script-driven)
Source the PDR lifecycle library and call move_pdr for each Accepted PDR. This performs an atomic mv (no copy-then-delete duplication risk) and regenerates both scopes' indexes automatically.
source "{REPO_ROOT}/.agents/skills/product-implement/scripts/bash/pdr-lib.sh"
# Or on Windows: . "{REPO_ROOT}/.agents/skills/product-implement/scripts/powershell/pdr-lib.ps1"
for pdr_id in <list of Accepted PDR IDs>; do
move_pdr "$pdr_id" drafts memory
done
- PDRs with status "Accepted" are moved (not copied) from
.adlc/drafts/pdr/to.adlc/memory/pdr/. - Do NOT change status to "Completed" — keep status as "Accepted" so the index header ("Accepted PDRs only") remains truthful.
- Proposed/Discovered PDRs remain in drafts (not moved).
- Both
drafts/pdr/pdr.mdandmemory/pdr/pdr.mdindexes are regenerated bymove_pdr.
Step 4.2: Generate Memory PDR Index (MANDATORY — script-driven)
The move_pdr call in Step 4.1 already regenerates the memory index. To manually regenerate (e.g., after bulk edits to PDR files):
source "{REPO_ROOT}/.agents/skills/product-implement/scripts/bash/pdr-lib.sh"
generate_pdr_index memory
This writes {REPO_ROOT}/.adlc/memory/pdr/pdr.md using a frontmatter-primary + heading-fallback parser that handles both ## (H2 legacy) and ### (H3 current) metadata. Blank cells trigger a stderr warning and defaults are applied — no silent blank rows.
The generated index has this format:
# Product Decision Records (Memory)
> Auto-generated by /product-implement. Accepted PDRs only.
> Source: .adlc/memory/pdr/PDR-*.md
## PDR Index
| ID | Feature-Area | Category | Status | Date | Owner | Title |
|----|--------------|----------|--------|------|-------|-------|
| PDR-001 | control-plane | Governance | Accepted | 2026-08-04 | User/AI collaboration | Lit Factory Operating Model |
This index is consumed by team-boot for session-start injection (similar to how CDR.md is used for team-level context).
Step 4.3: Update state.json
{
"phase": "completed",
"pdr_lifecycle": {
"pdrs_promoted": [N],
"memory_pdr_moved": true,
"drafts_retained": true,
"drafts_reason": "Proposed/Discovered PDRs remain",
"memory_index_generated": true
}
}
Phase 5: Final Verification
Before marking complete, verify ALL checks:
| # | Check | Expected |
|---|---|---|
| 1 | Section files on disk | N files in .adlc/product/sections/ |
| 2 | PRD.md exists | Yes |
| 3 | PRD.md content size | >200 lines |
| 4 | PRD.md has all sections | Sections 1-12 + sub-sections |
| 5 | PRD.md is self-contained | 0 .adlc/ links |
| 6 | Diagrams embedded | ≥4 mermaid blocks |
| 7 | Memory PDRs written | .adlc/memory/pdr/PDR-*.md exist |
| 8 | Memory PDR index generated | .adlc/memory/pdr/pdr.md exists with correct table |
| 9 | state.json consistent | All sections "completed" |
Gate Rule: If ANY check fails → do NOT mark as completed. Report failures.
PDR Traceability Rules
- Every section must reference source PDRs with ID
- Every requirement (REQ-XXX) must trace to a PDR
- No content without PDR backing
- PDRs are source of truth for conflict resolution
Configuration
PDR_DRAFTS_DIR—{REPO_ROOT}/.adlc/drafts/pdrPDR_MEMORY_DIR—{REPO_ROOT}/.adlc/memory/pdrPRD_FILE—{REPO_ROOT}/PRD.mdSECTIONS_DIR—{REPO_ROOT}/.adlc/product/sectionsSTATE_FILE—{REPO_ROOT}/.adlc/product/state.json
12-Factor Alignment
- Factor III (Mission Definition): Compiles mission decisions into actionable requirements
- Factor IV (Structured Planning): DAG orchestration separates planning from execution
- Factor IX (Traceability): Every PRD element traces back to a PDR
Common Rationalizations
| Rationalization | Reality |
|---|---|
| "I'll skip the checkpoint and just generate everything." | Requirements shapes NFRs, Out-of-Scope, Risks, and Roadmap. Skipping the checkpoint risks cascading errors. |
| "The PRD can reference section files." | PRD.md MUST be self-contained. External references break when section files are moved or deleted. |
| "I don't need to move PDRs to memory." | Without promotion, drafts and memory diverge. The next clarify session sees stale data. |
Red Flags
- Generating PRD from non-Accepted PDRs — implement skips Proposed/Discovered; the PRD will be incomplete.
- Writing PRD.md directly from PDRs — content MUST come from section files to ensure validation passed.
- Missing the Requirements checkpoint — this is the cornerstone section; errors here cascade.
- Leaving
.adlc/links in PRD.md — breaks self-containment; readers cannot follow internal paths.
Verification
- Pre-flight: ≥1 Accepted PDR exists
- Plan approved by user
- state.json written with DAG
- Each section file ≥20 lines
- validate-prd.sh passes for each section
- Requirements checkpoint approved by user
- PRD.md >200 lines with all 15 sections
- Zero
.adlc/links in PRD.md - ≥4 Mermaid diagrams embedded in-section
- All requirements trace to PDRs
- Accepted PDRs moved to
.adlc/memory/pdr/ - Final completion verification: all 8 checks pass
Files (adlc-team-skills)
-
scripts
-
bash
-
migrate-pdr-frontmatter.sh 8.7 KB
#!/usr/bin/env bash # # migrate-pdr-frontmatter.sh — One-time instance repair script for adlc-workspace/.adlc/ # # This script performs a one-time repair of the adlc-workspace/.adlc/ directory: # 1. Migrates all PDR files in memory/pdr/ to YAML frontmatter (from heading-based metadata) # 2. Generates the new memory/pdr/pdr.md index (INSIDE the pdr/ directory) # 3. Deletes the old memory/pdr.md (superseded by memory/pdr/pdr.md) # 4. Moves drafts/adr/adr.md → memory/adr/adr.md (Bug 2: ADR index was in wrong directory) # 5. Deletes the 12 duplicated drafts/pdr/PDR-034..045.md files (Bug 3: PDR duplication) # 6. Regenerates drafts/pdr/pdr.md as a Proposed-only stub (Bug 3: boundary clarification) # 7. Creates drafts/adr/adr.md Proposed-only stub (for symmetry with the PDR side) # # Usage: # REPO_ROOT=/path/to/adlc-workspace bash migrate-pdr-frontmatter.sh # # or run from the adlc-workspace directory: # bash /path/to/adlc-team-skills/.agents/skills/product-implement/scripts/bash/migrate-pdr-frontmatter.sh # set -euo pipefail # Resolve REPO_ROOT — default to the adlc-workspace directory (parent of adlc-team-skills) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SKILLS_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)" # .agents/skills/ # If REPO_ROOT not set, try to detect the adlc-workspace directory if [ -z "${REPO_ROOT:-}" ]; then # Try: walk up from skills dir to find .adlc dir="$SKILLS_DIR" while [ "$dir" != "/" ]; do if [ -d "$dir/.adlc" ]; then REPO_ROOT="$dir" break fi dir="$(dirname "$dir")" done if [ -z "${REPO_ROOT:-}" ]; then echo "[ERROR] Could not find .adlc directory. Set REPO_ROOT manually." echo " REPO_ROOT=/path/to/adlc-workspace bash $0" exit 1 fi fi export REPO_ROOT echo "[INFO] REPO_ROOT = $REPO_ROOT" # Source the PDR lifecycle library source "$SCRIPT_DIR/pdr-lib.sh" # ============================================================================ # Step 1: Migrate all PDR files in memory/pdr/ to YAML frontmatter # ============================================================================ echo "" echo "=== Step 1: Migrate PDR files to YAML frontmatter ===" PDR_MEMORY_DIR="$REPO_ROOT/.adlc/memory/pdr" if [ -d "$PDR_MEMORY_DIR" ]; then migrate_pdr_dir "$PDR_MEMORY_DIR" else echo "[WARN] memory/pdr/ directory not found at $PDR_MEMORY_DIR" fi # ============================================================================ # Step 2: Generate the new memory/pdr/pdr.md index (INSIDE the pdir) # ============================================================================ echo "" echo "=== Step 2: Generate memory/pdr/pdr.md index ===" generate_pdr_index memory echo "[OK] memory/pdr/pdr.md generated" # ============================================================================ # Step 3: Delete the old memory/pdr.md (superseded by memory/pdr/pdr.md) # ============================================================================ echo "" echo "=== Step 3: Delete old memory/pdr.md ===" OLD_PDR_INDEX="$REPO_ROOT/.adlc/memory/pdr.md" if [ -f "$OLD_PDR_INDEX" ]; then rm "$OLD_PDR_INDEX" echo "[OK] Deleted old memory/pdr.md (index is now at memory/pdr/pdr.md)" else echo "[INFO] Old memory/pdr.md not found (already absent)" fi # ============================================================================ # Step 4: Move drafts/adr/adr.md → memory/adr/adr.md (Bug 2 fix) # ============================================================================ echo "" echo "=== Step 4: Relocate ADR index from drafts to memory ===" DRAFTS_ADR_INDEX="$REPO_ROOT/.adlc/drafts/adr/adr.md" MEMORY_ADR_DIR="$REPO_ROOT/.adlc/memory/adr" MEMORY_ADR_INDEX="$MEMORY_ADR_DIR/adr.md" if [ -f "$DRAFTS_ADR_INDEX" ]; then mkdir -p "$MEMORY_ADR_DIR" if [ -f "$MEMORY_ADR_INDEX" ]; then echo "[WARN] memory/adr/adr.md already exists — overwriting with drafts version" rm "$MEMORY_ADR_INDEX" fi mv "$DRAFTS_ADR_INDEX" "$MEMORY_ADR_INDEX" echo "[OK] Moved drafts/adr/adr.md → memory/adr/adr.md" else echo "[INFO] drafts/adr/adr.md not found (already moved?)" fi # ============================================================================ # Step 5: Delete the 12 duplicated drafts/pdr/PDR-034..045.md files (Bug 3 fix) # ============================================================================ echo "" echo "=== Step 5: Delete duplicated draft PDR files ===" DRAFTS_PDR_DIR="$REPO_ROOT/.adlc/drafts/pdr" deleted_count=0 for f in "$DRAFTS_PDR_DIR"/PDR-0{34,35,36,37,38,39,40,41,42,43,44,45}.md; do if [ -f "$f" ]; then rm "$f" deleted_count=$((deleted_count + 1)) fi done echo "[OK] Deleted $deleted_count duplicated PDR files from drafts/pdr/" # Also check for any other PDR files in drafts that have copies in memory for f in "$DRAFTS_PDR_DIR"/PDR-*.md; do [ -f "$f" ] || continue fname=$(basename "$f") if [ -f "$PDR_MEMORY_DIR/$fname" ]; then rm "$f" echo "[OK] Deleted additional duplicate: $fname" deleted_count=$((deleted_count + 1)) fi done echo "[INFO] Total duplicated draft PDR files deleted: $deleted_count" # ============================================================================ # Step 6: Repurpose drafts/pdr/pdr.md as a Proposed-only stub # ============================================================================ echo "" echo "=== Step 6: Repurpose drafts/pdr/pdr.md as Proposed-only stub ===" DRAFTS_PDR_INDEX="$DRAFTS_PDR_DIR/pdr.md" # First, regenerate the drafts index (will only contain Proposed PDRs if any) if [ -d "$DRAFTS_PDR_DIR" ]; then generate_pdr_index drafts # Check if the generated index has any rows pdr_rows=$(grep -c '| PDR-' "$DRAFTS_PDR_INDEX" 2>/dev/null || echo 0) if [ "$pdr_rows" -eq 0 ]; then # No Proposed PDRs — make it a stub cat > "$DRAFTS_PDR_INDEX" << 'STUB' # Product Decision Records (Drafts) > Auto-generated by /product-clarify. Proposed PDRs only. > Source: .adlc/drafts/pdr/PDR-*.md ## PDR Index | ID | Feature-Area | Category | Status | Date | Owner | Title | |----|--------------|----------|--------|------|-------|-------| _No proposed PDRs. Accepted PDRs are in `.adlc/memory/pdr/pdr.md`._ STUB echo "[OK] drafts/pdr/pdr.md is now a Proposed-only stub (no Proposed PDRs found)" else echo "[OK] drafts/pdr/pdr.md regenerated with $pdr_rows Proposed PDR(s)" fi fi # ============================================================================ # Step 7: Create drafts/adr/adr.md Proposed-only stub (for symmetry) # ============================================================================ echo "" echo "=== Step 7: Create drafts/adr/adr.md Proposed-only stub ===" DRAFTS_ADR_DIR="$REPO_ROOT/.adlc/drafts/adr" if [ -d "$DRAFTS_ADR_DIR" ] && [ ! -f "$DRAFTS_ADR_DIR/adr.md" ]; then cat > "$DRAFTS_ADR_DIR/adr.md" << 'STUB' # Architecture Decision Records (Drafts) > Auto-generated by /architect-clarify. Proposed ADRs only. > Source: .adlc/drafts/adr/ADR-*.md ## ADR Index | ID | Sub-System | Decision | Status | Date | |----|------------|----------|--------|------| _No proposed ADRs. Accepted ADRs are in `.adlc/memory/adr/adr.md`._ STUB echo "[OK] drafts/adr/adr.md Proposed-only stub created" else # If there are remaining Proposed ADRs, the drafts index should be regenerated # by the ADR setup script if [ -d "$DRAFTS_ADR_DIR" ]; then echo "[INFO] drafts/adr/adr.md already exists — regenerating" # The ADR setup script can handle this; for now just note it else echo "[INFO] drafts/adr/ directory not found — skipping" fi fi # ============================================================================ # Summary # ============================================================================ echo "" echo "============================================" echo "Instance repair complete." echo "============================================" echo "" echo "Changes made:" echo " 1. Migrated PDR files in memory/pdr/ to YAML frontmatter" echo " 2. Generated new index at memory/pdr/pdr.md" echo " 3. Deleted old memory/pdr.md" echo " 4. Moved drafts/adr/adr.md → memory/adr/adr.md" echo " 5. Deleted $deleted_count duplicated draft PDR files" echo " 6. Repurposed drafts/pdr/pdr.md as Proposed-only stub" echo " 7. Created drafts/adr/adr.md Proposed-only stub" echo "" echo "Verify with:" echo " head -20 $REPO_ROOT/.adlc/memory/pdr/PDR-001.md # should have YAML frontmatter" echo " cat $REPO_ROOT/.adlc/memory/pdr/pdr.md # should have all 45 rows populated" echo " ls $REPO_ROOT/.adlc/memory/adr/adr.md # should exist" echo " ls $REPO_ROOT/.adlc/drafts/pdr/PDR-*.md # should be empty (all deleted)" echo " ls $REPO_ROOT/.adlc/memory/pdr.md # should NOT exist (deleted)" -
pdr-lib.sh 17.8 KB
#!/usr/bin/env bash # # pdr-lib.sh — Shared PDR lifecycle library for adlc-skills product-* skills. # # Mirrors the ADR-side tooling in setup-architect.sh (generate_adr_index, move_adr, # parse_fm_field, parse_fm_title) so that the PDR side has the same structural # robustness: script-driven index generation, atomic move promotion, and a # frontmatter-primary + heading-fallback parser that handles both legacy H2 # (## Status) and current H3 (### Status) metadata. # # Bundled with each product-* skill so it works standalone. # Sourced by setup-product-*.sh scripts and callable directly. # # Usage: # source pdr-lib.sh # load functions # generate_pdr_index memory # regenerate .adlc/memory/pdr/pdr.md # generate_pdr_index drafts # regenerate .adlc/drafts/pdr/pdr.md # move_pdr 020 drafts memory # atomically move PDR-020 drafts→memory # migrate_pdr_to_frontmatter .adlc/memory/pdr/PDR-001.md # one-time legacy migration # set -euo pipefail # ============================================================================ # Project root resolution (mirror of common.sh _get_project_root) # ============================================================================ _get_project_root() { local dir dir="$(pwd)" while [ "$dir" != "/" ]; do if [ -d "$dir/.adlc" ] || [ -d "$dir/.git" ]; then echo "$dir" return 0 fi dir="$(dirname "$dir")" done pwd } # Resolve REPO_ROOT if not already set by the caller. if [ -z "${REPO_ROOT:-}" ]; then REPO_ROOT="$(_get_project_root)" fi export REPO_ROOT # ============================================================================ # YAML frontmatter parser (copied from setup-architect.sh parse_fm_field) # ============================================================================ # Parse a YAML frontmatter field from a markdown file. # Usage: parse_fm_field "file" "fieldname" # Returns the field value with quotes, inline comments, and surrounding whitespace stripped. parse_fm_field() { local file="$1" local field="$2" [ -f "$file" ] || return 0 awk -v fld="^[[:space:]]*${field}:[[:space:]]*" ' /^---[[:space:]]*$/ { fm++; next } fm == 1 && $0 ~ fld { sub(fld, "") sub(/[[:space:]]+#.*$/, "") gsub(/^["'\'']|["'\'']$/, "") gsub(/^\[|\]$/, "") sub(/^[[:space:]]+/, ""); sub(/[[:space:]]+$/, "") print exit } ' "$file" } # Extract the H1 title (first "# " line after frontmatter) from a markdown file. # Usage: parse_fm_title "file" parse_fm_title() { [ -f "$1" ] || return 0 awk '/^---[[:space:]]*$/ { fm++; next } fm >= 2 && /^#[[:space:]]+/ { sub(/^#[[:space:]]+/, ""); sub(/[[:space:]]+$/, ""); print; exit }' "$1" } # ============================================================================ # Heading-based fallback parser (handles legacy H2 and current H3 PDR files) # ============================================================================ # Parse a metadata field from Markdown headings (## or ###). # Looks for a heading line matching "^###+ <field>$", returns the next non-empty # non-heading line with ** bold markers stripped. # Usage: parse_pdr_heading_field "file" "Status" (case-sensitive field name) parse_pdr_heading_field() { local file="$1" local field="$2" [ -f "$file" ] || return 0 awk -v fld="$field" ' $0 ~ "^#+[[:space:]]*" fld "[[:space:]]*$" { found=1; next } found && /^#+/ { exit } found && NF > 0 { gsub(/\*\*/, "") sub(/^[[:space:]]+/, ""); sub(/[[:space:]]+$/, "") print exit } ' "$file" } # Extract the title from a "# PDR-NNN: <title>" or "## PDR-NNN: <title>" heading. # Strips the heading marker and "PDR-NNN:" prefix. # Usage: parse_pdr_heading_title "file" parse_pdr_heading_title() { [ -f "$1" ] || return 0 awk ' $0 ~ "^#+[[:space:]]*PDR-[0-9]+:[[:space:]]*" { sub(/^#+[[:space:]]*PDR-[0-9]+:[[:space:]]*/, "") sub(/[[:space:]]+$/, "") print exit } ' "$1" } # ============================================================================ # Combined parsers (frontmatter primary, heading fallback) # ============================================================================ # Parse a PDR metadata field: tries YAML frontmatter first, falls back to headings. # Usage: parse_pdr_field "file" "status" (frontmatter field name, lowercase hyphenated) # parse_pdr_field "file" "Status" (heading field name, Title Case) # Note: frontmatter uses lowercase hyphenated keys (status, feature-area); # headings use Title Case (Status, Feature-Area). This function tries both. parse_pdr_field() { local file="$1" local field="$2" local value="" # Try frontmatter (lowercase the field name for YAML key matching) local fm_field fm_field=$(echo "$field" | tr '[:upper:]' '[:lower:]') value=$(parse_fm_field "$file" "$fm_field") if [ -n "$value" ]; then echo "$value" return fi # Fallback: heading-based (Title Case the field name for heading matching) # Accept both "Feature-Area" and "feature-area" heading styles local title_field title_field=$(echo "$field" | awk -F'-' '{for (i=1; i<=NF; i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1' OFS='-') value=$(parse_pdr_heading_field "$file" "$title_field") if [ -n "$value" ]; then echo "$value" return fi # Try the raw field name (handles "Feature-Area" where only first letter caps) value=$(parse_pdr_heading_field "$file" "$field") if [ -n "$value" ]; then echo "$value" return fi # Empty string — caller should apply defaults echo "" } # Extract the PDR title: tries frontmatter "title" field, falls back to H1 parsing. # Usage: parse_pdr_title "file" parse_pdr_title() { [ -f "$1" ] || return 0 local value value=$(parse_fm_field "$1" "title") if [ -n "$value" ]; then echo "$value" return fi # Fallback: strip "PDR-NNN:" prefix from H1/H2 value=$(parse_pdr_heading_title "$1") if [ -n "$value" ]; then echo "$value" return fi # Last resort: bare H1 (no PDR-NNN prefix) value=$(parse_fm_title "$1") echo "$value" } # ============================================================================ # Index generation (mirrors generate_adr_index from setup-architect.sh) # ============================================================================ # Generate pdr.md index from individual PDR files. # Usage: generate_pdr_index [scope] (scope = drafts | memory; default: drafts) # Writes to: $REPO_ROOT/.adlc/{scope}/pdr/pdr.md (INSIDE the pdr/ directory) # Schema: 7 columns — ID | Feature-Area | Category | Status | Date | Owner | Title # Fails loudly on blank cells (warns to stderr; applies defaults so no row is blank). generate_pdr_index() { local scope="${1:-drafts}" local pdr_dir="$REPO_ROOT/.adlc/$scope/pdr" local index_file="$pdr_dir/pdr.md" if [ ! -d "$pdr_dir" ]; then return 0 fi local index_content="# Product Decision Records" if [ "$scope" = "memory" ]; then index_content="$index_content (Memory) > Auto-generated by /product-implement. Accepted PDRs only. > Source: .adlc/$scope/pdr/PDR-*.md" else index_content="$index_content (Drafts) > Auto-generated by /product-clarify. Proposed PDRs only. > Source: .adlc/$scope/pdr/PDR-*.md" fi index_content="$index_content ## PDR Index | ID | Feature-Area | Category | Status | Date | Owner | Title | |----|--------------|----------|--------|------|-------|-------| " # Sort PDR files numerically local f fname id title status date owner category feature_area padded_id local blank_warnings="" for f in $(ls -1 "$pdr_dir"/PDR-*.md 2>/dev/null | sort -t'-' -k2 -n); do fname=$(basename "$f") id=$(echo "$fname" | sed -E 's/PDR-([0-9]+)\.md/\1/') padded_id=$(printf "%03d" "$((10#$id))") title=$(parse_pdr_title "$f") status=$(parse_pdr_field "$f" "status") date=$(parse_pdr_field "$f" "date") owner=$(parse_pdr_field "$f" "owner") category=$(parse_pdr_field "$f" "category") feature_area=$(parse_pdr_field "$f" "feature-area") # Defaults — no silent blank cells [ -z "$status" ] && { status="Unknown"; blank_warnings="$blank_warnings\n - PDR-$padded_id: Status"; } [ -z "$date" ] && { date="YYYY-MM-DD"; blank_warnings="$blank_warnings\n - PDR-$padded_id: Date"; } [ -z "$owner" ] && { owner="Unknown"; blank_warnings="$blank_warnings\n - PDR-$padded_id: Owner"; } [ -z "$category" ] && { category="Unknown"; blank_warnings="$blank_warnings\n - PDR-$padded_id: Category"; } [ -z "$feature_area" ] && { feature_area="system"; blank_warnings="$blank_warnings\n - PDR-$padded_id: Feature-Area"; } [ -z "$title" ] && { title="PDR-$padded_id"; blank_warnings="$blank_warnings\n - PDR-$padded_id: Title"; } index_content="$index_content| PDR-$padded_id | $feature_area | $category | $status | $date | $owner | $title | " done # Write the index printf '%s\n' "$index_content" > "$index_file" # Warn on any blank cells that needed defaults if [ -n "$blank_warnings" ]; then echo "[WARN] generate_pdr_index ($scope): the following PDRs had blank metadata cells;" >&2 echo " defaults were applied. Run /product-clarify to fix the source files." >&2 printf '%b\n' "$blank_warnings" >&2 fi } # ============================================================================ # Atomic move (mirrors move_adr from setup-architect.sh) # ============================================================================ # Move a PDR from one scope to another (e.g., drafts -> memory). # Usage: move_pdr <pdr_id> [from_scope] [to_scope] # Performs an atomic mv, then regenerates both scopes' indexes. # Fails if the source file does not exist. Verifies no duplicates remain. move_pdr() { local pdr_id="$1" local from_scope="${2:-drafts}" local to_scope="${3:-memory}" local from_dir="$REPO_ROOT/.adlc/$from_scope/pdr" local to_dir="$REPO_ROOT/.adlc/$to_scope/pdr" local numeric_id numeric_id=$(echo "$pdr_id" | sed -E 's/[^0-9]//g') local padded_id padded_id=$(printf "%03d" "$((10#$numeric_id))") mkdir -p "$to_dir" if [ -f "$from_dir/PDR-$padded_id.md" ]; then mv "$from_dir/PDR-$padded_id.md" "$to_dir/PDR-$padded_id.md" else echo "[WARN] move_pdr: source file not found: $from_dir/PDR-$padded_id.md" >&2 return 1 fi # Duplicate check — the source must be gone if [ -f "$from_dir/PDR-$padded_id.md" ]; then echo "[ERROR] move_pdr: duplicate detected — PDR-$padded_id still exists in $from_scope after move" >&2 return 1 fi # Regenerate both scopes generate_pdr_index "$from_scope" generate_pdr_index "$to_scope" } # ============================================================================ # One-time migration: heading-based metadata → YAML frontmatter # ============================================================================ # Migrate a legacy PDR file (heading-based metadata) to YAML frontmatter. # Reads Status/Date/Owner/Category/Feature-Area/Title from headings, prepends # frontmatter, and preserves the body unchanged. Skips files that already have # frontmatter. Strips ** bold markers from Status. # Usage: migrate_pdr_to_frontmatter <file> migrate_pdr_to_frontmatter() { local file="$1" [ -f "$file" ] || { echo "[WARN] migrate: file not found: $file" >&2; return 1; } # Skip if already has frontmatter if head -1 "$file" | grep -q '^---[[:space:]]*$'; then return 0 fi local title status date owner category feature_area title=$(parse_pdr_heading_title "$file") status=$(parse_pdr_heading_field "$file" "Status") date=$(parse_pdr_heading_field "$file" "Date") owner=$(parse_pdr_heading_field "$file" "Owner") category=$(parse_pdr_heading_field "$file" "Category") feature_area=$(parse_pdr_heading_field "$file" "Feature-Area") # Strip ** bold markers from status status="${status//\*\*/}" # Build frontmatter local fm="--- status: ${status:-Unknown} date: ${date:-YYYY-MM-DD} owner: ${owner:-Unknown} category: ${category:-Unknown} feature-area: ${feature_area:-system} title: ${title:-Untitled} --- " # Prepend frontmatter to the original body printf '%s\n%s\n' "$fm" "$(cat "$file")" > "$file.tmp" && mv "$file.tmp" "$file" } # Migrate all PDR files in a directory. # Usage: migrate_pdr_dir <dir> migrate_pdr_dir() { local dir="$1" [ -d "$dir" ] || { echo "[WARN] migrate_pdr_dir: dir not found: $dir" >&2; return 1; } local f count=0 skipped=0 for f in "$dir"/PDR-*.md; do [ -f "$f" ] || continue if head -1 "$f" | grep -q '^---[[:space:]]*$'; then skipped=$((skipped + 1)) else migrate_pdr_to_frontmatter "$f" && count=$((count + 1)) fi done echo "[INFO] migrate_pdr_dir: migrated $count file(s), skipped $skipped (already had frontmatter)" } # ============================================================================ # Fix frontmatter: re-extract metadata from body headings and update frontmatter # ============================================================================ # Fix PDR frontmatter by re-reading heading-based metadata from the body. # For files that were migrated with incorrect/blank frontmatter (e.g., due to # a parser bug), this function re-extracts Status/Date/Owner/Category/Feature-Area/Title # from the body headings and rewrites the frontmatter block. # Usage: fix_pdr_frontmatter <file> fix_pdr_frontmatter() { local file="$1" [ -f "$file" ] || { echo "[WARN] fix_pdr_frontmatter: file not found: $file" >&2; return 1; } # Must have frontmatter to fix if ! head -1 "$file" | grep -q '^---[[:space:]]*$'; then return 0 # Not migrated yet — skip fi # Extract metadata from body headings (these are always present, even after migration) local title status date owner category feature_area title=$(parse_pdr_heading_title "$file") status=$(parse_pdr_heading_field "$file" "Status") date=$(parse_pdr_heading_field "$file" "Date") owner=$(parse_pdr_heading_field "$file" "Owner") category=$(parse_pdr_heading_field "$file" "Category") feature_area=$(parse_pdr_heading_field "$file" "Feature-Area") # Strip ** bold markers status="${status//\*\*/}" # Skip if all fields are empty (can't fix) if [ -z "$status" ] && [ -z "$date" ] && [ -z "$owner" ] && [ -z "$category" ] && [ -z "$feature_area" ] && [ -z "$title" ]; then return 0 fi # Read current frontmatter values to preserve any non-empty ones local fm_status fm_date fm_owner fm_category fm_feature_area fm_title fm_status=$(parse_fm_field "$file" "status") fm_date=$(parse_fm_field "$file" "date") fm_owner=$(parse_fm_field "$file" "owner") fm_category=$(parse_fm_field "$file" "category") fm_feature_area=$(parse_fm_field "$file" "feature-area") fm_title=$(parse_fm_field "$file" "title") # Use heading value if non-empty, else keep frontmatter value, else default [ -n "$status" ] && fm_status="$status" [ -n "$date" ] && fm_date="$date" [ -n "$owner" ] && fm_owner="$owner" [ -n "$category" ] && fm_category="$category" [ -n "$feature_area" ] && fm_feature_area="$feature_area" [ -n "$title" ] && fm_title="$title" # Defaults for any remaining blanks [ -z "$fm_status" ] && fm_status="Unknown" [ -z "$fm_date" ] && fm_date="YYYY-MM-DD" [ -z "$fm_owner" ] && fm_owner="Unknown" [ -z "$fm_category" ] && fm_category="Unknown" [ -z "$fm_feature_area" ] && fm_feature_area="system" [ -z "$fm_title" ] && fm_title="Untitled" # Build new frontmatter local new_fm="--- status: $fm_status date: $fm_date owner: $fm_owner category: $fm_category feature-area: $fm_feature_area title: $fm_title ---" # Replace the old frontmatter block (everything between the first and second `---`) # with the new frontmatter, keeping the body unchanged. local body body=$(awk ' BEGIN { fm_count = 0; printing = 0 } /^---[[:space:]]*$/ { fm_count++; if (fm_count == 2) { printing = 1; next } else { next } } fm_count >= 2 && printing { print } ' "$file") printf '%s\n\n%s\n' "$new_fm" "$body" > "$file.tmp" && mv "$file.tmp" "$file" } # Fix all PDR files in a directory. # Usage: fix_pdr_dir <dir> fix_pdr_dir() { local dir="$1" [ -d "$dir" ] || { echo "[WARN] fix_pdr_dir: dir not found: $dir" >&2; return 1; } local f count=0 for f in "$dir"/PDR-*.md; do [ -f "$f" ] || continue fix_pdr_frontmatter "$f" && count=$((count + 1)) done echo "[INFO] fix_pdr_dir: fixed $count file(s)" } # ============================================================================ # Level-agnostic Accepted counter (replaces the H3-hardcoded grep) # ============================================================================ # Count PDRs with Accepted status in a directory, handling both YAML frontmatter # and heading-based metadata (H2 or H3). Replaces setup-product-clarify.sh:14 # which hardcoded '^### Status'. # Usage: count_pdr_accepted <dir> count_pdr_accepted() { local dir="$1" [ -d "$dir" ] || return 0 local count=0 f status for f in "$dir"/PDR-*.md; do [ -f "$f" ] || continue status=$(parse_pdr_field "$f" "status") # Normalize: strip ** bold, lowercase, trim status=$(echo "$status" | sed 's/\*\*//g' | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') if [ "$status" = "accepted" ] || [ "$status" = "completed" ]; then count=$((count + 1)) fi done echo "$count" } -
setup-product-implement.sh 1.2 KB
#!/bin/bash # product-implement setup script set -euo pipefail JSON_MODE=false for arg in "$@"; do case "$arg" in --json) JSON_MODE=true ;; esac; done source "$(dirname "${BASH_SOURCE[0]}")/pdr-lib.sh" 2>/dev/null || true REPO_ROOT="${REPO_ROOT:-$(_get_project_root)}" PDR_DRAFTS_DIR="$REPO_ROOT/.adlc/drafts/pdr" PDR_MEMORY_DIR="$REPO_ROOT/.adlc/memory/pdr" PRD_FILE="$REPO_ROOT/PRD.md" SECTIONS_DIR="$REPO_ROOT/.adlc/product/sections" STATE_FILE="$REPO_ROOT/.adlc/product/state.json" mkdir -p "$PDR_DRAFTS_DIR" mkdir -p "$PDR_MEMORY_DIR" mkdir -p "$SECTIONS_DIR" mkdir -p "$REPO_ROOT/.adlc/product" ACCEPTED_COUNT=0 if [[ -d "$PDR_DRAFTS_DIR" ]]; then for f in "$PDR_DRAFTS_DIR"/PDR-*.md; do if [[ -f "$f" ]] && grep -q '^\*\*Accepted\*\*' "$f" 2>/dev/null; then ((ACCEPTED_COUNT++)) fi done fi if $JSON_MODE; then cat <<EOF {"REPO_ROOT":"$REPO_ROOT","PDR_DRAFTS_DIR":"$PDR_DRAFTS_DIR","PDR_MEMORY_DIR":"$PDR_MEMORY_DIR","PRD_FILE":"$PRD_FILE","SECTIONS_DIR":"$SECTIONS_DIR","STATE_FILE":"$STATE_FILE","accepted_count":$ACCEPTED_COUNT} EOF else echo "[INFO] product-implement setup" echo " Accepted PDRs: $ACCEPTED_COUNT" echo " PRD_FILE: $PRD_FILE" echo " SECTIONS_DIR: $SECTIONS_DIR" fi -
validate-pdr.sh 1.4 KB
#!/bin/bash # PDR Validation Script for individual PDR files # Usage: validate-pdr.sh [PDR_FILE] set -e PDR_FILE="${1:-}" if [[ -z "$PDR_FILE" || ! -f "$PDR_FILE" ]]; then echo "ERROR: PDR file not found: $PDR_FILE" echo "Usage: validate-pdr.sh <pdr-file.md>" exit 1 fi ERRORS=0 WARNINGS=0 pass() { echo " ✓ $1"; } warn() { echo " ⚠ $1"; ((WARNINGS++)); } fail() { echo " ✗ $1"; ((ERRORS++)); } echo "🔍 Validating PDR: $PDR_FILE" # Check required sections for header in "Context" "Decision" "Consequences"; do if grep -qiE "^###?\s*$header" "$PDR_FILE"; then pass "Has '$header' section" else fail "Missing '$header' section" fi done # Check status if grep -qiE '^\*\*Status\*\*' "$PDR_FILE" || grep -qiE '^\*\*(Proposed|Accepted|Discovered|Deprecated|Superseded)' "$PDR_FILE"; then pass "Has valid status" else warn "No valid status marker found" fi # Check alternatives if grep -qiE "Alternatives Considered" "$PDR_FILE"; then pass "Has 'Alternatives Considered' section" else warn "Missing 'Alternatives Considered'" fi # Check for placeholders if grep -qE '\[(Category|Problem|Decision Title|Owner)\]' "$PDR_FILE"; then warn "Contains template placeholders" fi # Summary echo "" if [[ $ERRORS -eq 0 && $WARNINGS -eq 0 ]]; then echo "✓ PDR validation passed" exit 0 elif [[ $ERRORS -eq 0 ]]; then echo "⚠ $WARNINGS warning(s)" exit 2 else echo "✗ $ERRORS error(s) and $WARNINGS warning(s)" exit 1 fi -
validate-prd.sh 13.5 KB
#!/bin/bash # PRD Validation Script v1.5.7 # v1.5.7: fix set -e abort on ((VAR++)) from 0 (pre-increment); fix REQ regex to match '- **REQ-NNN:**' canonical format; fix BRE \| alternation in REQUIRED_SECTIONS used with grep -E # Validates PRD compliance with product extension standards # Checks: Section 1 = Doc Info, in-section diagrams, Mermaid, business sections, self-contained, PDR traceability # Usage: validate-prd.sh [PRD_FILE] [--strict|--warn] # # Exit codes: # 0 = All checks passed # 1 = Critical failures (in strict mode) or validation errors # 2 = Warnings only (default warn mode) set -e # Colors for output RED='\033[0;31m' YELLOW='\033[1;33m' GREEN='\033[0;32m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration STRICT_MODE=false WARN_MODE=true PRD_FILE="${1:-PRD.md}" WARNINGS=0 ERRORS=0 # Parse arguments for arg in "$@"; do case "$arg" in --strict) STRICT_MODE=true WARN_MODE=false ;; --warn) STRICT_MODE=false WARN_MODE=true ;; --help|-h) echo "Usage: $0 [PRD_FILE] [--strict|--warn]" echo "" echo "Validates PRD compliance with product extension v1.5.6 standards" echo "" echo "Options:" echo " --strict Exit with error on any issue (default: warn only)" echo " --warn Show warnings but don't exit with error (default)" echo " --help Show this help message" echo "" echo "Examples:" echo " $0 # Validate PRD.md with warnings" echo " $0 my-prd.md --strict # Strict validation of my-prd.md" echo " $0 .adlc/product/sections/ecosystem/overview.md # Validate section" exit 0 ;; esac done # Check if file exists if [[ ! -f "$PRD_FILE" ]]; then echo -e "${RED}ERROR: PRD file not found: $PRD_FILE${NC}" exit 1 fi echo -e "${BLUE}🔍 Validating PRD: $PRD_FILE${NC}" echo -e "${BLUE}Extension Version: 1.5.7 | Mode: $([ "$STRICT_MODE" == true ] && echo "STRICT" || echo "WARN")${NC}" echo "================================================" # Function to report success pass() { echo -e "${GREEN}✓${NC} $1" } # Function to report warning warn() { if [[ "$WARN_MODE" == true ]]; then echo -e "${YELLOW}⚠ WARNING${NC}: $1" else echo -e "${RED}✗ ERROR${NC}: $1" fi ((++WARNINGS)) } # Function to report error fail() { echo -e "${RED}✗ FAIL${NC}: $1" ((++ERRORS)) } # ============================================ # CHECK 1: Section 1 is Document Information (v1.5.6) # ============================================ echo "" echo -e "${BLUE}[1/9] Checking Section 1 is Document Information...${NC}" # Get the first section header FIRST_SECTION=$(grep -E '^## [0-9]+\.?\s' "$PRD_FILE" | head -1 || echo "") if [[ -z "$FIRST_SECTION" ]]; then fail "No numbered sections found (## 1. format required)" else if echo "$FIRST_SECTION" | grep -qiE '^## 1\.\s*Document Information'; then pass "Section 1 is 'Document Information' (v1.5.6 compliant)" elif echo "$FIRST_SECTION" | grep -qiE '^## 1\.\s*Visual Summary'; then warn "Section 1 is 'Visual Summary' - v1.5.6 requires 'Document Information' as Section 1 (diagrams are now in-section)" else warn "Section 1 is: $FIRST_SECTION" warn "Expected Section 1 to be 'Document Information' per v1.5.6 template" fi fi # Check that Visual Summary does NOT exist as a separate section if grep -qiE "^## [0-9]*\.?\s*Visual Summary" "$PRD_FILE"; then warn "Found 'Visual Summary' as a separate section - v1.5.6 embeds diagrams in-section instead" else pass "No separate Visual Summary section (diagrams are embedded in-section per v1.5.6)" fi # ============================================ # CHECK 2: No ASCII Diagrams in Main Content # ============================================ echo "" echo -e "${BLUE}[2/9] Checking for ASCII diagrams...${NC}" # Box-drawing characters (Unicode range U+2500 to U+257F) ASCII_LINES=$(grep -n -P '[─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╌╍╎╏═║╒╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡╢╣╤╥╦╧╨╩╪╫╬╭╮╯╰╱╲╳╴╵╶╷╸╹╺╻╼╽╾╿]' "$PRD_FILE" 2>/dev/null || true) if [[ -n "$ASCII_LINES" ]]; then # Check context - are they in <details> blocks? OUTSIDE_DETAILS=false while IFS= read -r line; do LINE_NUM=$(echo "$line" | cut -d: -f1) # Simple check: count details tags before this line DETAILS_OPEN=$(head -n "$LINE_NUM" "$PRD_FILE" | grep -c "<details>" || true) DETAILS_CLOSE=$(head -n "$LINE_NUM" "$PRD_FILE" | grep -c "</details>" || true) if [[ $DETAILS_OPEN -le $DETAILS_CLOSE ]]; then OUTSIDE_DETAILS=true break fi done <<< "$ASCII_LINES" if [[ "$OUTSIDE_DETAILS" == true ]]; then fail "ASCII box-drawing characters found OUTSIDE <details> blocks" echo "$ASCII_LINES" | head -3 | while read line; do echo " Line: $line" done if [[ $(echo "$ASCII_LINES" | wc -l) -gt 3 ]]; then echo " ... and $(( $(echo "$ASCII_LINES" | wc -l) - 3 )) more lines" fi echo "" echo " ASCII diagrams are ONLY allowed in <details> blocks as fallbacks." echo " Main content MUST use Mermaid (\`\`\`mermaid)" else pass "ASCII characters found only in <details> blocks (allowed as fallback)" fi else pass "No ASCII box-drawing characters found" fi # ============================================ # CHECK 3: Mermaid Diagrams Present # ============================================ echo "" echo -e "${BLUE}[3/9] Checking Mermaid diagrams...${NC}" MERMAID_COUNT=$(grep -c "^\s*\`\`\`mermaid" "$PRD_FILE" || true) if [[ $MERMAID_COUNT -eq 0 ]]; then fail "No Mermaid diagrams found - MUST have at least 1" echo " Use: \`\`\`mermaid blocks with flowchart/stateDiagram/etc" elif [[ $MERMAID_COUNT -lt 2 ]]; then warn "Only $MERMAID_COUNT Mermaid diagram(s) - recommend 2+ (hierarchy, deps, flows)" else pass "Found $MERMAID_COUNT Mermaid diagrams" fi # Check for deprecated 'graph' keyword GRAPH_COUNT=$(grep -cE "^\s*graph\s+(TD|TB|LR|BT|RL)" "$PRD_FILE" || true) if [[ $GRAPH_COUNT -gt 0 ]]; then warn "Found $GRAPH_COUNT deprecated 'graph' keyword(s) - use 'flowchart' (Mermaid v10+)" fi # ============================================ # CHECK 4: No Unfilled Placeholders # ============================================ echo "" echo -e "${BLUE}[4/9] Checking for unfilled placeholders...${NC}" PLACEHOLDER_PATTERNS=( '\[PRODUCT_NAME\]' '\[FEATURE_AREA_NAME\]' '\[PDR_IDS\]' '\[DATE\]' '\[PLACEHOLDER\]' '\[TODO\]' '\[TBD\]' '\[Author\]' '\[X\.X\]' ) FOUND_PLACEHOLDERS=0 for pattern in "${PLACEHOLDER_PATTERNS[@]}"; do MATCHES=$(grep -n "$pattern" "$PRD_FILE" 2>/dev/null || true) if [[ -n "$MATCHES" ]]; then while IFS= read -r line; do fail "Unfilled placeholder: $line" done <<< "$MATCHES" FOUND_PLACEHOLDERS=$((FOUND_PLACEHOLDERS + $(echo "$MATCHES" | wc -l))) fi done if [[ $FOUND_PLACEHOLDERS -eq 0 ]]; then pass "No unfilled placeholders found" fi # ============================================ # CHECK 5: PDR Traceability # ============================================ echo "" echo -e "${BLUE}[5/9] Checking PDR traceability...${NC}" # Count requirements REQ_COUNT=$(grep -cE '^\s*[-*+]?\s*\*\*REQ-[0-9]+:?\*\*' "$PRD_FILE" || true) # Count PDR references PDR_REFS=$(grep -cE 'PDR-[0-9]+' "$PRD_FILE" || true) if [[ $REQ_COUNT -gt 0 ]]; then pass "Found $REQ_COUNT requirements (REQ-XXX format)" # Check if requirements have PDR references REQ_LINES=$(grep -nE '^\s*[-*+]?\s*\*\*REQ-[0-9]+:?\*\*' "$PRD_FILE" | cut -d: -f1) REQ_WITH_PDR=0 for line_num in $REQ_LINES; do # Check next 3 lines for PDR reference CONTEXT=$(sed -n "${line_num},$((line_num + 3))p" "$PRD_FILE") if echo "$CONTEXT" | grep -qE 'PDR-[0-9]+'; then ((++REQ_WITH_PDR)) fi done if [[ $REQ_WITH_PDR -lt $REQ_COUNT ]]; then warn "Only $REQ_WITH_PDR/$REQ_COUNT requirements have PDR traceability" echo " Each requirement MUST reference a source PDR" else pass "All requirements trace to PDRs" fi else warn "No REQ-XXX format requirements found - consider using this format for traceability" fi # ============================================ # CHECK 6: Required Sections Present # ============================================ echo "" echo -e "${BLUE}[6/9] Checking required sections...${NC}" REQUIRED_SECTIONS=( "1.*Document Information" "2.*Overview" "3.*Problem|3.*The Problem" "4.*Goals|4.*Objectives" "5.*Metrics|5.*Success Metrics" "6.*Personas" "7.*Functional Requirements|7.*Requirements" "8.*Non-Functional|8.*NFRs" "9.*Out of Scope" "10.*Risks|10.*Mitigation" "11.*Roadmap|11.*Milestones" "12.*PDR Summary|12.*Product Decision" ) MISSING_SECTIONS=0 for section_pattern in "${REQUIRED_SECTIONS[@]}"; do if ! grep -qiE "^## [0-9]*\.?.*($section_pattern)" "$PRD_FILE"; then warn "Missing or misnumbered section matching: $section_pattern" ((++MISSING_SECTIONS)) fi done if [[ $MISSING_SECTIONS -eq 0 ]]; then pass "All required sections present and numbered" fi # ============================================ # CHECK 6.5: Business Sections (v1.5.3) # ============================================ echo "" echo -e "${BLUE}[6.5/9] Checking business stakeholder sections (v1.5.6)...${NC}" BUSINESS_SECTIONS=( "1\.5.*Executive Summary" "3\.5.*Market Opportunity" "10\.5.*Investment" "11\.5.*Go-to-Market" ) MISSING_BUSINESS=0 for biz_pattern in "${BUSINESS_SECTIONS[@]}"; do if grep -qiE "^## $biz_pattern" "$PRD_FILE"; then pass "Found business section: $biz_pattern" else warn "Missing business section: $biz_pattern (recommended for stakeholder PRDs)" ((++MISSING_BUSINESS)) fi done if [[ $MISSING_BUSINESS -eq 0 ]]; then pass "All 4 business stakeholder sections present" fi # ============================================ # CHECK 6.6: Self-Contained PRD (v1.5.3) # ============================================ echo "" echo -e "${BLUE}[6.6/9] Checking self-contained PRD (v1.5.6 - no external .adlc/ links)...${NC}" # Check for reader-facing links to .adlc/ paths EXTERNAL_LINKS=$(grep -nE '\]\(\.adlc/' "$PRD_FILE" 2>/dev/null || true) # Exclude links inside HTML comments EXTERNAL_LINKS_FILTERED="" if [[ -n "$EXTERNAL_LINKS" ]]; then while IFS= read -r line; do LINE_NUM=$(echo "$line" | cut -d: -f1) LINE_CONTENT=$(sed -n "${LINE_NUM}p" "$PRD_FILE") # Skip if inside HTML comment if ! echo "$LINE_CONTENT" | grep -q '<!--'; then EXTERNAL_LINKS_FILTERED="${EXTERNAL_LINKS_FILTERED}${line}\n" fi done <<< "$EXTERNAL_LINKS" fi if [[ -n "$EXTERNAL_LINKS_FILTERED" ]]; then warn "PRD contains reader-facing links to .adlc/ files (should be self-contained)" echo -e "$EXTERNAL_LINKS_FILTERED" | head -5 | while read line; do [[ -n "$line" ]] && echo " $line" done echo " Use in-document anchors instead: [Section 1.1](#11-feature-hierarchy)" else pass "PRD is self-contained (no reader-facing .adlc/ links)" fi # ============================================ # CHECK 7: Constitution Alignment Claims # ============================================ echo "" echo -e "${BLUE}[7/9] Checking constitution alignment...${NC}" if grep -qi "Constitution Alignment\|Aligns with Constitution" "$PRD_FILE"; then pass "Constitution alignment section found" # Check if constitution is populated (not just template) CONST_FILE=".adlc/memory/constitution.md" if [[ -f "$CONST_FILE" ]]; then if grep -qE '\[PRINCIPLE_[0-9]+_NAME\]|\[PROJECT_NAME\]' "$CONST_FILE" 2>/dev/null; then warn "Constitution file contains template placeholders - populate or remove alignment claims" else pass "Constitution file appears to be populated" fi else warn "Constitution file not found at $CONST_FILE" fi else warn "No constitution alignment section found (recommended but not required)" fi # ============================================ # SUMMARY # ============================================ echo "" echo "================================================" echo -e "${BLUE}Validation Summary${NC}" echo "================================================" if [[ $ERRORS -eq 0 && $WARNINGS -eq 0 ]]; then echo -e "${GREEN}✓ All checks passed! PRD is compliant with v1.5.6${NC}" echo "" echo "You may proceed to mark sections as 'completed'" exit 0 elif [[ $ERRORS -eq 0 ]]; then echo -e "${YELLOW}⚠ $WARNINGS warning(s) found${NC}" echo " PRD is usable but has issues that should be addressed" echo "" if [[ "$STRICT_MODE" == true ]]; then echo -e "${RED}Exiting with error (strict mode)${NC}" echo " Fix all warnings before marking 'completed'" exit 1 else echo " Run with --strict to enforce no warnings" exit 2 fi else echo -e "${RED}✗ $ERRORS error(s) and $WARNINGS warning(s) found${NC}" echo "" echo "PRD is NON-COMPLIANT with v1.5.6 standards" echo "Fix all errors before proceeding" exit 1 fi
-
-
powershell
-
pdr-lib.ps1 10.7 KB · in bundle
-
setup-product-implement.ps1 1.3 KB · in bundle
-
-
-
SKILL.md 15 KB
--- name: product-implement description: Use when accepted PDRs exist and PRD.md must be generated or updated. disable-model-invocation: true --- # product-implement ## What this skill does Transforms **accepted PDRs** into a comprehensive, self-contained `PRD.md` using a **three-phase DAG**: 1. **Plan Agent**: Analyze PDRs, detect feature-areas, generate customized DAG, get user approval 2. **Execute Agent**: Generate sections per feature-area with **mandatory checkpoint after Requirements** 3. **Summarize Agent**: Aggregate sections, resolve conflicts, produce unified `PRD.md` **Output**: - `PRD.md` (repo root) — self-contained product requirements - `{REPO_ROOT}/.adlc/product/sections/{feature-area}/{section}.md` — intermediate section files - Accepted PDRs **moved** to `{REPO_ROOT}/.adlc/memory/pdr/` ## When to use - After `/product-clarify` has approved PDRs - After `/product-init` to document existing product - PDR updates requiring PRD regeneration ## When NOT to use - No Accepted PDRs (run `/product-clarify` first) - Minor PRD edits (edit `PRD.md` directly) ## Pre-Flight Validation **Before starting, verify prerequisites:** 1. **Check PDRs exist**: `{REPO_ROOT}/.adlc/drafts/pdr/PDR-*.md` 2. **Check for Accepted PDRs**: Count files with status "Accepted" - If **zero**: STOP and output: ``` Cannot proceed: No Accepted PDRs found. Run /product-clarify to review and approve PDRs first. ``` - If ≥1: Proceed ## Three-Phase DAG Workflow ``` ┌─────────────────────────────────────────────────────────┐ │ PHASE 1: PLAN (Plan Agent) │ │ Load PDRs → Detect Feature-Areas → Generate DAG → Approve│ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ PHASE 2: EXECUTE (Execute Agent) │ │ Overview → Problem → Goals → Metrics → Personas │ │ → [REQUIREMENTS CHECKPOINT] ← MANDATORY USER APPROVAL │ │ → NFRs → Out-of-Scope → Risks → Roadmap → PDR-Summary │ └─────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────┐ │ PHASE 3: SUMMARIZE (Summarize Agent) │ │ Read sections → Detect conflicts → Resolve → PRD.md │ └─────────────────────────────────────────────────────────┘ ``` ## Execution Steps ### Phase 1: Plan **Step 1.1: Load and Analyze PDRs** 1. Read all `PDR-*.md` files from `.adlc/drafts/pdr/` 2. Filter to **Accepted** status only 3. Parse feature-area from each PDR 4. Group PDRs by feature-area **Step 1.2: Detect Feature-Area Characteristics** | Characteristic | Detection Pattern | DAG Customization | |---------------|-------------------|-------------------| | B2B SaaS | Enterprise, admin, SSO | Include compliance sections | | Consumer App | Mobile, freemium, social | Simplify requirements | | Platform | API, integrations, developer | Expand NFRs | | Marketplace | Multi-sided, transaction | Add business model sections | **Step 1.3: Generate Customized DAG** **Default DAG** (all 15 sections): ``` Document Information → Executive Summary → Overview → Problem → Market Opportunity → Goals → Metrics → Personas → [CHECKPOINT: Requirements] → NFRs → Out-of-Scope → Risks → Investment → Roadmap → Go-to-Market → PDR-Summary ``` **Section numbering** (fixed): - 1. Document Information - 1.5 Executive Summary - 2. Overview - 3. The Problem - 3.5 Market Opportunity - 4. Goals & Objectives - 5. Success Metrics - 6. Personas - 7. Functional Requirements - 8. Non-Functional Requirements - 9. Out of Scope - 10. Risks & Mitigation - 10.5 Investment & Resources - 11. Roadmap & Milestones - 11.5 Go-to-Market Strategy - 12. PDR Summary **Step 1.4: Present Plan for Approval** ```markdown ## DAG Execution Plan **Feature-Areas detected**: 3 **Total sections**: 15 **Feature-Area: Core** **PDRs**: PDR-001, PDR-005, PDR-008 **DAG**: Document Info → Executive Summary → Overview → Problem → Market Opportunity → Goals → Metrics → Personas → [Requirements Checkpoint] → NFRs → Out-of-Scope → Risks → Investment → Roadmap → GTM → PDR-Summary **Approve this plan?** [Yes/Modify/Cancel] ``` **Step 1.5: Write state.json** ```json { "version": "1.0", "phase": "plan_approved", "feature_areas": [ { "id": "core", "name": "Core", "pdrs": ["PDR-001", "PDR-005"], "dag": ["document-info", "executive-summary", "overview", "problem", ...], "progress": {} } ], "checkpoint": { "enabled": true, "after_section": "requirements", "status": "pending" } } ``` ### Phase 2: Execute For each section in the DAG: 1. **Check dependencies** — ensure all prerequisites completed 2. **Load section template** — `../templates/sections/{section}.md` 3. **Generate content** — fill template with PDR-derived content 4. **Write section file** — `.adlc/product/sections/{feature-area}/{section}.md` 5. **Validate** — run `scripts/bash/validate-prd.sh {section}.md` 6. **Update state.json** — mark section as "completed" **Section template usage** (MANDATORY): - Read template FIRST - Fill ALL [PLACEHOLDERS] - NEVER generate from scratch **In-section diagrams** (MANDATORY): - Use ` ```mermaid ` code blocks - Use `flowchart` keyword (NOT deprecated `graph`) - ASCII box-drawing characters are PROHIBITED - Diagrams embedded in their home sections | Section | Diagram Type | Subsection | |---------|-------------|------------| | 2. Overview | Feature Hierarchy (`flowchart TD`) | 2.4 | | 2. Overview | Architecture (`flowchart TB`) | 2.5 | | 6. Personas | User Journey (`journey`) | 6.4 | | 7. Requirements | Req Dependencies (`flowchart LR`) | 7.4 | | 7. Requirements | Feature Dependencies (`flowchart LR`) | 7.5 | | 11. Roadmap | Gantt Chart (`gantt`) | 11.1 | **Requirements Checkpoint** (MANDATORY): After generating Requirements section: ```markdown ## CHECKPOINT: Requirements Section Complete The Requirements section has been generated. **Why checkpoint here?** Requirements shapes: - NFRs (how requirements are met) - Out-of-Scope (what's NOT required) - Risks (technical feasibility) - Roadmap (priority and sequencing) **Options**: A) Approve — Continue to remaining sections B) Modify — Edit requirements, then continue C) Restart — Regenerate from Problem phase D) Cancel — Stop execution ``` ### Phase 3: Summarize **Step 3.1: Read All Sections FROM DISK** > CRITICAL: Read each section file from filesystem. Do NOT use content from memory. 1. Scan `.adlc/product/sections/` for all `.md` files 2. Read each file 3. Validate: ≥20 lines, proper headers **Step 3.2: Detect Cross-Feature-Area Conflicts** | Conflict Type | Detection | Resolution | |--------------|-----------|------------| | Duplicate requirements | Same requirement, different wording | Standardize to PDR terminology | | Priority mismatch | Same feature, different priority | Defer to PDR | | Metric inconsistency | Same metric, different definition | Use PDR definition | **Step 3.3: Aggregate into PRD.md** > CRITICAL: PRD.md MUST be SELF-CONTAINED. > - ALL diagrams embedded IN-SECTION > - ZERO reader-facing links to `.adlc/` paths > - Use in-document anchors only: `[Section 2.4](#24-feature-hierarchy)` > - PDR references as plain text: `PDR-078` (NOT linked) **PRD structure** (must match template): ```markdown # Product Requirements Document: [Product Name] ## 1. Document Information [Quick Stats, revision history, approval] ## 1.5 Executive Summary [Business case, ROI, recommendation] ## 2. Overview [Product description, scope] ### 2.4 Feature Hierarchy [MERMAID flowchart TD] ### 2.5 Architecture Overview [MERMAID flowchart TB] ## 3. The Problem [Problem statement, validation evidence] ## 3.5 Market Opportunity [TAM/SAM/SOM, competitive landscape] ## 4. Goals & Objectives [Primary, technical, business goals traced to PDRs] ## 5. Success Metrics [Adoption, engagement, quality] ### 5.5 Business Outcome Metrics ### 5.6 Financial Metrics ## 6. Personas [Primary, secondary, anti-personas] ### 6.4 User Journey [MERMAID journey] ## 7. Functional Requirements [CHECKPOINT] [User stories, REQ-XXX IDs, priority matrix] ### 7.4 Requirement Dependencies [MERMAID flowchart LR] ### 7.5 Feature Dependencies [MERMAID flowchart LR] ## 8. Non-Functional Requirements [Performance, security, reliability, scalability] ## 9. Out of Scope [Feature, technical, market exclusions] ## 10. Risks & Mitigation [Risk summary, technical, market, operational] ### 10.4 Business Risks ## 10.5 Investment & Resources [Team, budget, ROI, go/no-go criteria] ## 11. Roadmap & Milestones ### 11.1 Roadmap Overview [MERMAID gantt] [Milestone details with demo sentences] ### 11.2 Milestone Gates & Progress [Per milestone: done-means definition, feature rollup, gate table, issue/evidence status — sourced from milestone PDRs] ## 11.5 Go-to-Market Strategy [Launch phases, pricing, messaging] ## 12. PDR Summary [Key decisions, constitution alignment — NO external links] ``` ### Phase 4: PDR Lifecycle Management (MANDATORY) **Step 4.1: Move Accepted PDRs to Memory (atomic — script-driven)** Source the PDR lifecycle library and call `move_pdr` for each Accepted PDR. This performs an atomic `mv` (no copy-then-delete duplication risk) and regenerates both scopes' indexes automatically. ```bash source "{REPO_ROOT}/.agents/skills/product-implement/scripts/bash/pdr-lib.sh" # Or on Windows: . "{REPO_ROOT}/.agents/skills/product-implement/scripts/powershell/pdr-lib.ps1" for pdr_id in <list of Accepted PDR IDs>; do move_pdr "$pdr_id" drafts memory done ``` - PDRs with status "Accepted" are moved (not copied) from `.adlc/drafts/pdr/` to `.adlc/memory/pdr/`. - **Do NOT change status to "Completed"** — keep status as "Accepted" so the index header ("Accepted PDRs only") remains truthful. - Proposed/Discovered PDRs remain in drafts (not moved). - Both `drafts/pdr/pdr.md` and `memory/pdr/pdr.md` indexes are regenerated by `move_pdr`. **Step 4.2: Generate Memory PDR Index (MANDATORY — script-driven)** The `move_pdr` call in Step 4.1 already regenerates the memory index. To manually regenerate (e.g., after bulk edits to PDR files): ```bash source "{REPO_ROOT}/.agents/skills/product-implement/scripts/bash/pdr-lib.sh" generate_pdr_index memory ``` This writes `{REPO_ROOT}/.adlc/memory/pdr/pdr.md` using a frontmatter-primary + heading-fallback parser that handles both `##` (H2 legacy) and `###` (H3 current) metadata. Blank cells trigger a stderr warning and defaults are applied — no silent blank rows. The generated index has this format: ```markdown # Product Decision Records (Memory) > Auto-generated by /product-implement. Accepted PDRs only. > Source: .adlc/memory/pdr/PDR-*.md ## PDR Index | ID | Feature-Area | Category | Status | Date | Owner | Title | |----|--------------|----------|--------|------|-------|-------| | PDR-001 | control-plane | Governance | Accepted | 2026-08-04 | User/AI collaboration | Lit Factory Operating Model | ``` This index is consumed by `team-boot` for session-start injection (similar to how `CDR.md` is used for team-level context). **Step 4.3: Update state.json** ```json { "phase": "completed", "pdr_lifecycle": { "pdrs_promoted": [N], "memory_pdr_moved": true, "drafts_retained": true, "drafts_reason": "Proposed/Discovered PDRs remain", "memory_index_generated": true } } ``` ### Phase 5: Final Verification Before marking complete, verify ALL checks: | # | Check | Expected | |---|-------|----------| | 1 | Section files on disk | N files in `.adlc/product/sections/` | | 2 | PRD.md exists | Yes | | 3 | PRD.md content size | >200 lines | | 4 | PRD.md has all sections | Sections 1-12 + sub-sections | | 5 | PRD.md is self-contained | 0 `.adlc/` links | | 6 | Diagrams embedded | ≥4 `mermaid` blocks | | 7 | Memory PDRs written | `.adlc/memory/pdr/PDR-*.md` exist | | 8 | Memory PDR index generated | `.adlc/memory/pdr/pdr.md` exists with correct table | | 9 | state.json consistent | All sections "completed" | **Gate Rule**: If ANY check fails → do NOT mark as completed. Report failures. ## PDR Traceability Rules - **Every section** must reference source PDRs with ID - **Every requirement** (REQ-XXX) must trace to a PDR - **No content** without PDR backing - **PDRs are source of truth** for conflict resolution ## Configuration - `PDR_DRAFTS_DIR` — `{REPO_ROOT}/.adlc/drafts/pdr` - `PDR_MEMORY_DIR` — `{REPO_ROOT}/.adlc/memory/pdr` - `PRD_FILE` — `{REPO_ROOT}/PRD.md` - `SECTIONS_DIR` — `{REPO_ROOT}/.adlc/product/sections` - `STATE_FILE` — `{REPO_ROOT}/.adlc/product/state.json` ## 12-Factor Alignment - **Factor III (Mission Definition)**: Compiles mission decisions into actionable requirements - **Factor IV (Structured Planning)**: DAG orchestration separates planning from execution - **Factor IX (Traceability)**: Every PRD element traces back to a PDR ## Common Rationalizations | Rationalization | Reality | |-----------------|---------| | "I'll skip the checkpoint and just generate everything." | Requirements shapes NFRs, Out-of-Scope, Risks, and Roadmap. Skipping the checkpoint risks cascading errors. | | "The PRD can reference section files." | PRD.md MUST be self-contained. External references break when section files are moved or deleted. | | "I don't need to move PDRs to memory." | Without promotion, drafts and memory diverge. The next clarify session sees stale data. | ## Red Flags - **Generating PRD from non-Accepted PDRs** — implement skips Proposed/Discovered; the PRD will be incomplete. - **Writing PRD.md directly from PDRs** — content MUST come from section files to ensure validation passed. - **Missing the Requirements checkpoint** — this is the cornerstone section; errors here cascade. - **Leaving `.adlc/` links in PRD.md** — breaks self-containment; readers cannot follow internal paths. ## Verification - [ ] Pre-flight: ≥1 Accepted PDR exists - [ ] Plan approved by user - [ ] state.json written with DAG - [ ] Each section file ≥20 lines - [ ] validate-prd.sh passes for each section - [ ] Requirements checkpoint approved by user - [ ] PRD.md >200 lines with all 15 sections - [ ] Zero `.adlc/` links in PRD.md - [ ] ≥4 Mermaid diagrams embedded in-section - [ ] All requirements trace to PDRs - [ ] Accepted PDRs moved to `.adlc/memory/pdr/` - [ ] Final completion verification: all 8 checks pass
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.