From ae3163a61fcb25e306f7c40c835cac860443263d Mon Sep 17 00:00:00 2001 From: Sean Chatman <136349053+seanchatmangpt@users.noreply.github.com> Date: Fri, 19 Dec 2025 21:58:11 -0800 Subject: [PATCH 1/3] feat: Add RDF-first specification architecture (ggen integration) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integrate ggen v6 RDF-first architecture into spec-kit, enabling deterministic ontology-driven specification generation following the constitutional equation: spec.md = μ(feature.ttl) ## Core Architecture Changes ### 1. Constitutional Equation - TTL files (Turtle/RDF) are the source of truth - Markdown files are generated artifacts (never manually edited) - SHACL shapes enforce constraints - Idempotent transformations (μ∘μ = μ) - Cryptographic provenance receipts ### 2. Infrastructure Updates **Scripts (RDF-first support):** - `scripts/bash/check-prerequisites.sh` - Returns TTL paths as primary sources - Detects RDF vs. legacy features (checks ontology/ + ggen.toml) - Validates TTL files first, falls back to MD for backward compatibility - JSON output includes: TTL_SOURCES, ONTOLOGY_DIR, GENERATED_DIR - `scripts/bash/common.sh` - Extended path variables for RDF architecture - Added TTL source paths: FEATURE_SPEC_TTL, IMPL_PLAN_TTL, TASKS_TTL - Added generated paths: ontology/, generated/, templates/ - SPECIFY_FEATURE env var support for exact branch matching - `scripts/bash/setup-plan.sh` - Creates plan.ttl from templates - Auto-detects RDF-first features - Creates ontology/plan.ttl from template - Symlinks templates/plan.tera - Maintains backward compatibility for legacy MD-based features ### 3. Tera Templates (Markdown Generation) **New templates for RDF → Markdown transformation:** - `templates/plan.tera` (151 lines) - Renders plan.md from plan.ttl - Technology stack, phases, decisions, risks, dependencies - `templates/tasks.tera` (148 lines) - Renders tasks.md from tasks.ttl - Phase-based organization, dependency tracking, parallelization - `templates/constitution.tera` (173 lines) - Renders constitution.md - Core principles, build standards, workflow rules, governance ### 4. RDF Helper Templates (Turtle/RDF Sources) **Complete TTL template library (10 templates):** - `templates/rdf-helpers/user-story.ttl.template` - User story instances with acceptance scenarios - `templates/rdf-helpers/functional-requirement.ttl.template` - Functional requirements - `templates/rdf-helpers/success-criterion.ttl.template` - Success criteria with metrics - `templates/rdf-helpers/entity.ttl.template` - Domain entity definitions - `templates/rdf-helpers/edge-case.ttl.template` - Edge case scenarios (NEW) - `templates/rdf-helpers/assumption.ttl.template` - Assumption instances (NEW) - `templates/rdf-helpers/plan-decision.ttl.template` - Architectural decisions (NEW) - `templates/rdf-helpers/task.ttl.template` - Individual task instances (NEW) - `templates/rdf-helpers/plan.ttl.template` - Complete plan structure (NEW, 2.3KB) - `templates/rdf-helpers/tasks.ttl.template` - Complete task breakdown (NEW, 3.1KB) ### 5. Documentation **Comprehensive RDF workflow documentation:** - `docs/RDF_WORKFLOW_GUIDE.md` (19KB) - Complete workflow guide - Constitutional equation explanation - Five-stage pipeline (μ₁→μ₂→μ₃→μ₄→μ₅) - SHACL validation guide with error examples - Template system explanation - Troubleshooting common issues - End-to-end examples - `docs/GGEN_RDF_README.md` - ggen-specific RDF integration overview ## Key Features ### SHACL Validation - Priority values MUST be "P1", "P2", or "P3" (SHACL enforced) - Dates in YYYY-MM-DD format with ^^xsd:date - User stories require minimum 1 acceptance scenario - Automatic validation during ggen render ### Five-Stage Pipeline 1. **μ₁ (Normalization)** - Canonicalize RDF + SHACL validation 2. **μ₂ (Extraction)** - SPARQL queries extract data 3. **μ₃ (Emission)** - Tera templates render markdown 4. **μ₄ (Canonicalization)** - Format markdown 5. **μ₅ (Receipt)** - Generate cryptographic hash ### Backward Compatibility - Legacy MD-based features continue to work - Auto-detection of RDF vs. legacy format - Graceful fallback when TTL files missing - SPECIFY_FEATURE env var for multi-feature branches ## Directory Structure (RDF-first features) ``` specs/NNN-feature-name/ ├── ontology/ # SOURCE OF TRUTH │ ├── feature-content.ttl │ ├── plan.ttl │ ├── tasks.ttl │ └── spec-kit-schema.ttl (symlink) ├── generated/ # GENERATED ARTIFACTS │ ├── spec.md │ ├── plan.md │ └── tasks.md ├── templates/ # TERA TEMPLATES (symlinks) │ ├── spec.tera │ ├── plan.tera │ └── tasks.tera ├── ggen.toml # GGEN V6 CONFIG └── checklists/ └── requirements.md ``` ## Usage Examples ### Create RDF-first specification: ```bash /speckit.specify "Add TTL validation command" # Creates: ontology/feature-content.ttl # Edit TTL source vim specs/005-feature/ontology/feature-content.ttl # Validate against SHACL ggen validate ontology/feature-content.ttl --shapes ontology/spec-kit-schema.ttl # Generate markdown ggen render templates/spec.tera ontology/feature-content.ttl > generated/spec.md ``` ### Create implementation plan: ```bash /speckit.plan # Creates: ontology/plan.ttl # Generate markdown ggen render templates/plan.tera ontology/plan.ttl > generated/plan.md ``` ### Create task breakdown: ```bash /speckit.tasks # Creates: ontology/tasks.ttl # Generate markdown ggen render templates/tasks.tera ontology/tasks.ttl > generated/tasks.md ``` ## Integration Notes This branch integrates ggen v6's RDF-first architecture into spec-kit, enabling: - Deterministic specification generation - SHACL-enforced quality constraints - Cryptographic provenance tracking - Idempotent transformations - Complete Turtle/RDF template library For complete workflow documentation, see: docs/RDF_WORKFLOW_GUIDE.md 🤖 Generated with ggen v6 ontology-driven specification system --- docs/GGEN_RDF_README.md | 312 +++++++ docs/RDF_WORKFLOW_GUIDE.md | 876 ++++++++++++++++++ scripts/bash/check-prerequisites.sh | 155 +++- scripts/bash/common.sh | 27 +- scripts/bash/setup-plan.sh | 83 +- templates/constitution.tera | 210 +++++ templates/plan.tera | 187 ++++ templates/rdf-helpers/assumption.ttl.template | 23 + templates/rdf-helpers/edge-case.ttl.template | 23 + templates/rdf-helpers/entity.ttl.template | 35 + .../functional-requirement.ttl.template | 29 + .../rdf-helpers/plan-decision.ttl.template | 29 + templates/rdf-helpers/plan.ttl.template | 133 +++ .../success-criterion.ttl.template | 44 + templates/rdf-helpers/task.ttl.template | 56 ++ templates/rdf-helpers/tasks.ttl.template | 149 +++ templates/rdf-helpers/user-story.ttl.template | 39 + templates/tasks.tera | 150 +++ 18 files changed, 2509 insertions(+), 51 deletions(-) create mode 100644 docs/GGEN_RDF_README.md create mode 100644 docs/RDF_WORKFLOW_GUIDE.md create mode 100644 templates/constitution.tera create mode 100644 templates/plan.tera create mode 100644 templates/rdf-helpers/assumption.ttl.template create mode 100644 templates/rdf-helpers/edge-case.ttl.template create mode 100644 templates/rdf-helpers/entity.ttl.template create mode 100644 templates/rdf-helpers/functional-requirement.ttl.template create mode 100644 templates/rdf-helpers/plan-decision.ttl.template create mode 100644 templates/rdf-helpers/plan.ttl.template create mode 100644 templates/rdf-helpers/success-criterion.ttl.template create mode 100644 templates/rdf-helpers/task.ttl.template create mode 100644 templates/rdf-helpers/tasks.ttl.template create mode 100644 templates/rdf-helpers/user-story.ttl.template create mode 100644 templates/tasks.tera diff --git a/docs/GGEN_RDF_README.md b/docs/GGEN_RDF_README.md new file mode 100644 index 0000000000..aaae8ac973 --- /dev/null +++ b/docs/GGEN_RDF_README.md @@ -0,0 +1,312 @@ +# .specify - RDF-First Specification System + +## Constitutional Equation + +``` +spec.md = μ(feature.ttl) +``` + +**Core Principle**: All specifications are Turtle/RDF ontologies. Markdown files are **generated** from TTL using Tera templates. + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ RDF Ontology (Source of Truth) │ +│ .ttl files define: user stories, requirements, entities │ +└─────────────────┬───────────────────────────────────────────┘ + │ + │ SPARQL queries + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Tera Template Engine │ +│ spec.tera template applies transformations │ +└─────────────────┬───────────────────────────────────────────┘ + │ + │ Rendering + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Markdown Artifact (Generated, Do Not Edit) │ +│ spec.md, plan.md, tasks.md for GitHub viewing │ +└─────────────────────────────────────────────────────────────┘ +``` + +## Directory Structure + +``` +.specify/ +├── ontology/ # Ontology schemas +│ └── spec-kit-schema.ttl # Vocabulary definitions (SHACL shapes, classes) +│ +├── memory/ # Project memory (architectural decisions) +│ ├── constitution.ttl # Source of truth (RDF) +│ └── constitution.md # Generated from .ttl +│ +├── specs/NNN-feature/ # Feature specifications +│ ├── feature.ttl # User stories, requirements, success criteria (SOURCE) +│ ├── entities.ttl # Domain entities and relationships (SOURCE) +│ ├── plan.ttl # Architecture decisions (SOURCE) +│ ├── tasks.ttl # Task breakdown (SOURCE) +│ ├── spec.md # Generated from feature.ttl (DO NOT EDIT) +│ ├── plan.md # Generated from plan.ttl (DO NOT EDIT) +│ ├── tasks.md # Generated from tasks.ttl (DO NOT EDIT) +│ └── evidence/ # Test evidence, artifacts +│ ├── tests/ +│ ├── benchmarks/ +│ └── traces/ +│ +└── templates/ # Templates for generation + ├── rdf-helpers/ # TTL templates for creating RDF instances + │ ├── user-story.ttl.template + │ ├── entity.ttl.template + │ ├── functional-requirement.ttl.template + │ └── success-criterion.ttl.template + ├── spec.tera # Markdown generation template (SPARQL → Markdown) + ├── plan-template.md # Plan template (legacy, being replaced by plan.tera) + └── tasks-template.md # Tasks template (legacy, being replaced by tasks.tera) +``` + +## Workflow + +### 1. Create Feature Specification (TTL Source) + +```bash +# Start new feature branch +git checkout -b 013-feature-name + +# Create feature directory +mkdir -p .specify/specs/013-feature-name + +# Copy user story template +cp .specify/templates/rdf-helpers/user-story.ttl.template \ + .specify/specs/013-feature-name/feature.ttl + +# Edit feature.ttl with RDF data +vim .specify/specs/013-feature-name/feature.ttl +``` + +**Example feature.ttl**: +```turtle +@prefix sk: . +@prefix : . + +:feature a sk:Feature ; + sk:featureName "Feature Name" ; + sk:featureBranch "013-feature-name" ; + sk:status "planning" ; + sk:hasUserStory :us-001 . + +:us-001 a sk:UserStory ; + sk:storyIndex 1 ; + sk:title "User can do X" ; + sk:priority "P1" ; + sk:description "As a user, I want to do X so that Y" ; + sk:priorityRationale "Critical for MVP launch" ; + sk:independentTest "User completes X workflow end-to-end" ; + sk:hasAcceptanceScenario :us-001-as-001 . + +:us-001-as-001 a sk:AcceptanceScenario ; + sk:scenarioIndex 1 ; + sk:given "User is logged in" ; + sk:when "User clicks X button" ; + sk:then "System displays Y" . +``` + +### 2. Validate RDF (SHACL) + +```bash +# Validate against SHACL shapes +ggen validate .specify/specs/013-feature-name/feature.ttl + +# Expected output: +# ✓ Priority values are valid ("P1", "P2", "P3") +# ✓ All required fields present +# ✓ Minimum 1 acceptance scenario per user story +# ✓ Valid RDF syntax +``` + +### 3. Generate Markdown Artifacts + +```bash +# Regenerate spec.md from feature.ttl +ggen render .specify/templates/spec.tera \ + .specify/specs/013-feature-name/feature.ttl \ + > .specify/specs/013-feature-name/spec.md + +# Or use cargo make target +cargo make speckit-render +``` + +### 4. Commit Both TTL and Generated MD + +```bash +# Commit TTL source (required) +git add .specify/specs/013-feature-name/feature.ttl + +# Commit generated MD (for GitHub viewing) +git add .specify/specs/013-feature-name/spec.md + +git commit -m "feat(013): Add feature specification" +``` + +## NEVER Edit .md Files Directly + +❌ **WRONG**: +```bash +vim .specify/specs/013-feature-name/spec.md # NEVER DO THIS +``` + +✅ **CORRECT**: +```bash +# 1. Edit TTL source +vim .specify/specs/013-feature-name/feature.ttl + +# 2. Regenerate markdown +ggen render .specify/templates/spec.tera \ + .specify/specs/013-feature-name/feature.ttl \ + > .specify/specs/013-feature-name/spec.md +``` + +## RDF Templates Reference + +### User Story Template +- Location: `.specify/templates/rdf-helpers/user-story.ttl.template` +- Required fields: `storyIndex`, `title`, `priority`, `description`, `priorityRationale`, `independentTest` +- Priority values: **MUST** be `"P1"`, `"P2"`, or `"P3"` (SHACL validated) +- Minimum: 1 acceptance scenario per story + +### Entity Template +- Location: `.specify/templates/rdf-helpers/entity.ttl.template` +- Required fields: `entityName`, `definition`, `keyAttributes` +- Used for: Domain model, data structures + +### Functional Requirement Template +- Location: `.specify/templates/rdf-helpers/functional-requirement.ttl.template` +- Required fields: `requirementId`, `reqDescription`, `category` +- Categories: `"Functional"`, `"Non-Functional"`, `"Security"`, etc. + +### Success Criterion Template +- Location: `.specify/templates/rdf-helpers/success-criterion.ttl.template` +- Required fields: `criterionId`, `scDescription`, `measurable`, `metric`, `target` +- Used for: Definition of Done, acceptance criteria + +## SPARQL Queries (spec.tera) + +The `spec.tera` template uses SPARQL to query the RDF graph: + +```sparql +PREFIX sk: + +SELECT ?storyIndex ?title ?priority ?description +WHERE { + ?story a sk:UserStory ; + sk:storyIndex ?storyIndex ; + sk:title ?title ; + sk:priority ?priority ; + sk:description ?description . +} +ORDER BY ?storyIndex +``` + +## Integration with cargo make + +```bash +# Verify TTL specs exist for current branch +cargo make speckit-check + +# Validate TTL → Markdown generation chain +cargo make speckit-validate + +# Regenerate all markdown from TTL sources +cargo make speckit-render + +# Full workflow: validate + render +cargo make speckit-full +``` + +## Constitutional Compliance + +From `.specify/memory/constitution.ttl` (Principle II): + +> **Deterministic RDF Projections**: Every feature specification SHALL be defined as a Turtle/RDF ontology. Code and documentation are **projections** of the ontology via deterministic transformations (μ). NO manual markdown specifications permitted. + +## SHACL Validation Rules + +The `spec-kit-schema.ttl` defines SHACL shapes that enforce: + +1. **Priority Constraint**: `sk:priority` must be exactly `"P1"`, `"P2"`, or `"P3"` +2. **Minimum Scenarios**: Each user story must have at least 1 acceptance scenario +3. **Required Fields**: All required properties must be present with valid datatypes +4. **Referential Integrity**: All links (e.g., `sk:hasUserStory`) must reference valid instances + +## Benefits of RDF-First Approach + +1. **Machine-Readable**: SPARQL queries enable automated analysis +2. **Version Control**: Diffs show semantic changes, not formatting +3. **Validation**: SHACL shapes catch errors before implementation +4. **Consistency**: Single source of truth prevents divergence +5. **Automation**: Generate docs, tests, code from single ontology +6. **Traceability**: RDF links specifications to implementation artifacts + +## Migration from Markdown + +If you have existing `.md` specifications: + +```bash +# 1. Use ggen to parse markdown into RDF +ggen parse-spec .specify/specs/NNN-feature/spec.md \ + > .specify/specs/NNN-feature/feature.ttl + +# 2. Validate the generated RDF +ggen validate .specify/specs/NNN-feature/feature.ttl + +# 3. Regenerate markdown to verify +ggen render .specify/templates/spec.tera \ + .specify/specs/NNN-feature/feature.ttl \ + > .specify/specs/NNN-feature/spec-regenerated.md + +# 4. Compare original vs regenerated +diff .specify/specs/NNN-feature/spec.md \ + .specify/specs/NNN-feature/spec-regenerated.md +``` + +## Troubleshooting + +**Problem**: SHACL validation fails with "Priority must be P1, P2, or P3" + +**Solution**: Change `sk:priority "HIGH"` to `sk:priority "P1"` (exact string match required) + +--- + +**Problem**: Generated markdown missing sections + +**Solution**: Ensure all required RDF predicates are present: +```turtle +:us-001 a sk:UserStory ; + sk:storyIndex 1 ; # Required + sk:title "..." ; # Required + sk:priority "P1" ; # Required + sk:description "..." ; # Required + sk:priorityRationale "..." ; # Required + sk:independentTest "..." ; # Required + sk:hasAcceptanceScenario :us-001-as-001 . # Min 1 required +``` + +--- + +**Problem**: `ggen render` command not found + +**Solution**: Build ggen CLI: +```bash +cargo make build +./target/release/ggen render --help +``` + +## Further Reading + +- [Spec-Kit Schema](./ontology/spec-kit-schema.ttl) - Full vocabulary reference +- [Constitution](./memory/constitution.ttl) - Architectural principles +- [ggen CLAUDE.md](../CLAUDE.md) - Development guidelines +- [Turtle Syntax](https://www.w3.org/TR/turtle/) - W3C specification +- [SPARQL Query Language](https://www.w3.org/TR/sparql11-query/) - W3C specification +- [SHACL Shapes](https://www.w3.org/TR/shacl/) - W3C specification diff --git a/docs/RDF_WORKFLOW_GUIDE.md b/docs/RDF_WORKFLOW_GUIDE.md new file mode 100644 index 0000000000..0e88162dd9 --- /dev/null +++ b/docs/RDF_WORKFLOW_GUIDE.md @@ -0,0 +1,876 @@ +# RDF-First Specification Workflow Guide + +**Version**: 1.0.0 +**Last Updated**: 2025-12-19 +**Status**: Production + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [Architecture](#architecture) +3. [Prerequisites](#prerequisites) +4. [Complete Workflow](#complete-workflow) +5. [SHACL Validation](#shacl-validation) +6. [Template System](#template-system) +7. [Troubleshooting](#troubleshooting) +8. [Examples](#examples) + +--- + +## Overview + +### The Constitutional Equation + +``` +spec.md = μ(feature.ttl) +``` + +All specifications in ggen are **deterministic transformations** from RDF/Turtle ontologies to markdown artifacts. + +### Key Principles + +1. **TTL files are the source of truth** - Edit these, never the markdown +2. **Markdown files are generated artifacts** - Created via `ggen render`, never manually edited +3. **SHACL shapes enforce constraints** - Validation happens before generation +4. **Idempotent transformations** - Running twice produces zero changes +5. **Cryptographic provenance** - Receipts prove spec.md = μ(ontology) + +--- + +## Architecture + +### Directory Structure + +``` +specs/NNN-feature-name/ +├── ontology/ # SOURCE OF TRUTH (edit these) +│ ├── feature-content.ttl # Feature specification (user stories, requirements) +│ ├── plan.ttl # Implementation plan (tech stack, phases, decisions) +│ ├── tasks.ttl # Task breakdown (actionable work items) +│ └── spec-kit-schema.ttl # Symlink to SHACL shapes (validation rules) +├── generated/ # GENERATED ARTIFACTS (never edit) +│ ├── spec.md # Generated from feature-content.ttl +│ ├── plan.md # Generated from plan.ttl +│ └── tasks.md # Generated from tasks.ttl +├── templates/ # TERA TEMPLATES (symlinks to .specify/templates/) +│ ├── spec.tera # Template for spec.md generation +│ ├── plan.tera # Template for plan.md generation +│ └── tasks.tera # Template for tasks.md generation +├── checklists/ # QUALITY VALIDATION +│ └── requirements.md # Specification quality checklist +├── ggen.toml # GGEN V6 CONFIGURATION +└── .gitignore # Git ignore rules +``` + +### The Five-Stage Pipeline (ggen v6) + +``` +μ₁ (Normalization) → Canonicalize RDF + SHACL validation + ↓ +μ₂ (Extraction) → SPARQL queries extract data from ontology + ↓ +μ₃ (Emission) → Tera templates render markdown from SPARQL results + ↓ +μ₄ (Canonicalization)→ Format markdown (line endings, whitespace) + ↓ +μ₅ (Receipt) → Generate cryptographic hash proving spec.md = μ(ontology) +``` + +--- + +## Prerequisites + +### Required Tools + +- **ggen v6**: `cargo install ggen` (or from workspace) +- **Git**: For branch management +- **Text editor**: With Turtle/RDF syntax support (VS Code + RDF extension recommended) + +### Environment Setup + +```bash +# Ensure ggen is available +which ggen # Should show path to ggen binary + +# Check ggen version +ggen --version # Should be v6.x.x or higher + +# Ensure you're in the ggen repository root +cd /path/to/ggen +``` + +--- + +## Complete Workflow + +### Phase 1: Create Feature Specification + +#### Step 1.1: Start New Feature Branch + +```bash +# Run speckit.specify command (via Claude Code) +/speckit.specify "Add TTL validation command to ggen CLI that validates RDF files against SHACL shapes" +``` + +**What this does:** +- Calculates next feature number (e.g., 005) +- Creates branch `005-ttl-shacl-validation` +- Sets up directory structure: + - `specs/005-ttl-shacl-validation/ontology/feature-content.ttl` + - `specs/005-ttl-shacl-validation/ggen.toml` + - `specs/005-ttl-shacl-validation/templates/` (symlinks) + - `specs/005-ttl-shacl-validation/generated/` (empty, for artifacts) + +#### Step 1.2: Edit Feature TTL (Source of Truth) + +```bash +# Open the TTL source file +vim specs/005-ttl-shacl-validation/ontology/feature-content.ttl +``` + +**File structure:** + +```turtle +@prefix sk: . +@prefix : . + +:ttl-shacl-validation a sk:Feature ; + sk:featureBranch "005-ttl-shacl-validation" ; + sk:featureName "Add TTL validation command" ; + sk:created "2025-12-19"^^xsd:date ; + sk:status "Draft" ; + sk:userInput "Add TTL validation command..." ; + sk:hasUserStory :us-001, :us-002 ; + sk:hasFunctionalRequirement :fr-001, :fr-002 ; + sk:hasSuccessCriterion :sc-001 ; + sk:hasEntity :entity-001 ; + sk:hasEdgeCase :edge-001 ; + sk:hasAssumption :assume-001 . + +# User Story 1 (P1 - MVP) +:us-001 a sk:UserStory ; + sk:storyIndex 1 ; + sk:title "Developer validates single TTL file" ; + sk:priority "P1" ; # MUST be exactly "P1", "P2", or "P3" (SHACL validated) + sk:description "As a ggen developer, I want to validate..." ; + sk:priorityRationale "Core MVP functionality..." ; + sk:independentTest "Run 'ggen validate .ttl'..." ; + sk:hasAcceptanceScenario :us-001-as-001 . + +# Acceptance Scenario 1.1 +:us-001-as-001 a sk:AcceptanceScenario ; + sk:scenarioIndex 1 ; + sk:given "A TTL file with known SHACL violations" ; + sk:when "User runs ggen validate command" ; + sk:then "Violations are detected and reported with clear error messages" . + +# ... more user stories, requirements, criteria, entities, edge cases, assumptions +``` + +**Critical rules:** +- Priority MUST be exactly "P1", "P2", or "P3" (SHACL validated, will fail if "HIGH", "LOW", etc.) +- Dates must be in YYYY-MM-DD format with `^^xsd:date` +- All predicates must use `sk:` namespace from spec-kit-schema.ttl +- Every user story must have at least 1 acceptance scenario + +#### Step 1.3: Validate TTL Against SHACL Shapes + +```bash +# Run SHACL validation (automatic in ggen render, or manual) +cd specs/005-ttl-shacl-validation +ggen validate ontology/feature-content.ttl --shapes ontology/spec-kit-schema.ttl +``` + +**Expected output (if valid):** +``` +✓ ontology/feature-content.ttl conforms to SHACL shapes +✓ 0 violations found +``` + +**Example error (if invalid priority):** +``` +✗ Constraint violation in ontology/feature-content.ttl: + - :us-001 has invalid sk:priority value "HIGH" + - Expected: "P1", "P2", or "P3" + - Shape: PriorityShape from spec-kit-schema.ttl +``` + +**Fix:** Change `sk:priority "HIGH"` to `sk:priority "P1"` in the TTL file. + +#### Step 1.4: Generate Spec Markdown + +```bash +# Generate spec.md from feature-content.ttl using ggen render +cd specs/005-ttl-shacl-validation +ggen render templates/spec.tera ontology/feature-content.ttl > generated/spec.md +``` + +**What this does:** +1. **μ₁ (Normalization)**: Validates ontology/feature-content.ttl against SHACL shapes +2. **μ₂ (Extraction)**: Executes SPARQL query from ggen.toml to extract data +3. **μ₃ (Emission)**: Applies spec.tera template to SPARQL results +4. **μ₄ (Canonicalization)**: Formats markdown (line endings, whitespace) +5. **μ₅ (Receipt)**: Generates cryptographic hash (stored in .ggen/receipts/) + +**Generated file header:** +```markdown + + + +# Feature Specification: Add TTL validation command to ggen CLI + +**Branch**: `005-ttl-shacl-validation` +**Created**: 2025-12-19 +**Status**: Draft + +... +``` + +**Footer:** +```markdown +--- + +**Generated with**: [ggen v6](https://github.com/seanchatmangpt/ggen) ontology-driven specification system +**Constitutional Equation**: `spec.md = μ(feature-content.ttl)` +``` + +#### Step 1.5: Verify Quality Checklist + +```bash +# Review checklist (created during /speckit.specify) +cat specs/005-ttl-shacl-validation/checklists/requirements.md +``` + +**Checklist items:** +- [ ] No implementation details (languages, frameworks, APIs) +- [ ] Focused on user value and business needs +- [ ] All mandatory sections completed +- [ ] No [NEEDS CLARIFICATION] markers remain +- [ ] Requirements are testable and unambiguous +- [ ] Success criteria are measurable and technology-agnostic +- [ ] All user story priorities use SHACL-compliant values ("P1", "P2", "P3") + +**All items must be checked before proceeding to planning.** + +--- + +### Phase 2: Create Implementation Plan + +#### Step 2.1: Run Speckit Plan Command + +```bash +# Run speckit.plan command (via Claude Code) +/speckit.plan +``` + +**What this does:** +- Detects RDF-first feature (checks for `ontology/` + `ggen.toml`) +- Creates `ontology/plan.ttl` from template +- Symlinks `templates/plan.tera` (if not exists) +- Does NOT generate plan.md yet (manual step) + +#### Step 2.2: Edit Plan TTL (Source of Truth) + +```bash +# Open the plan TTL file +vim specs/005-ttl-shacl-validation/ontology/plan.ttl +``` + +**File structure:** + +```turtle +@prefix sk: . +@prefix : . + +:plan a sk:Plan ; + sk:featureBranch "005-ttl-shacl-validation" ; + sk:featureName "Add TTL validation command" ; + sk:planCreated "2025-12-19"^^xsd:date ; + sk:planStatus "Draft" ; + sk:architecturePattern "CLI command with Oxigraph SHACL validator" ; + sk:hasTechnology :tech-001, :tech-002 ; + sk:hasProjectStructure :struct-001 ; + sk:hasPhase :phase-setup, :phase-foundation, :phase-us1 ; + sk:hasDecision :decision-001 ; + sk:hasRisk :risk-001 ; + sk:hasDependency :dep-001 . + +# Technology: Rust +:tech-001 a sk:Technology ; + sk:techName "Rust 1.75+" ; + sk:techVersion "1.75+" ; + sk:techPurpose "Existing ggen CLI infrastructure, type safety" . + +# Technology: Oxigraph +:tech-002 a sk:Technology ; + sk:techName "Oxigraph" ; + sk:techVersion "0.3" ; + sk:techPurpose "RDF store with SHACL validation support" . + +# Project Structure +:struct-001 a sk:ProjectStructure ; + sk:structurePath "crates/ggen-validation/src/" ; + sk:structurePurpose "New crate for TTL/SHACL validation logic" . + +# Phase: Setup +:phase-setup a sk:Phase ; + sk:phaseId "phase-setup" ; + sk:phaseName "Setup" ; + sk:phaseOrder 1 ; + sk:phaseDescription "Create crate, configure dependencies" ; + sk:phaseDeliverables "Cargo.toml with oxigraph dependency" . + +# Decision: SHACL Engine Choice +:decision-001 a sk:PlanDecision ; + sk:decisionId "DEC-001" ; + sk:decisionTitle "SHACL Validation Engine" ; + sk:decisionChoice "Oxigraph embedded SHACL validator" ; + sk:decisionRationale "Zero external deps, Rust native, sufficient for spec validation" ; + sk:alternativesConsidered "Apache Jena (JVM overhead), pySHACL (Python interop)" ; + sk:tradeoffs "Gain: simplicity. Lose: advanced SHACL-AF features" ; + sk:revisitCriteria "If SHACL-AF (advanced features) becomes required" . + +# Risk: SHACL Performance +:risk-001 a sk:Risk ; + sk:riskId "RISK-001" ; + sk:riskDescription "SHACL validation slow on large ontologies" ; + sk:riskImpact "medium" ; + sk:riskLikelihood "low" ; + sk:mitigationStrategy "Cache validation results, set ontology size limits" . + +# Dependency: Spec-Kit Schema +:dep-001 a sk:Dependency ; + sk:dependencyName "Spec-Kit Schema Ontology" ; + sk:dependencyType "external" ; + sk:dependencyStatus "available" ; + sk:dependencyNotes "Symlinked from .specify/ontology/spec-kit-schema.ttl" . +``` + +#### Step 2.3: Generate Plan Markdown + +```bash +# Generate plan.md from plan.ttl +cd specs/005-ttl-shacl-validation +ggen render templates/plan.tera ontology/plan.ttl > generated/plan.md +``` + +**Generated output:** +```markdown + + +# Implementation Plan: Add TTL validation command + +**Branch**: `005-ttl-shacl-validation` +**Created**: 2025-12-19 +**Status**: Draft + +--- + +## Technical Context + +**Architecture Pattern**: CLI command with Oxigraph SHACL validator + +**Technology Stack**: +- Rust 1.75+ - Existing ggen CLI infrastructure, type safety +- Oxigraph (0.3) - RDF store with SHACL validation support + +**Project Structure**: +- `crates/ggen-validation/src/` - New crate for TTL/SHACL validation logic + +--- + +## Implementation Phases + +### Phase 1: Setup + +Create crate, configure dependencies + +**Deliverables**: Cargo.toml with oxigraph dependency + +... +``` + +--- + +### Phase 3: Create Task Breakdown + +#### Step 3.1: Run Speckit Tasks Command + +```bash +# Run speckit.tasks command (via Claude Code) +/speckit.tasks +``` + +**What this does:** +- SPARQL queries feature.ttl and plan.ttl to extract context +- Generates tasks.ttl with dependency-ordered task breakdown +- Links tasks to phases and user stories + +#### Step 3.2: Edit Tasks TTL (Source of Truth) + +```bash +# Open the tasks TTL file +vim specs/005-ttl-shacl-validation/ontology/tasks.ttl +``` + +**File structure:** + +```turtle +@prefix sk: . +@prefix : . + +:tasks a sk:Tasks ; + sk:featureBranch "005-ttl-shacl-validation" ; + sk:featureName "Add TTL validation command" ; + sk:tasksCreated "2025-12-19"^^xsd:date ; + sk:totalTasks 12 ; + sk:estimatedEffort "3-5 days" ; + sk:hasPhase :phase-setup, :phase-foundation, :phase-us1 . + +# Phase: Setup +:phase-setup a sk:Phase ; + sk:phaseId "phase-setup" ; + sk:phaseName "Setup" ; + sk:phaseOrder 1 ; + sk:phaseDescription "Create crate and configure dependencies" ; + sk:phaseDeliverables "Project structure, Cargo.toml" ; + sk:hasTask :task-001, :task-002 . + +:task-001 a sk:Task ; + sk:taskId "T001" ; + sk:taskOrder 1 ; + sk:taskDescription "Create crates/ggen-validation directory structure" ; + sk:filePath "crates/ggen-validation/" ; + sk:parallelizable "false"^^xsd:boolean ; # Must run first + sk:belongsToPhase :phase-setup . + +:task-002 a sk:Task ; + sk:taskId "T002" ; + sk:taskOrder 2 ; + sk:taskDescription "Configure Cargo.toml with oxigraph dependency" ; + sk:filePath "crates/ggen-validation/Cargo.toml" ; + sk:parallelizable "false"^^xsd:boolean ; + sk:belongsToPhase :phase-setup ; + sk:dependencies "T001" . + +# ... more tasks, phases +``` + +#### Step 3.3: Generate Tasks Markdown + +```bash +# Generate tasks.md from tasks.ttl +cd specs/005-ttl-shacl-validation +ggen render templates/tasks.tera ontology/tasks.ttl > generated/tasks.md +``` + +**Generated output:** +```markdown + + +# Implementation Tasks: Add TTL validation command + +**Branch**: `005-ttl-shacl-validation` +**Created**: 2025-12-19 +**Total Tasks**: 12 +**Estimated Effort**: 3-5 days + +--- + +## Phase 1: Setup + +- [ ] T001 Create crates/ggen-validation directory structure in crates/ggen-validation/ +- [ ] T002 Configure Cargo.toml with oxigraph dependency in crates/ggen-validation/Cargo.toml (depends on: T001) + +... +``` + +--- + +## SHACL Validation + +### What is SHACL? + +**SHACL (Shapes Constraint Language)** is a W3C standard for validating RDF graphs against a set of constraints (shapes). + +**Example shape:** +```turtle +sk:PriorityShape a sh:NodeShape ; + sh:targetObjectsOf sk:priority ; + sh:in ( "P1" "P2" "P3" ) ; + sh:message "Priority must be exactly P1, P2, or P3" . +``` + +### Validation Workflow + +1. **Automatic validation during ggen render:** + ```bash + ggen render templates/spec.tera ontology/feature-content.ttl > generated/spec.md + # ↑ Automatically validates against ontology/spec-kit-schema.ttl before rendering + ``` + +2. **Manual validation:** + ```bash + ggen validate ontology/feature-content.ttl --shapes ontology/spec-kit-schema.ttl + ``` + +### Common SHACL Violations + +#### Violation: Invalid Priority Value + +**Error:** +``` +✗ Constraint violation in ontology/feature-content.ttl: + - :us-001 has invalid sk:priority value "HIGH" + - Expected: "P1", "P2", or "P3" + - Shape: PriorityShape +``` + +**Fix:** +```turtle +# WRONG +:us-001 sk:priority "HIGH" . + +# CORRECT +:us-001 sk:priority "P1" . +``` + +#### Violation: Missing Acceptance Scenario + +**Error:** +``` +✗ Constraint violation in ontology/feature-content.ttl: + - :us-002 is missing required sk:hasAcceptanceScenario + - Shape: UserStoryShape (min count: 1) +``` + +**Fix:** +```turtle +# Add at least one acceptance scenario +:us-002 sk:hasAcceptanceScenario :us-002-as-001 . + +:us-002-as-001 a sk:AcceptanceScenario ; + sk:scenarioIndex 1 ; + sk:given "Initial state" ; + sk:when "Action occurs" ; + sk:then "Expected outcome" . +``` + +#### Violation: Invalid Date Format + +**Error:** +``` +✗ Constraint violation in ontology/feature-content.ttl: + - :feature sk:created value "12/19/2025" has wrong datatype + - Expected: xsd:date in YYYY-MM-DD format +``` + +**Fix:** +```turtle +# WRONG +:feature sk:created "12/19/2025" . + +# CORRECT +:feature sk:created "2025-12-19"^^xsd:date . +``` + +--- + +## Template System + +### How Tera Templates Work + +**Tera** is a template engine similar to Jinja2. It takes SPARQL query results and renders them into markdown. + +**Flow:** +``` +ontology/feature-content.ttl + ↓ (SPARQL query from ggen.toml) +SPARQL results (table of bindings) + ↓ (Tera template from templates/spec.tera) +generated/spec.md +``` + +### SPARQL Query Example (from ggen.toml) + +```sparql +SELECT ?featureBranch ?featureName ?created + ?storyIndex ?title ?priority ?description +WHERE { + ?feature a sk:Feature ; + sk:featureBranch ?featureBranch ; + sk:featureName ?featureName ; + sk:created ?created . + + OPTIONAL { + ?feature sk:hasUserStory ?story . + ?story sk:storyIndex ?storyIndex ; + sk:title ?title ; + sk:priority ?priority ; + sk:description ?description . + } +} +ORDER BY ?storyIndex +``` + +**SPARQL results (table):** +| featureBranch | featureName | created | storyIndex | title | priority | description | +|---------------|-------------|---------|------------|-------|----------|-------------| +| 005-ttl-shacl-validation | Add TTL validation... | 2025-12-19 | 1 | Developer validates... | P1 | As a ggen developer... | +| 005-ttl-shacl-validation | Add TTL validation... | 2025-12-19 | 2 | CI validates... | P2 | As a CI pipeline... | + +### Tera Template Example (spec.tera snippet) + +```jinja2 +{%- set feature_metadata = sparql_results | first -%} + +# Feature Specification: {{ feature_metadata.featureName }} + +**Branch**: `{{ feature_metadata.featureBranch }}` +**Created**: {{ feature_metadata.created }} + +--- + +## User Stories + +{%- set current_story = "" %} +{%- for row in sparql_results %} +{%- if row.storyIndex and row.storyIndex != current_story -%} +{%- set_global current_story = row.storyIndex -%} + +### User Story {{ row.storyIndex }} - {{ row.title }} (Priority: {{ row.priority }}) + +{{ row.description }} + +{%- endif %} +{%- endfor %} +``` + +**Rendered markdown:** +```markdown +# Feature Specification: Add TTL validation command to ggen CLI + +**Branch**: `005-ttl-shacl-validation` +**Created**: 2025-12-19 + +--- + +## User Stories + +### User Story 1 - Developer validates single TTL file (Priority: P1) + +As a ggen developer, I want to validate... + +### User Story 2 - CI validates all TTL files (Priority: P2) + +As a CI pipeline, I want to... +``` + +--- + +## Troubleshooting + +### Problem: "ERROR: plan.ttl not found" + +**Symptom:** +```bash +$ .specify/scripts/bash/check-prerequisites.sh --json +ERROR: plan.ttl not found in /Users/sac/ggen/specs/005-ttl-shacl-validation/ontology +``` + +**Cause:** RDF-first feature detected (has `ontology/` and `ggen.toml`), but plan.ttl hasn't been created yet. + +**Fix:** +```bash +# Run /speckit.plan to create plan.ttl +# OR manually create from template: +cp .specify/templates/rdf-helpers/plan.ttl.template specs/005-ttl-shacl-validation/ontology/plan.ttl +``` + +--- + +### Problem: "SHACL violation: invalid priority" + +**Symptom:** +```bash +$ ggen render templates/spec.tera ontology/feature-content.ttl > generated/spec.md +✗ SHACL validation failed: :us-001 priority "HIGH" not in ("P1", "P2", "P3") +``` + +**Cause:** Priority value doesn't match SHACL constraint (must be exactly "P1", "P2", or "P3"). + +**Fix:** +```turtle +# Edit ontology/feature-content.ttl +# Change: +:us-001 sk:priority "HIGH" . + +# To: +:us-001 sk:priority "P1" . +``` + +--- + +### Problem: "Multiple spec directories found with prefix 005" + +**Symptom:** +```bash +$ .specify/scripts/bash/check-prerequisites.sh --json +ERROR: Multiple spec directories found with prefix '005': 005-feature-a 005-feature-b +``` + +**Cause:** Two feature directories exist with the same numeric prefix. + +**Fix (Option 1 - Use SPECIFY_FEATURE env var):** +```bash +SPECIFY_FEATURE=005-feature-a .specify/scripts/bash/check-prerequisites.sh --json +``` + +**Fix (Option 2 - Rename one feature to different number):** +```bash +git branch -m 005-feature-b 006-feature-b +mv specs/005-feature-b specs/006-feature-b +``` + +--- + +### Problem: "Template variables are empty" + +**Symptom:** +Generated markdown has blank fields: +```markdown +**Branch**: `` +**Created**: +``` + +**Cause:** SPARQL query variable names don't match template expectations. + +**Diagnosis:** +```bash +# Check what variables the SPARQL query returns +ggen query ontology/feature-content.ttl "SELECT * WHERE { ?s ?p ?o } LIMIT 10" + +# Check what variables the template expects +grep "{{" templates/spec.tera | grep -o "feature_metadata\.[a-zA-Z]*" | sort -u +``` + +**Fix:** Ensure SPARQL query SELECT clause includes all variables used in template (see [Verify spec.tera](#verify-spectera) section). + +--- + +## Examples + +### Example 1: Complete Feature Workflow + +**Step 1: Create feature** +```bash +/speckit.specify "Add user authentication to ggen CLI" +``` + +**Step 2: Edit feature.ttl** +```turtle +@prefix sk: . +@prefix : . + +:user-auth a sk:Feature ; + sk:featureBranch "006-user-auth" ; + sk:featureName "Add user authentication to ggen CLI" ; + sk:created "2025-12-19"^^xsd:date ; + sk:status "Draft" ; + sk:hasUserStory :us-001 . + +:us-001 a sk:UserStory ; + sk:storyIndex 1 ; + sk:title "User logs in via CLI" ; + sk:priority "P1" ; + sk:description "As a ggen user, I want to log in via the CLI..." ; + sk:priorityRationale "Core security requirement" ; + sk:independentTest "Run 'ggen login' and verify authentication" ; + sk:hasAcceptanceScenario :us-001-as-001 . + +:us-001-as-001 a sk:AcceptanceScenario ; + sk:scenarioIndex 1 ; + sk:given "User has valid credentials" ; + sk:when "User runs 'ggen login' command" ; + sk:then "User is authenticated and session token is stored" . +``` + +**Step 3: Validate TTL** +```bash +cd specs/006-user-auth +ggen validate ontology/feature-content.ttl --shapes ontology/spec-kit-schema.ttl +# ✓ 0 violations found +``` + +**Step 4: Generate spec.md** +```bash +ggen render templates/spec.tera ontology/feature-content.ttl > generated/spec.md +``` + +**Step 5: Verify generated markdown** +```bash +cat generated/spec.md +# Should show user story, acceptance scenario, etc. +``` + +--- + +### Example 2: Fixing SHACL Violations + +**Original TTL (with errors):** +```turtle +:us-001 a sk:UserStory ; + sk:storyIndex 1 ; + sk:title "User logs in" ; + sk:priority "HIGH" ; # ❌ WRONG - should be P1, P2, or P3 + sk:description "User logs in..." . + # ❌ MISSING: hasAcceptanceScenario (required) +``` + +**Validation error:** +```bash +$ ggen validate ontology/feature-content.ttl --shapes ontology/spec-kit-schema.ttl +✗ 2 violations found: + 1. :us-001 priority "HIGH" not in ("P1", "P2", "P3") + 2. :us-001 missing required sk:hasAcceptanceScenario +``` + +**Fixed TTL:** +```turtle +:us-001 a sk:UserStory ; + sk:storyIndex 1 ; + sk:title "User logs in" ; + sk:priority "P1" ; # ✅ FIXED - valid priority + sk:description "User logs in..." ; + sk:hasAcceptanceScenario :us-001-as-001 . # ✅ ADDED - required scenario + +:us-001-as-001 a sk:AcceptanceScenario ; + sk:scenarioIndex 1 ; + sk:given "User has credentials" ; + sk:when "User runs login command" ; + sk:then "User is authenticated" . +``` + +**Re-validation:** +```bash +$ ggen validate ontology/feature-content.ttl --shapes ontology/spec-kit-schema.ttl +✓ 0 violations found +``` + +--- + +## Next Steps + +After completing the RDF-first workflow for specifications: + +1. **Run /speckit.plan** to create implementation plan (plan.ttl → plan.md) +2. **Run /speckit.tasks** to generate task breakdown (tasks.ttl → tasks.md) +3. **Run /speckit.implement** to execute tasks from RDF sources +4. **Run /speckit.finish** to validate Definition of Done and create PR + +--- + +**Generated with**: [ggen v6](https://github.com/seanchatmangpt/ggen) RDF-first specification system +**Constitutional Equation**: `documentation.md = μ(workflow-knowledge)` diff --git a/scripts/bash/check-prerequisites.sh b/scripts/bash/check-prerequisites.sh index 98e387c271..098537ea3c 100644 --- a/scripts/bash/check-prerequisites.sh +++ b/scripts/bash/check-prerequisites.sh @@ -15,9 +15,9 @@ # --help, -h Show help message # # OUTPUTS: -# JSON mode: {"FEATURE_DIR":"...", "AVAILABLE_DOCS":["..."]} -# Text mode: FEATURE_DIR:... \n AVAILABLE_DOCS: \n ✓/✗ file.md -# Paths only: REPO_ROOT: ... \n BRANCH: ... \n FEATURE_DIR: ... etc. +# JSON mode: {"FEATURE_DIR":"...", "FEATURE_SPEC_TTL":"...", "IMPL_PLAN_TTL":"...", "AVAILABLE_DOCS":["..."]} +# Text mode: FEATURE_DIR:... \n TTL_SOURCES: ... \n AVAILABLE_DOCS: \n ✓/✗ file.md +# Paths only: REPO_ROOT: ... \n BRANCH: ... \n FEATURE_DIR: ... \n TTL paths ... etc. set -e @@ -85,16 +85,28 @@ check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1 # If paths-only mode, output paths and exit (support JSON + paths-only combined) if $PATHS_ONLY; then if $JSON_MODE; then - # Minimal JSON paths payload (no validation performed) - printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \ - "$REPO_ROOT" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS" + # Minimal JSON paths payload (no validation performed) - RDF-first architecture + printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC_TTL":"%s","IMPL_PLAN_TTL":"%s","TASKS_TTL":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s","ONTOLOGY_DIR":"%s","GENERATED_DIR":"%s","GGEN_CONFIG":"%s"}\n' \ + "$REPO_ROOT" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC_TTL" "$IMPL_PLAN_TTL" "$TASKS_TTL" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS" "$ONTOLOGY_DIR" "$GENERATED_DIR" "$GGEN_CONFIG" else echo "REPO_ROOT: $REPO_ROOT" echo "BRANCH: $CURRENT_BRANCH" echo "FEATURE_DIR: $FEATURE_DIR" + echo "" + echo "# RDF-First Architecture: TTL sources (source of truth)" + echo "FEATURE_SPEC_TTL: $FEATURE_SPEC_TTL" + echo "IMPL_PLAN_TTL: $IMPL_PLAN_TTL" + echo "TASKS_TTL: $TASKS_TTL" + echo "" + echo "# Generated artifacts (NEVER edit manually)" echo "FEATURE_SPEC: $FEATURE_SPEC" echo "IMPL_PLAN: $IMPL_PLAN" echo "TASKS: $TASKS" + echo "" + echo "# RDF infrastructure" + echo "ONTOLOGY_DIR: $ONTOLOGY_DIR" + echo "GENERATED_DIR: $GENERATED_DIR" + echo "GGEN_CONFIG: $GGEN_CONFIG" fi exit 0 fi @@ -106,23 +118,67 @@ if [[ ! -d "$FEATURE_DIR" ]]; then exit 1 fi -if [[ ! -f "$IMPL_PLAN" ]]; then - echo "ERROR: plan.md not found in $FEATURE_DIR" >&2 - echo "Run /speckit.plan first to create the implementation plan." >&2 - exit 1 +# RDF-First Architecture: Check for TTL sources first, fall back to legacy MD +# Detect feature format (RDF-first vs. legacy) +IS_RDF_FEATURE=false +if [[ -d "$ONTOLOGY_DIR" ]] && [[ -f "$GGEN_CONFIG" ]]; then + IS_RDF_FEATURE=true fi -# Check for tasks.md if required -if $REQUIRE_TASKS && [[ ! -f "$TASKS" ]]; then - echo "ERROR: tasks.md not found in $FEATURE_DIR" >&2 - echo "Run /speckit.tasks first to create the task list." >&2 - exit 1 +if $IS_RDF_FEATURE; then + # RDF-first feature: Validate TTL sources + if [[ ! -f "$IMPL_PLAN_TTL" ]] && [[ ! -f "$IMPL_PLAN_LEGACY" ]]; then + echo "ERROR: plan.ttl not found in $ONTOLOGY_DIR (and no legacy plan.md)" >&2 + echo "Run /speckit.plan first to create the implementation plan." >&2 + exit 1 + fi + + # Check for tasks.ttl if required + if $REQUIRE_TASKS && [[ ! -f "$TASKS_TTL" ]] && [[ ! -f "$TASKS_LEGACY" ]]; then + echo "ERROR: tasks.ttl not found in $ONTOLOGY_DIR (and no legacy tasks.md)" >&2 + echo "Run /speckit.tasks first to create the task list." >&2 + exit 1 + fi +else + # Legacy feature: Check for MD files + if [[ ! -f "$IMPL_PLAN_LEGACY" ]]; then + echo "ERROR: plan.md not found in $FEATURE_DIR" >&2 + echo "Run /speckit.plan first to create the implementation plan." >&2 + exit 1 + fi + + # Check for tasks.md if required + if $REQUIRE_TASKS && [[ ! -f "$TASKS_LEGACY" ]]; then + echo "ERROR: tasks.md not found in $FEATURE_DIR" >&2 + echo "Run /speckit.tasks first to create the task list." >&2 + exit 1 + fi fi -# Build list of available documents +# Build list of available documents (both TTL sources and MD artifacts) docs=() +ttl_sources=() + +if $IS_RDF_FEATURE; then + # RDF-first feature: List TTL sources and generated artifacts + [[ -f "$FEATURE_SPEC_TTL" ]] && ttl_sources+=("ontology/feature-content.ttl") + [[ -f "$IMPL_PLAN_TTL" ]] && ttl_sources+=("ontology/plan.ttl") + [[ -f "$TASKS_TTL" ]] && ttl_sources+=("ontology/tasks.ttl") + + # Generated artifacts (for reference only) + [[ -f "$FEATURE_SPEC" ]] && docs+=("generated/spec.md") + [[ -f "$IMPL_PLAN" ]] && docs+=("generated/plan.md") + [[ -f "$TASKS" ]] && docs+=("generated/tasks.md") +else + # Legacy feature: List MD files as primary + [[ -f "$FEATURE_SPEC_LEGACY" ]] && docs+=("spec.md") + [[ -f "$IMPL_PLAN_LEGACY" ]] && docs+=("plan.md") + if $INCLUDE_TASKS && [[ -f "$TASKS_LEGACY" ]]; then + docs+=("tasks.md") + fi +fi -# Always check these optional docs +# Always check these optional docs (same for RDF and legacy) [[ -f "$RESEARCH" ]] && docs+=("research.md") [[ -f "$DATA_MODEL" ]] && docs+=("data-model.md") @@ -133,13 +189,16 @@ fi [[ -f "$QUICKSTART" ]] && docs+=("quickstart.md") -# Include tasks.md if requested and it exists -if $INCLUDE_TASKS && [[ -f "$TASKS" ]]; then - docs+=("tasks.md") -fi - # Output results if $JSON_MODE; then + # Build JSON array of TTL sources + if [[ ${#ttl_sources[@]} -eq 0 ]]; then + json_ttl="[]" + else + json_ttl=$(printf '"%s",' "${ttl_sources[@]}") + json_ttl="[${json_ttl%,}]" + fi + # Build JSON array of documents if [[ ${#docs[@]} -eq 0 ]]; then json_docs="[]" @@ -147,20 +206,48 @@ if $JSON_MODE; then json_docs=$(printf '"%s",' "${docs[@]}") json_docs="[${json_docs%,}]" fi - - printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$FEATURE_DIR" "$json_docs" + + # Output with RDF-first architecture fields + printf '{"FEATURE_DIR":"%s","IS_RDF_FEATURE":%s,"TTL_SOURCES":%s,"AVAILABLE_DOCS":%s,"FEATURE_SPEC_TTL":"%s","IMPL_PLAN_TTL":"%s","TASKS_TTL":"%s","ONTOLOGY_DIR":"%s","GENERATED_DIR":"%s","GGEN_CONFIG":"%s"}\n' \ + "$FEATURE_DIR" "$IS_RDF_FEATURE" "$json_ttl" "$json_docs" "$FEATURE_SPEC_TTL" "$IMPL_PLAN_TTL" "$TASKS_TTL" "$ONTOLOGY_DIR" "$GENERATED_DIR" "$GGEN_CONFIG" else # Text output echo "FEATURE_DIR:$FEATURE_DIR" - echo "AVAILABLE_DOCS:" - - # Show status of each potential document - check_file "$RESEARCH" "research.md" - check_file "$DATA_MODEL" "data-model.md" - check_dir "$CONTRACTS_DIR" "contracts/" - check_file "$QUICKSTART" "quickstart.md" - - if $INCLUDE_TASKS; then - check_file "$TASKS" "tasks.md" + echo "" + + if $IS_RDF_FEATURE; then + echo "# RDF-First Feature (source of truth: TTL files)" + echo "TTL_SOURCES:" + check_file "$FEATURE_SPEC_TTL" " ontology/feature-content.ttl" + check_file "$IMPL_PLAN_TTL" " ontology/plan.ttl" + check_file "$TASKS_TTL" " ontology/tasks.ttl" + echo "" + echo "GENERATED_ARTIFACTS (NEVER edit manually):" + check_file "$FEATURE_SPEC" " generated/spec.md" + check_file "$IMPL_PLAN" " generated/plan.md" + check_file "$TASKS" " generated/tasks.md" + echo "" + echo "RDF_INFRASTRUCTURE:" + check_dir "$ONTOLOGY_DIR" " ontology/" + check_dir "$GENERATED_DIR" " generated/" + check_file "$GGEN_CONFIG" " ggen.toml" + check_file "$SCHEMA_TTL" " ontology/spec-kit-schema.ttl (symlink)" + echo "" + else + echo "# Legacy Feature (source of truth: MD files)" + echo "AVAILABLE_DOCS:" + check_file "$FEATURE_SPEC_LEGACY" " spec.md" + check_file "$IMPL_PLAN_LEGACY" " plan.md" + if $INCLUDE_TASKS; then + check_file "$TASKS_LEGACY" " tasks.md" + fi + echo "" fi + + # Show status of optional documents (same for RDF and legacy) + echo "OPTIONAL_DOCS:" + check_file "$RESEARCH" " research.md" + check_file "$DATA_MODEL" " data-model.md" + check_dir "$CONTRACTS_DIR" " contracts/" + check_file "$QUICKSTART" " quickstart.md" fi diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 2c3165e41d..4365f318b8 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -133,21 +133,38 @@ get_feature_paths() { has_git_repo="true" fi - # Use prefix-based lookup to support multiple branches per spec - local feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch") + # Use exact match if SPECIFY_FEATURE is set, otherwise use prefix-based lookup + local feature_dir + if [[ -n "${SPECIFY_FEATURE:-}" ]]; then + feature_dir="$repo_root/specs/$SPECIFY_FEATURE" + else + feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch") + fi + # Output variable assignments (no comments - they break eval) cat < "$IMPL_PLAN_TTL" + echo "Created plan.ttl from template at $IMPL_PLAN_TTL" + else + echo "Warning: Plan TTL template not found at $PLAN_TTL_TEMPLATE" + touch "$IMPL_PLAN_TTL" + fi + + # Create symlink to plan.tera template (if not exists) + PLAN_TERA_TARGET="$REPO_ROOT/.specify/templates/plan.tera" + PLAN_TERA_LINK="$TEMPLATES_DIR/plan.tera" + if [[ -f "$PLAN_TERA_TARGET" ]] && [[ ! -e "$PLAN_TERA_LINK" ]]; then + ln -s "$PLAN_TERA_TARGET" "$PLAN_TERA_LINK" + echo "Created symlink to plan.tera template" + fi + + # Note: plan.md generation would be done by ggen render (not this script) + echo "Note: Run 'ggen render templates/plan.tera ontology/plan.ttl > generated/plan.md' to generate markdown" else - echo "Warning: Plan template not found at $TEMPLATE" - # Create a basic plan file if template doesn't exist - touch "$IMPL_PLAN" + # Legacy Feature: Copy markdown template + echo "Detected legacy feature, setting up MD-based plan..." + + TEMPLATE="$REPO_ROOT/.specify/templates/plan-template.md" + if [[ -f "$TEMPLATE" ]]; then + cp "$TEMPLATE" "$IMPL_PLAN_LEGACY" + echo "Copied plan template to $IMPL_PLAN_LEGACY" + else + echo "Warning: Plan template not found at $TEMPLATE" + # Create a basic plan file if template doesn't exist + touch "$IMPL_PLAN_LEGACY" + fi fi # Output results if $JSON_MODE; then - printf '{"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","SPECS_DIR":"%s","BRANCH":"%s","HAS_GIT":"%s"}\n' \ - "$FEATURE_SPEC" "$IMPL_PLAN" "$FEATURE_DIR" "$CURRENT_BRANCH" "$HAS_GIT" + if $IS_RDF_FEATURE; then + printf '{"IS_RDF_FEATURE":%s,"FEATURE_SPEC_TTL":"%s","IMPL_PLAN_TTL":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","ONTOLOGY_DIR":"%s","GENERATED_DIR":"%s","SPECS_DIR":"%s","BRANCH":"%s","HAS_GIT":"%s"}\n' \ + "$IS_RDF_FEATURE" "$FEATURE_SPEC_TTL" "$IMPL_PLAN_TTL" "$FEATURE_SPEC" "$IMPL_PLAN" "$ONTOLOGY_DIR" "$GENERATED_DIR" "$FEATURE_DIR" "$CURRENT_BRANCH" "$HAS_GIT" + else + printf '{"IS_RDF_FEATURE":%s,"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","SPECS_DIR":"%s","BRANCH":"%s","HAS_GIT":"%s"}\n' \ + "$IS_RDF_FEATURE" "$FEATURE_SPEC_LEGACY" "$IMPL_PLAN_LEGACY" "$FEATURE_DIR" "$CURRENT_BRANCH" "$HAS_GIT" + fi else - echo "FEATURE_SPEC: $FEATURE_SPEC" - echo "IMPL_PLAN: $IMPL_PLAN" + if $IS_RDF_FEATURE; then + echo "# RDF-First Feature" + echo "FEATURE_SPEC_TTL: $FEATURE_SPEC_TTL" + echo "IMPL_PLAN_TTL: $IMPL_PLAN_TTL" + echo "FEATURE_SPEC (generated): $FEATURE_SPEC" + echo "IMPL_PLAN (generated): $IMPL_PLAN" + echo "ONTOLOGY_DIR: $ONTOLOGY_DIR" + echo "GENERATED_DIR: $GENERATED_DIR" + else + echo "# Legacy Feature" + echo "FEATURE_SPEC: $FEATURE_SPEC_LEGACY" + echo "IMPL_PLAN: $IMPL_PLAN_LEGACY" + fi echo "SPECS_DIR: $FEATURE_DIR" echo "BRANCH: $CURRENT_BRANCH" echo "HAS_GIT: $HAS_GIT" diff --git a/templates/constitution.tera b/templates/constitution.tera new file mode 100644 index 0000000000..fc0c74ab3c --- /dev/null +++ b/templates/constitution.tera @@ -0,0 +1,210 @@ +{# Constitution Template - Renders project constitution from RDF ontology #} +{# Generates constitution.md from constitution.ttl using SPARQL query results #} + +{%- set const_metadata = sparql_results | first -%} + +# {{ const_metadata.projectName }} Constitution + +**Version**: {{ const_metadata.constitutionVersion }} +**Ratified**: {{ const_metadata.ratificationDate }} +**Last Amended**: {{ const_metadata.lastAmendedDate }} + +--- + +## Core Principles + +{%- set principles = sparql_results | filter(attribute="principleIndex") | unique(attribute="principleIndex") | sort(attribute="principleIndex") %} + +{%- for principle in principles %} + +### {{ principle.principleIndex }}. {{ principle.principleName }} + +{{ principle.principleDescription }} + +**Rationale**: {{ principle.principleRationale }} + +{%- if principle.principleExamples %} + +**Examples**: +{{ principle.principleExamples }} +{%- endif %} + +{%- if principle.principleViolations %} + +**Common Violations to Avoid**: +{{ principle.principleViolations }} +{%- endif %} + +--- + +{%- endfor %} + +## Build & Quality Standards + +{%- set build_standards = sparql_results | filter(attribute="buildStandardId") | unique(attribute="buildStandardId") %} +{%- if build_standards | length > 0 %} + +{%- for standard in build_standards %} + +### {{ standard.buildStandardName }} + +{{ standard.buildStandardDescription }} + +**Required Tool**: `{{ standard.buildCommand }}` + +**SLO**: {{ standard.buildSLO }} + +{%- if standard.buildRationale %} +**Why**: {{ standard.buildRationale }} +{%- endif %} + +{%- endfor %} + +{%- else %} + +### cargo make Protocol + +**NEVER use direct cargo commands** - ALWAYS use `cargo make` + +- `cargo make check` - Compilation (<5s timeout) +- `cargo make test` - All tests with timeouts +- `cargo make lint` - Clippy with timeouts + +**Rationale**: Prevents hanging, enforces SLOs, integrated with hooks + +--- + +{%- endif %} + +## Workflow Rules + +{%- set workflow_rules = sparql_results | filter(attribute="workflowRuleId") | unique(attribute="workflowRuleId") %} +{%- if workflow_rules | length > 0 %} + +{%- for rule in workflow_rules %} + +### {{ rule.workflowRuleName }} + +{{ rule.workflowRuleDescription }} + +{%- if rule.workflowRuleExample %} + +**Example**: +``` +{{ rule.workflowRuleExample }} +``` +{%- endif %} + +{%- if rule.workflowRuleEnforcement %} +**Enforcement**: {{ rule.workflowRuleEnforcement }} +{%- endif %} + +--- + +{%- endfor %} + +{%- else %} + +### Error Handling Rule + +**Production Code**: NO `unwrap()` / `expect()` - Use `Result` +**Test/Bench Code**: `unwrap()` / `expect()` ALLOWED + +### Chicago TDD Rule + +**State-based testing with real collaborators** - tests verify behavior, not implementation + +### Concurrent Execution Rule + +**"1 MESSAGE = ALL RELATED OPERATIONS"** - Batch all operations for 2.8-4.4x speed improvement + +--- + +{%- endif %} + +## Governance + +### Amendment Procedure + +{%- if const_metadata.amendmentProcedure %} +{{ const_metadata.amendmentProcedure }} +{%- else %} +1. Propose amendment via pull request to `constitution.ttl` +2. Document rationale and impact analysis +3. Require approval from project maintainers +4. Update version according to semantic versioning +5. Regenerate `constitution.md` from `constitution.ttl` +{%- endif %} + +### Versioning Policy + +{%- if const_metadata.versioningPolicy %} +{{ const_metadata.versioningPolicy }} +{%- else %} +- **MAJOR**: Backward incompatible principle changes or removals +- **MINOR**: New principles added or material expansions +- **PATCH**: Clarifications, wording fixes, non-semantic refinements +{%- endif %} + +### Compliance Review + +{%- if const_metadata.complianceReview %} +{{ const_metadata.complianceReview }} +{%- else %} +Constitution compliance is reviewed: +- Before each feature merge (via `/speckit.finish`) +- During architectural decisions (via `/speckit.plan`) +- In code reviews (enforced by git hooks) +- Violations require either code changes or constitution amendments (explicit) +{%- endif %} + +--- + +## Prohibited Patterns (Zero Tolerance) + +{%- set prohibited = sparql_results | filter(attribute="prohibitedPattern") | unique(attribute="prohibitedPattern") %} +{%- if prohibited | length > 0 %} + +{%- for pattern in prohibited %} +- **{{ pattern.prohibitedPattern }}**: {{ pattern.prohibitedReason }} +{%- endfor %} + +{%- else %} + +1. Direct cargo commands (use `cargo make`) +2. `unwrap()`/`expect()` in production code +3. Ignoring Andon signals (RED/YELLOW) +4. Using `--no-verify` to bypass git hooks +5. Manual editing of generated `.md` files +6. Saving working files to root directory +7. Multiple sequential messages (batch operations) + +{%- endif %} + +--- + +## Key Associations (Mental Models) + +{%- set associations = sparql_results | filter(attribute="associationKey") | unique(attribute="associationKey") %} +{%- if associations | length > 0 %} + +{%- for assoc in associations %} +- **{{ assoc.associationKey }}** = {{ assoc.associationValue }} +{%- endfor %} + +{%- else %} + +- **Types** = invariants = compile-time guarantees +- **Zero-cost** = generics/macros/const generics +- **Ownership** = explicit = memory safety +- **Tests** = observable outputs = behavior verification +- **TTL** = source of truth (edit this) +- **Markdown** = generated artifact (never edit manually) +- **Constitutional Equation** = spec.md = μ(feature.ttl) + +{%- endif %} + +--- + +**Generated with**: [ggen v6](https://github.com/seanchatmangpt/ggen) ontology-driven constitution system +**Constitutional Equation**: `constitution.md = μ(constitution.ttl)` diff --git a/templates/plan.tera b/templates/plan.tera new file mode 100644 index 0000000000..78c20bd131 --- /dev/null +++ b/templates/plan.tera @@ -0,0 +1,187 @@ +{# Plan Template - Renders implementation plan from RDF ontology #} +{# Generates plan.md from plan.ttl using SPARQL query results #} + +{%- set plan_metadata = sparql_results | first -%} + +# Implementation Plan: {{ plan_metadata.featureName }} + +**Branch**: `{{ plan_metadata.featureBranch }}` +**Created**: {{ plan_metadata.planCreated }} +**Status**: {{ plan_metadata.planStatus }} + +--- + +## Technical Context + +**Architecture Pattern**: {{ plan_metadata.architecturePattern }} + +**Technology Stack**: +{%- for row in sparql_results %} +{%- if row.techName %} +- {{ row.techName }}{% if row.techVersion %} ({{ row.techVersion }}){% endif %}{% if row.techPurpose %} - {{ row.techPurpose }}{% endif %} +{%- endif %} +{%- endfor %} + +**Key Dependencies**: +{%- set dependencies = sparql_results | filter(attribute="dependencyName") | unique(attribute="dependencyName") %} +{%- for dep in dependencies %} +- {{ dep.dependencyName }}{% if dep.dependencyVersion %} ({{ dep.dependencyVersion }}){% endif %}{% if dep.dependencyReason %} - {{ dep.dependencyReason }}{% endif %} +{%- endfor %} + +--- + +## Constitution Check + +{%- set const_checks = sparql_results | filter(attribute="principleId") | unique(attribute="principleId") %} +{%- if const_checks | length > 0 %} + +{%- for check in const_checks %} +### {{ check.principleId }}: {{ check.principleName }} + +**Status**: {% if check.compliant == "true" %}✅ COMPLIANT{% else %}❌ VIOLATION{% endif %} + +{{ check.principleDescription }} + +**Compliance Notes**: {{ check.complianceNotes }} + +{%- endfor %} + +{%- else %} +*No constitution checks defined yet.* +{%- endif %} + +--- + +## Research & Decisions + +{%- set decisions = sparql_results | filter(attribute="decisionId") | unique(attribute="decisionId") %} +{%- if decisions | length > 0 %} + +{%- for decision in decisions %} +### {{ decision.decisionId }}: {{ decision.decisionTitle }} + +**Decision**: {{ decision.decisionChoice }} + +**Rationale**: {{ decision.decisionRationale }} + +**Alternatives Considered**: {{ decision.alternativesConsidered }} + +**Trade-offs**: {{ decision.tradeoffs }} + +{%- endfor %} + +{%- else %} +*No research decisions documented yet.* +{%- endif %} + +--- + +## Data Model + +{%- set entities = sparql_results | filter(attribute="entityName") | unique(attribute="entityName") %} +{%- if entities | length > 0 %} + +{%- for entity in entities %} +### {{ entity.entityName }} + +{{ entity.entityDefinition }} + +**Attributes**: +{%- if entity.entityAttributes %} +{{ entity.entityAttributes }} +{%- else %} +*Not defined* +{%- endif %} + +**Relationships**: +{%- if entity.entityRelationships %} +{{ entity.entityRelationships }} +{%- else %} +*None* +{%- endif %} + +{%- endfor %} + +{%- else %} +*No data model defined yet.* +{%- endif %} + +--- + +## API Contracts + +{%- set contracts = sparql_results | filter(attribute="contractId") | unique(attribute="contractId") %} +{%- if contracts | length > 0 %} + +{%- for contract in contracts %} +### {{ contract.contractId }}: {{ contract.contractEndpoint }} + +**Method**: {{ contract.contractMethod }} + +**Description**: {{ contract.contractDescription }} + +**Request**: +``` +{{ contract.contractRequest }} +``` + +**Response**: +``` +{{ contract.contractResponse }} +``` + +{%- if contract.contractValidation %} +**Validation**: {{ contract.contractValidation }} +{%- endif %} + +{%- endfor %} + +{%- else %} +*No API contracts defined yet.* +{%- endif %} + +--- + +## Project Structure + +{%- if plan_metadata.projectStructure %} +``` +{{ plan_metadata.projectStructure }} +``` +{%- else %} +*Project structure to be defined during implementation.* +{%- endif %} + +--- + +## Quality Gates + +{%- set gates = sparql_results | filter(attribute="gateId") | unique(attribute="gateId") %} +{%- if gates | length > 0 %} + +{%- for gate in gates %} +- **{{ gate.gateId }}**: {{ gate.gateDescription }} (Checkpoint: {{ gate.gateCheckpoint }}) +{%- endfor %} + +{%- else %} +1. All tests pass (cargo make test) +2. No clippy warnings (cargo make lint) +3. Code coverage ≥ 80% +4. All SHACL validations pass +5. Constitution compliance verified +{%- endif %} + +--- + +## Implementation Notes + +{%- if plan_metadata.implementationNotes %} +{{ plan_metadata.implementationNotes }} +{%- else %} +*Implementation will follow constitutional principles and SPARC methodology.* +{%- endif %} + +--- + +**Generated with**: [ggen v6](https://github.com/seanchatmangpt/ggen) ontology-driven planning system +**Constitutional Equation**: `plan.md = μ(plan.ttl)` diff --git a/templates/rdf-helpers/assumption.ttl.template b/templates/rdf-helpers/assumption.ttl.template new file mode 100644 index 0000000000..a8bb80cebb --- /dev/null +++ b/templates/rdf-helpers/assumption.ttl.template @@ -0,0 +1,23 @@ +# Assumption Template - Copy this pattern for each assumption +# Replace NNN with assumption number (001, 002, etc.) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix : . + +# Assumption Instance +:assume-NNN a sk:Assumption ; + sk:description "ASSUMPTION DESCRIPTION - State the assumption being made about context, constraints, or environment" . + +# Link to feature (add to feature's hasAssumption list) +:feature-name sk:hasAssumption :assume-NNN . + +# EXAMPLES: +# :assume-001 a sk:Assumption ; +# sk:description "Users have modern browsers with JavaScript enabled (no IE11 support required)" . +# +# :assume-002 a sk:Assumption ; +# sk:description "Data retention policies comply with GDPR (90-day retention for user activity logs)" . +# +# :assume-003 a sk:Assumption ; +# sk:description "System operates in single geographic region (US-East) with <100ms latency" . diff --git a/templates/rdf-helpers/edge-case.ttl.template b/templates/rdf-helpers/edge-case.ttl.template new file mode 100644 index 0000000000..74d138639b --- /dev/null +++ b/templates/rdf-helpers/edge-case.ttl.template @@ -0,0 +1,23 @@ +# Edge Case Template - Copy this pattern for each edge case +# Replace NNN with edge case number (001, 002, etc.) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix : . + +# Edge Case Instance +:edge-NNN a sk:EdgeCase ; + sk:scenario "EDGE CASE SCENARIO - Describe the unusual or boundary condition" ; + sk:expectedBehavior "EXPECTED BEHAVIOR - How the system should handle this edge case" . + +# Link to feature (add to feature's hasEdgeCase list) +:feature-name sk:hasEdgeCase :edge-NNN . + +# EXAMPLES: +# :edge-001 a sk:EdgeCase ; +# sk:scenario "User inputs empty string for required field" ; +# sk:expectedBehavior "System displays validation error: 'This field is required' and prevents form submission" . +# +# :edge-002 a sk:EdgeCase ; +# sk:scenario "Network connection lost during file upload" ; +# sk:expectedBehavior "System retries upload automatically (max 3 attempts) and shows progress to user" . diff --git a/templates/rdf-helpers/entity.ttl.template b/templates/rdf-helpers/entity.ttl.template new file mode 100644 index 0000000000..a72ed2d7be --- /dev/null +++ b/templates/rdf-helpers/entity.ttl.template @@ -0,0 +1,35 @@ +# Entity Template - Copy for each key domain entity +# Entities represent the core data objects in the system + +@prefix sk: . +@prefix : . + +# Entity Instance +:entity-name a sk:Entity ; + sk:entityName "ENTITY NAME (capitalized, singular form)" ; + sk:definition "DEFINITION - What this entity represents in the domain" ; + sk:keyAttributes "ATTRIBUTE LIST - Key properties, fields, or metadata (comma-separated)" . + +# Link to feature (add to feature's hasEntity list) +:feature-name sk:hasEntity :entity-name . + +# EXAMPLES: +# :album a sk:Entity ; +# sk:entityName "Album" ; +# sk:definition "A container for organizing photos by date, event, or theme" ; +# sk:keyAttributes "name (user-provided), creation date (auto-generated), display order (user-customizable), photo count" . +# +# :photo a sk:Entity ; +# sk:entityName "Photo" ; +# sk:definition "An image file stored locally with metadata for display and organization" ; +# sk:keyAttributes "file path, thumbnail image, full-size image, upload date, parent album reference" . + +# VALIDATION RULES: +# - entityName is required (string) +# - definition is required (string) +# - keyAttributes is optional but recommended (comma-separated list) + +# NAMING CONVENTIONS: +# - Use lowercase-hyphen-separated URIs (:photo-album) +# - Use singular form for entity names ("Album" not "Albums") +# - List attributes with types/constraints in parentheses where helpful diff --git a/templates/rdf-helpers/functional-requirement.ttl.template b/templates/rdf-helpers/functional-requirement.ttl.template new file mode 100644 index 0000000000..bb522c8d61 --- /dev/null +++ b/templates/rdf-helpers/functional-requirement.ttl.template @@ -0,0 +1,29 @@ +# Functional Requirement Template - Copy for each requirement +# Replace NNN with requirement number (001, 002, etc.) + +@prefix sk: . +@prefix : . + +# Functional Requirement Instance +:fr-NNN a sk:FunctionalRequirement ; + sk:requirementId "FR-NNN" ; # MUST match pattern: ^FR-[0-9]{3}$ (SHACL validated) + sk:description "System MUST/SHOULD [capability description]" ; + sk:category "CATEGORY NAME" . # Optional: group related requirements + +# Link to feature (add to feature's hasFunctionalRequirement list) +:feature-name sk:hasFunctionalRequirement :fr-NNN . + +# EXAMPLES: +# :fr-001 a sk:FunctionalRequirement ; +# sk:requirementId "FR-001" ; +# sk:description "System MUST allow users to create albums with a user-provided name and auto-generated creation date" . +# +# :fr-002 a sk:FunctionalRequirement ; +# sk:requirementId "FR-002" ; +# sk:category "Album Management" ; +# sk:description "System MUST display albums in a main list view with album name and creation date visible" . + +# VALIDATION RULES (enforced by SHACL): +# - requirementId MUST match pattern: FR-001, FR-002, etc. (not REQ-1, R-001) +# - description is required +# - category is optional diff --git a/templates/rdf-helpers/plan-decision.ttl.template b/templates/rdf-helpers/plan-decision.ttl.template new file mode 100644 index 0000000000..629c4ba100 --- /dev/null +++ b/templates/rdf-helpers/plan-decision.ttl.template @@ -0,0 +1,29 @@ +# Plan Decision Template - Copy this pattern for each architectural/technical decision +# Replace NNN with decision number (001, 002, etc.) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix : . + +# Decision Instance +:decision-NNN a sk:PlanDecision ; + sk:decisionId "DEC-NNN" ; + sk:decisionTitle "DECISION TITLE (e.g., 'Choice of RDF Store')" ; + sk:decisionChoice "CHOSEN OPTION - What was decided" ; + sk:decisionRationale "RATIONALE - Why this option was chosen, business/technical justification" ; + sk:alternativesConsidered "ALTERNATIVES - Other options evaluated and why they were rejected" ; + sk:tradeoffs "TRADEOFFS - What we gain and what we lose with this decision" ; + sk:revisitCriteria "WHEN TO REVISIT - Conditions that might trigger reconsideration of this decision" . + +# Link to plan (add to plan's hasDecision list) +:plan sk:hasDecision :decision-NNN . + +# EXAMPLES: +# :decision-001 a sk:PlanDecision ; +# sk:decisionId "DEC-001" ; +# sk:decisionTitle "RDF Store Selection" ; +# sk:decisionChoice "Oxigraph embedded store" ; +# sk:decisionRationale "Zero external dependencies, fast startup, sufficient for <1M triples, Rust native" ; +# sk:alternativesConsidered "Apache Jena (JVM overhead), Blazegraph (deprecated), GraphDB (commercial)" ; +# sk:tradeoffs "Gain: simplicity, speed. Lose: scalability beyond 1M triples, no SPARQL federation" ; +# sk:revisitCriteria "Dataset grows beyond 500K triples or requires distributed queries" . diff --git a/templates/rdf-helpers/plan.ttl.template b/templates/rdf-helpers/plan.ttl.template new file mode 100644 index 0000000000..545e8e5059 --- /dev/null +++ b/templates/rdf-helpers/plan.ttl.template @@ -0,0 +1,133 @@ +# Implementation Plan Template - Copy this pattern for complete implementation plans +# Replace FEATURE-NAME with actual feature name (e.g., 001-feature-name) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix xsd: . +@prefix : . + +# Plan Instance +:plan a sk:Plan ; + sk:featureBranch "FEATURE-NAME" ; + sk:featureName "FEATURE NAME - Full description of what this feature does" ; + sk:planCreated "YYYY-MM-DD"^^xsd:date ; + sk:planStatus "Draft" ; # Draft, In Progress, Approved, Complete + sk:architecturePattern "ARCHITECTURE PATTERN - e.g., 'Event-driven microservices with CQRS'" ; + sk:hasTechnology :tech-001, :tech-002, :tech-003 ; + sk:hasProjectStructure :struct-001, :struct-002 ; + sk:hasPhase :phase-setup, :phase-foundation, :phase-001 ; + sk:hasDecision :decision-001, :decision-002 ; + sk:hasRisk :risk-001, :risk-002 ; + sk:hasDependency :dep-001 . + +# Technology Stack +:tech-001 a sk:Technology ; + sk:techName "TECH NAME - e.g., 'Rust 1.75+'" ; + sk:techVersion "VERSION - e.g., '1.75+'" ; + sk:techPurpose "PURPOSE - Why this technology was chosen and what it does" . + +:tech-002 a sk:Technology ; + sk:techName "TECH NAME - e.g., 'Oxigraph'" ; + sk:techVersion "VERSION - e.g., '0.3'" ; + sk:techPurpose "PURPOSE - RDF store for ontology processing" . + +:tech-003 a sk:Technology ; + sk:techName "TECH NAME - e.g., 'Tera'" ; + sk:techVersion "VERSION - e.g., '1.19'" ; + sk:techPurpose "PURPOSE - Template engine for code generation" . + +# Project Structure +:struct-001 a sk:ProjectStructure ; + sk:structurePath "PATH - e.g., 'crates/ggen-core/src/'" ; + sk:structurePurpose "PURPOSE - Core domain logic and types" ; + sk:structureNotes "NOTES - Optional: Additional context about this directory" . + +:struct-002 a sk:ProjectStructure ; + sk:structurePath "PATH - e.g., 'crates/ggen-cli/src/'" ; + sk:structurePurpose "PURPOSE - CLI interface and commands" . + +# Implementation Phases +:phase-setup a sk:Phase ; + sk:phaseId "phase-setup" ; + sk:phaseName "Setup" ; + sk:phaseOrder 1 ; + sk:phaseDescription "DESCRIPTION - Initial project setup, configuration, dependencies" ; + sk:phaseDeliverables "DELIVERABLES - What must be completed: project structure, Cargo.toml, basic CI" . + +:phase-foundation a sk:Phase ; + sk:phaseId "phase-foundation" ; + sk:phaseName "Foundation" ; + sk:phaseOrder 2 ; + sk:phaseDescription "DESCRIPTION - Core types, error handling, foundational modules" ; + sk:phaseDeliverables "DELIVERABLES - Result types, error hierarchy, configuration loading" . + +:phase-001 a sk:Phase ; + sk:phaseId "phase-001" ; + sk:phaseName "PHASE NAME - e.g., 'RDF Processing'" ; + sk:phaseOrder 3 ; + sk:phaseDescription "DESCRIPTION - What gets built in this phase" ; + sk:phaseDeliverables "DELIVERABLES - Specific outputs: RDF parser, SPARQL engine, validation" . + +# Technical Decisions (link to plan-decision.ttl.template for details) +:decision-001 a sk:PlanDecision ; + sk:decisionId "DEC-001" ; + sk:decisionTitle "DECISION TITLE - e.g., 'RDF Store Selection'" ; + sk:decisionChoice "CHOSEN OPTION - What was decided" ; + sk:decisionRationale "RATIONALE - Why this option was chosen" ; + sk:alternativesConsidered "ALTERNATIVES - Other options evaluated" ; + sk:tradeoffs "TRADEOFFS - What we gain and lose" ; + sk:revisitCriteria "WHEN TO REVISIT - Conditions for reconsideration" . + +:decision-002 a sk:PlanDecision ; + sk:decisionId "DEC-002" ; + sk:decisionTitle "DECISION TITLE - e.g., 'Error Handling Strategy'" ; + sk:decisionChoice "CHOSEN OPTION - e.g., 'Result with custom error types'" ; + sk:decisionRationale "RATIONALE - Type safety, composability, idiomatic Rust" ; + sk:alternativesConsidered "ALTERNATIVES - anyhow, thiserror crate" ; + sk:tradeoffs "TRADEOFFS - More boilerplate, but better type safety" ; + sk:revisitCriteria "WHEN TO REVISIT - If error handling becomes too verbose" . + +# Risks & Mitigation +:risk-001 a sk:Risk ; + sk:riskId "RISK-001" ; + sk:riskDescription "RISK DESCRIPTION - What could go wrong" ; + sk:riskImpact "high" ; # high, medium, low + sk:riskLikelihood "medium" ; # high, medium, low + sk:mitigationStrategy "MITIGATION - How to prevent or handle this risk" . + +:risk-002 a sk:Risk ; + sk:riskId "RISK-002" ; + sk:riskDescription "RISK DESCRIPTION - e.g., 'SPARQL query performance degrades with large ontologies'" ; + sk:riskImpact "medium" ; + sk:riskLikelihood "high" ; + sk:mitigationStrategy "MITIGATION - e.g., 'Add caching layer, profile early, set 1M triple limit'" . + +# Dependencies (external requirements) +:dep-001 a sk:Dependency ; + sk:dependencyName "DEPENDENCY NAME - e.g., 'Spec-Kit Schema Ontology'" ; + sk:dependencyType "external" ; # external, internal, library + sk:dependencyStatus "available" ; # available, in-progress, blocked + sk:dependencyNotes "NOTES - Where to find it, what version, any setup required" . + +# VALIDATION RULES: +# - All dates must be in YYYY-MM-DD format with ^^xsd:date +# - phaseOrder must be sequential integers +# - riskImpact/riskLikelihood must be "high", "medium", or "low" +# - dependencyStatus must be "available", "in-progress", or "blocked" +# - planStatus must be "Draft", "In Progress", "Approved", or "Complete" + +# EXAMPLES: +# See plan-decision.ttl.template for decision examples +# See task.ttl.template for linking tasks to phases + +# WORKFLOW: +# 1. Copy this template to ontology/plan.ttl +# 2. Replace FEATURE-NAME prefix throughout +# 3. Fill in plan metadata (branch, name, date, status) +# 4. Define technology stack (what you'll use) +# 5. Define project structure (directories and files) +# 6. Define phases (logical groupings of work) +# 7. Document key decisions (architecture, tech choices) +# 8. Identify risks and mitigation strategies +# 9. List dependencies (external requirements) +# 10. Generate plan.md: ggen render templates/plan.tera ontology/plan.ttl > generated/plan.md diff --git a/templates/rdf-helpers/success-criterion.ttl.template b/templates/rdf-helpers/success-criterion.ttl.template new file mode 100644 index 0000000000..e2d0794a26 --- /dev/null +++ b/templates/rdf-helpers/success-criterion.ttl.template @@ -0,0 +1,44 @@ +# Success Criterion Template - Copy for each measurable outcome +# Replace NNN with criterion number (001, 002, etc.) + +@prefix sk: . +@prefix xsd: . +@prefix : . + +# Success Criterion Instance (Measurable) +:sc-NNN a sk:SuccessCriterion ; + sk:criterionId "SC-NNN" ; # MUST match pattern: ^SC-[0-9]{3}$ (SHACL validated) + sk:description "DESCRIPTION of what success looks like" ; + sk:measurable true ; # Boolean: true or false + sk:metric "METRIC NAME - What is being measured" ; # Required if measurable=true + sk:target "TARGET VALUE - The goal or threshold (e.g., < 30 seconds, >= 90%)" . # Required if measurable=true + +# Success Criterion Instance (Non-Measurable) +:sc-NNN a sk:SuccessCriterion ; + sk:criterionId "SC-NNN" ; + sk:description "QUALITATIVE DESCRIPTION of success" ; + sk:measurable false . # No metric/target needed + +# Link to feature (add to feature's hasSuccessCriterion list) +:feature-name sk:hasSuccessCriterion :sc-NNN . + +# EXAMPLES: +# :sc-001 a sk:SuccessCriterion ; +# sk:criterionId "SC-001" ; +# sk:measurable true ; +# sk:metric "Time to create album and add photos" ; +# sk:target "< 30 seconds for 10 photos" ; +# sk:description "Users can create an album and add 10 photos in under 30 seconds" . +# +# :sc-002 a sk:SuccessCriterion ; +# sk:criterionId "SC-002" ; +# sk:measurable true ; +# sk:metric "Task completion rate" ; +# sk:target ">= 90%" ; +# sk:description "90% of users successfully organize photos into albums without assistance on first attempt" . + +# VALIDATION RULES (enforced by SHACL): +# - criterionId MUST match pattern: SC-001, SC-002, etc. (not C-001, SUCCESS-1) +# - description is required +# - measurable is required (boolean) +# - If measurable=true, metric and target are recommended diff --git a/templates/rdf-helpers/task.ttl.template b/templates/rdf-helpers/task.ttl.template new file mode 100644 index 0000000000..5b24d2ee36 --- /dev/null +++ b/templates/rdf-helpers/task.ttl.template @@ -0,0 +1,56 @@ +# Task Template - Copy this pattern for each implementation task +# Replace NNN with task number (001, 002, etc.) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix : . + +# Task Instance +:task-NNN a sk:Task ; + sk:taskId "TNNN" ; # Task ID (T001, T002, etc.) + sk:taskOrder NNN ; # Integer: 1, 2, 3... (execution order) + sk:taskDescription "TASK DESCRIPTION - Clear action with exact file path" ; + sk:filePath "path/to/file.ext" ; # Exact file to create/modify + sk:parallelizable "true"^^xsd:boolean ; # true if can run in parallel, false if sequential + sk:belongsToPhase :phase-NNN ; # Link to phase + sk:relatedToStory :us-NNN ; # Optional: Link to user story if applicable + sk:dependencies "T001, T002" ; # Optional: Comma-separated list of task IDs this depends on + sk:taskNotes "OPTIONAL NOTES - Additional context or implementation hints" . + +# Link to phase (add to phase's hasTasks list) +:phase-NNN sk:hasTask :task-NNN . + +# VALIDATION RULES (enforced by task checklist format): +# - taskId must match format TNNN (T001, T002, etc.) +# - taskOrder must be unique within phase +# - taskDescription should be specific and actionable +# - filePath must be present for implementation tasks +# - parallelizable true only if task has no incomplete dependencies + +# EXAMPLES: +# :task-001 a sk:Task ; +# sk:taskId "T001" ; +# sk:taskOrder 1 ; +# sk:taskDescription "Create project structure per implementation plan" ; +# sk:filePath "." ; +# sk:parallelizable "false"^^xsd:boolean ; +# sk:belongsToPhase :phase-setup . +# +# :task-005 a sk:Task ; +# sk:taskId "T005" ; +# sk:taskOrder 5 ; +# sk:taskDescription "Implement authentication middleware" ; +# sk:filePath "src/middleware/auth.py" ; +# sk:parallelizable "true"^^xsd:boolean ; +# sk:belongsToPhase :phase-foundation ; +# sk:dependencies "T001, T002" ; +# sk:taskNotes "Use JWT tokens, bcrypt for password hashing" . +# +# :task-012 a sk:Task ; +# sk:taskId "T012" ; +# sk:taskOrder 12 ; +# sk:taskDescription "Create User model" ; +# sk:filePath "src/models/user.py" ; +# sk:parallelizable "true"^^xsd:boolean ; +# sk:belongsToPhase :phase-us1 ; +# sk:relatedToStory :us-001 . diff --git a/templates/rdf-helpers/tasks.ttl.template b/templates/rdf-helpers/tasks.ttl.template new file mode 100644 index 0000000000..ba3471d173 --- /dev/null +++ b/templates/rdf-helpers/tasks.ttl.template @@ -0,0 +1,149 @@ +# Tasks Template - Copy this pattern for complete task breakdown +# Replace FEATURE-NAME with actual feature name (e.g., 001-feature-name) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix xsd: . +@prefix : . + +# Tasks Instance +:tasks a sk:Tasks ; + sk:featureBranch "FEATURE-NAME" ; + sk:featureName "FEATURE NAME - Full description of what this feature does" ; + sk:tasksCreated "YYYY-MM-DD"^^xsd:date ; + sk:totalTasks NNN ; # Integer: total number of tasks (e.g., 25) + sk:estimatedEffort "EFFORT ESTIMATE - e.g., '2-3 weeks' or '40-60 hours'" ; + sk:hasPhase :phase-setup, :phase-foundation, :phase-001 . + +# Phase: Setup (foundational tasks, run first) +:phase-setup a sk:Phase ; + sk:phaseId "phase-setup" ; + sk:phaseName "Setup" ; + sk:phaseOrder 1 ; + sk:phaseDescription "Initial project setup, configuration, dependencies" ; + sk:phaseDeliverables "Project structure, Cargo.toml, basic CI" ; + sk:hasTask :task-001, :task-002, :task-003 . + +:task-001 a sk:Task ; + sk:taskId "T001" ; + sk:taskOrder 1 ; + sk:taskDescription "Create project structure per implementation plan" ; + sk:filePath "." ; # Current directory (multiple files) + sk:parallelizable "false"^^xsd:boolean ; # Must run first + sk:belongsToPhase :phase-setup . + +:task-002 a sk:Task ; + sk:taskId "T002" ; + sk:taskOrder 2 ; + sk:taskDescription "Configure Cargo.toml with dependencies (see plan.ttl tech stack)" ; + sk:filePath "Cargo.toml" ; + sk:parallelizable "false"^^xsd:boolean ; + sk:belongsToPhase :phase-setup ; + sk:dependencies "T001" ; # Depends on project structure + sk:taskNotes "Add: oxigraph 0.3, tera 1.19, etc. (from plan.ttl)" . + +:task-003 a sk:Task ; + sk:taskId "T003" ; + sk:taskOrder 3 ; + sk:taskDescription "Set up basic CI pipeline (GitHub Actions)" ; + sk:filePath ".github/workflows/ci.yml" ; + sk:parallelizable "true"^^xsd:boolean ; # Can run in parallel with other setup + sk:belongsToPhase :phase-setup . + +# Phase: Foundation (core types and infrastructure) +:phase-foundation a sk:Phase ; + sk:phaseId "phase-foundation" ; + sk:phaseName "Foundation" ; + sk:phaseOrder 2 ; + sk:phaseDescription "Core types, error handling, foundational modules" ; + sk:phaseDeliverables "Result types, error hierarchy, configuration loading" ; + sk:hasTask :task-004, :task-005 . + +:task-004 a sk:Task ; + sk:taskId "T004" ; + sk:taskOrder 4 ; + sk:taskDescription "Define error types (use Result pattern)" ; + sk:filePath "src/error.rs" ; + sk:parallelizable "true"^^xsd:boolean ; + sk:belongsToPhase :phase-foundation ; + sk:dependencies "T002" ; # Needs dependencies configured + sk:taskNotes "Follow constitutional rule: NO unwrap/expect in production code" . + +:task-005 a sk:Task ; + sk:taskId "T005" ; + sk:taskOrder 5 ; + sk:taskDescription "Create core domain types" ; + sk:filePath "src/types.rs" ; + sk:parallelizable "true"^^xsd:boolean ; + sk:belongsToPhase :phase-foundation ; + sk:dependencies "T004" . + +# Phase: User Story Implementation (map to user stories from feature.ttl) +:phase-001 a sk:Phase ; + sk:phaseId "phase-us1" ; + sk:phaseName "User Story 1 - STORY TITLE" ; + sk:phaseOrder 3 ; + sk:phaseDescription "DESCRIPTION - What this user story accomplishes" ; + sk:phaseDeliverables "DELIVERABLES - Specific outputs for this story" ; + sk:hasTask :task-006, :task-007 . + +:task-006 a sk:Task ; + sk:taskId "T006" ; + sk:taskOrder 6 ; + sk:taskDescription "TASK DESCRIPTION - Implement specific feature component" ; + sk:filePath "src/feature.rs" ; + sk:parallelizable "true"^^xsd:boolean ; + sk:belongsToPhase :phase-001 ; + sk:relatedToStory :us-001 ; # Link to user story from feature.ttl + sk:dependencies "T004, T005" . + +:task-007 a sk:Task ; + sk:taskId "T007" ; + sk:taskOrder 7 ; + sk:taskDescription "Write Chicago TDD tests for feature (state-based, real collaborators)" ; + sk:filePath "tests/feature_tests.rs" ; + sk:parallelizable "true"^^xsd:boolean ; + sk:belongsToPhase :phase-001 ; + sk:relatedToStory :us-001 ; + sk:dependencies "T006" ; + sk:taskNotes "80%+ coverage, AAA pattern, verify observable behavior" . + +# VALIDATION RULES (enforced by SHACL shapes): +# - taskId must match format TNNN (T001, T002, etc.) +# - taskOrder must be unique within entire task list +# - taskDescription should be specific and actionable +# - filePath must be present for implementation tasks +# - parallelizable true only if task has no incomplete dependencies +# - dependencies must reference valid taskId values +# - All dates must be in YYYY-MM-DD format with ^^xsd:date +# - phaseOrder must be sequential integers + +# TASK ORGANIZATION PATTERNS: +# 1. Setup Phase (T001-T00N): Project structure, config, CI +# 2. Foundation Phase (T00N+1-T0NN): Core types, errors, utils +# 3. User Story Phases (T0NN+1-TNNN): One phase per user story (P1, then P2, then P3) +# 4. Polish Phase (TNNN+1-TNNN+N): Documentation, optimization, final tests + +# DEPENDENCY GUIDELINES: +# - Sequential tasks: dependencies="T001, T002" +# - Parallel tasks: parallelizable="true" with no dependencies or completed dependencies +# - Phase dependencies: All foundation tasks depend on setup tasks +# - Story dependencies: All story tasks depend on foundation tasks + +# LINKING TO PLAN: +# - belongsToPhase links to :phase-NNN in plan.ttl +# - relatedToStory links to :us-NNN in feature.ttl +# - Use same phase IDs across plan.ttl and tasks.ttl + +# WORKFLOW: +# 1. Copy this template to ontology/tasks.ttl +# 2. Replace FEATURE-NAME prefix throughout +# 3. Fill in tasks metadata (branch, name, date, total, effort) +# 4. Define phases (match phases from plan.ttl) +# 5. Create tasks for Setup phase (project structure, config, CI) +# 6. Create tasks for Foundation phase (errors, core types, utils) +# 7. Create tasks for each user story (from feature.ttl, ordered by priority) +# 8. Create tasks for Polish phase (docs, optimization, final tests) +# 9. Set parallelizable based on dependencies (false if must run sequentially) +# 10. Set dependencies using comma-separated task IDs (e.g., "T001, T002") +# 11. Generate tasks.md: ggen render templates/tasks.tera ontology/tasks.ttl > generated/tasks.md diff --git a/templates/rdf-helpers/user-story.ttl.template b/templates/rdf-helpers/user-story.ttl.template new file mode 100644 index 0000000000..59c4b1c2cd --- /dev/null +++ b/templates/rdf-helpers/user-story.ttl.template @@ -0,0 +1,39 @@ +# User Story Template - Copy this pattern for each user story +# Replace NNN with story number (001, 002, etc.) +# Replace PLACEHOLDERS with actual content + +@prefix sk: . +@prefix : . + +# User Story Instance +:us-NNN a sk:UserStory ; + sk:storyIndex NNN ; # Integer: 1, 2, 3... + sk:title "TITLE (2-8 words describing the story)" ; + sk:priority "P1" ; # MUST be exactly: "P1", "P2", or "P3" (SHACL validated) + sk:description "USER STORY DESCRIPTION - What the user wants to accomplish and why" ; + sk:priorityRationale "RATIONALE - Why this priority level was chosen, business justification" ; + sk:independentTest "TEST CRITERIA - How to verify this story independently, acceptance criteria" ; + sk:hasAcceptanceScenario :us-NNN-as-001, :us-NNN-as-002 . # Link to scenarios (min 1 required) + +# Acceptance Scenario 1 +:us-NNN-as-001 a sk:AcceptanceScenario ; + sk:scenarioIndex 1 ; + sk:given "INITIAL STATE - The context or preconditions before the action" ; + sk:when "ACTION - The specific action or event that triggers the behavior" ; + sk:then "OUTCOME - The expected result or state after the action" . + +# Acceptance Scenario 2 (add more as needed) +:us-NNN-as-002 a sk:AcceptanceScenario ; + sk:scenarioIndex 2 ; + sk:given "INITIAL STATE 2" ; + sk:when "ACTION 2" ; + sk:then "OUTCOME 2" . + +# Link to feature (add to feature's hasUserStory list) +:feature-name sk:hasUserStory :us-NNN . + +# VALIDATION RULES (enforced by SHACL): +# - priority MUST be "P1", "P2", or "P3" (not "HIGH", "LOW", etc.) +# - storyIndex MUST be a positive integer +# - MUST have at least one acceptance scenario (sk:hasAcceptanceScenario min 1) +# - title, description, priorityRationale, independentTest are required strings diff --git a/templates/tasks.tera b/templates/tasks.tera new file mode 100644 index 0000000000..924eb616e1 --- /dev/null +++ b/templates/tasks.tera @@ -0,0 +1,150 @@ +{# Tasks Template - Renders task breakdown from RDF ontology #} +{# Generates tasks.md from tasks.ttl using SPARQL query results #} + +{%- set tasks_metadata = sparql_results | first -%} + +# Implementation Tasks: {{ tasks_metadata.featureName }} + +**Branch**: `{{ tasks_metadata.featureBranch }}` +**Created**: {{ tasks_metadata.tasksCreated }} +**Total Tasks**: {{ tasks_metadata.totalTasks }} +**Estimated Effort**: {{ tasks_metadata.estimatedEffort }} + +--- + +## Task Organization + +Tasks are organized by user story to enable independent implementation and testing. + +{%- set phases = sparql_results | filter(attribute="phaseId") | unique(attribute="phaseId") | sort(attribute="phaseOrder") %} + +{%- for phase in phases %} + +## Phase {{ phase.phaseOrder }}: {{ phase.phaseName }} + +{%- if phase.phaseDescription %} +{{ phase.phaseDescription }} +{%- endif %} + +{%- if phase.userStoryId %} +**User Story**: {{ phase.userStoryId }} - {{ phase.userStoryTitle }} +**Independent Test**: {{ phase.userStoryTest }} +{%- endif %} + +### Tasks + +{%- set phase_tasks = sparql_results | filter(attribute="phaseId", value=phase.phaseId) | filter(attribute="taskId") | sort(attribute="taskOrder") %} + +{%- for task in phase_tasks %} +- [ ] {{ task.taskId }}{% if task.parallelizable == "true" %} [P]{% endif %}{% if task.userStoryId %} [{{ task.userStoryId }}]{% endif %} {{ task.taskDescription }}{% if task.filePath %} in {{ task.filePath }}{% endif %} +{%- if task.taskNotes %} + - *Note*: {{ task.taskNotes }} +{%- endif %} +{%- if task.dependencies %} + - *Depends on*: {{ task.dependencies }} +{%- endif %} +{%- endfor %} + +{%- if phase.phaseCheckpoint %} + +**Phase Checkpoint**: {{ phase.phaseCheckpoint }} +{%- endif %} + +--- + +{%- endfor %} + +## Task Dependencies + +{%- set dependencies = sparql_results | filter(attribute="dependencyFrom") | unique(attribute="dependencyFrom") %} +{%- if dependencies | length > 0 %} + +```mermaid +graph TD +{%- for dep in dependencies %} + {{ dep.dependencyFrom }} --> {{ dep.dependencyTo }} +{%- endfor %} +``` + +{%- else %} +*No explicit task dependencies defined. Tasks within each phase can be executed in parallel where marked [P].* +{%- endif %} + +--- + +## Parallel Execution Opportunities + +{%- set parallel_tasks = sparql_results | filter(attribute="parallelizable", value="true") | unique(attribute="taskId") %} +{%- if parallel_tasks | length > 0 %} + +The following tasks can be executed in parallel (marked with [P]): + +{%- for task in parallel_tasks %} +- {{ task.taskId }}: {{ task.taskDescription }} +{%- endfor %} + +**Total Parallel Tasks**: {{ parallel_tasks | length }} +**Potential Speed-up**: ~{{ (parallel_tasks | length / 2) | round }}x with 2 developers + +{%- else %} +*No explicitly parallelizable tasks marked. Review task independence to identify parallel opportunities.* +{%- endif %} + +--- + +## Implementation Strategy + +### MVP Scope (Minimum Viable Product) + +Focus on completing **Phase 2** (first user story) to deliver core value: + +{%- set mvp_phase = sparql_results | filter(attribute="phaseOrder", value="2") | first %} +{%- if mvp_phase %} +- {{ mvp_phase.phaseName }} +- {{ mvp_phase.userStoryTitle }} +{%- else %} +- Complete Setup (Phase 1) and first user story (Phase 2) +{%- endif %} + +### Incremental Delivery + +1. **Sprint 1**: Setup + MVP (Phases 1-2) +2. **Sprint 2**: Next priority user story (Phase 3) +3. **Sprint 3+**: Remaining user stories + polish + +### Task Execution Format + +Each task follows this format: +``` +- [ ] TaskID [P?] [StoryID?] Description with file path +``` + +- **TaskID**: Sequential identifier (T001, T002, etc.) +- **[P]**: Optional - Task can be parallelized +- **[StoryID]**: User story this task belongs to +- **Description**: Clear action with exact file path + +--- + +## Progress Tracking + +**Overall Progress**: 0 / {{ tasks_metadata.totalTasks }} tasks completed (0%) + +{%- for phase in phases %} +**{{ phase.phaseName }}**: 0 / {{ phase.taskCount }} tasks completed +{%- endfor %} + +--- + +## Checklist Format Validation + +✅ All tasks follow required format: +- Checkbox prefix: `- [ ]` +- Task ID: Sequential (T001, T002, T003...) +- Optional markers: [P] for parallelizable, [StoryID] for user story +- Clear description with file path + +--- + +**Generated with**: [ggen v6](https://github.com/seanchatmangpt/ggen) ontology-driven task system +**Constitutional Equation**: `tasks.md = μ(tasks.ttl)` From f840df96b0fb5cda85b42f9e327ae1fc6b1a487f Mon Sep 17 00:00:00 2001 From: Sean Chatman <136349053+seanchatmangpt@users.noreply.github.com> Date: Fri, 19 Dec 2025 22:03:11 -0800 Subject: [PATCH 2/3] feat: Add SHACL schema ontology for RDF validation Add spec-kit-schema.ttl (25KB) containing SHACL shapes for validating: - User story priorities (must be P1, P2, or P3) - Feature metadata (dates, status, required fields) - Acceptance scenarios (min 1 per user story) - Task dependencies and parallelization - Entity definitions and requirements This schema enforces quality constraints during ggen render operations. --- ontology/spec-kit-schema.ttl | 717 +++++++++++++++++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100644 ontology/spec-kit-schema.ttl diff --git a/ontology/spec-kit-schema.ttl b/ontology/spec-kit-schema.ttl new file mode 100644 index 0000000000..7d7898d4b9 --- /dev/null +++ b/ontology/spec-kit-schema.ttl @@ -0,0 +1,717 @@ +@prefix rdf: . +@prefix rdfs: . +@prefix owl: . +@prefix xsd: . +@prefix shacl: . +@prefix sk: . + +# ============================================================================ +# Spec-Kit Ontology Schema +# ============================================================================ +# Purpose: RDF vocabulary for Spec-Driven Development (SDD) methodology +# Based on: GitHub Spec-Kit v0.0.22 +# Transformation: Markdown templates → RDF + SHACL + Tera templates +# ============================================================================ + +# ---------------------------------------------------------------------------- +# Core Classes +# ---------------------------------------------------------------------------- + +sk:Feature a owl:Class ; + rdfs:label "Feature"@en ; + rdfs:comment "Complete feature specification with branch, user stories, requirements, and success criteria"@en . + +sk:UserStory a owl:Class ; + rdfs:label "User Story"@en ; + rdfs:comment "Prioritized user journey describing feature value with acceptance scenarios"@en . + +sk:AcceptanceScenario a owl:Class ; + rdfs:label "Acceptance Scenario"@en ; + rdfs:comment "Testable Given-When-Then acceptance criterion for a user story"@en . + +sk:FunctionalRequirement a owl:Class ; + rdfs:label "Functional Requirement"@en ; + rdfs:comment "Specific system capability requirement (FR-XXX pattern)"@en . + +sk:SuccessCriterion a owl:Class ; + rdfs:label "Success Criterion"@en ; + rdfs:comment "Measurable, technology-agnostic outcome metric (SC-XXX pattern)"@en . + +sk:Entity a owl:Class ; + rdfs:label "Entity"@en ; + rdfs:comment "Key domain entity with attributes and relationships"@en . + +sk:EdgeCase a owl:Class ; + rdfs:label "Edge Case"@en ; + rdfs:comment "Boundary condition or error scenario requiring special handling"@en . + +sk:Dependency a owl:Class ; + rdfs:label "Dependency"@en ; + rdfs:comment "External dependency with version constraints"@en . + +sk:Assumption a owl:Class ; + rdfs:label "Assumption"@en ; + rdfs:comment "Documented assumption about feature scope or environment"@en . + +sk:ImplementationPlan a owl:Class ; + rdfs:label "Implementation Plan"@en ; + rdfs:comment "Technical plan with tech stack, architecture, and phases"@en . + +sk:Task a owl:Class ; + rdfs:label "Task"@en ; + rdfs:comment "Actionable implementation task with dependencies and file paths"@en . + +sk:TechnicalContext a owl:Class ; + rdfs:label "Technical Context"@en ; + rdfs:comment "Technical environment: language, dependencies, storage, testing"@en . + +sk:ResearchDecision a owl:Class ; + rdfs:label "Research Decision"@en ; + rdfs:comment "Technology decision with rationale and alternatives"@en . + +sk:DataModel a owl:Class ; + rdfs:label "Data Model"@en ; + rdfs:comment "Entity data model with fields, validation, state transitions"@en . + +sk:Contract a owl:Class ; + rdfs:label "Contract"@en ; + rdfs:comment "API contract specification (OpenAPI, GraphQL, etc.)"@en . + +sk:Clarification a owl:Class ; + rdfs:label "Clarification"@en ; + rdfs:comment "Structured clarification question with options and user response"@en . + +# ---------------------------------------------------------------------------- +# Datatype Properties (Metadata) +# ---------------------------------------------------------------------------- + +sk:featureBranch a owl:DatatypeProperty ; + rdfs:label "feature branch"@en ; + rdfs:domain sk:Feature ; + rdfs:range xsd:string ; + rdfs:comment "Git branch name in NNN-feature-name format"@en . + +sk:featureName a owl:DatatypeProperty ; + rdfs:label "feature name"@en ; + rdfs:domain sk:Feature ; + rdfs:range xsd:string ; + rdfs:comment "Human-readable feature name"@en . + +sk:created a owl:DatatypeProperty ; + rdfs:label "created date"@en ; + rdfs:domain sk:Feature ; + rdfs:range xsd:date ; + rdfs:comment "Feature creation date"@en . + +sk:status a owl:DatatypeProperty ; + rdfs:label "status"@en ; + rdfs:domain sk:Feature ; + rdfs:range xsd:string ; + rdfs:comment "Feature status (Draft, In Progress, Complete, etc.)"@en . + +sk:userInput a owl:DatatypeProperty ; + rdfs:label "user input"@en ; + rdfs:domain sk:Feature ; + rdfs:range xsd:string ; + rdfs:comment "Original user description from /speckit.specify command"@en . + +# ---------------------------------------------------------------------------- +# User Story Properties +# ---------------------------------------------------------------------------- + +sk:storyIndex a owl:DatatypeProperty ; + rdfs:label "story index"@en ; + rdfs:domain sk:UserStory ; + rdfs:range xsd:integer ; + rdfs:comment "Sequential story number for ordering"@en . + +sk:title a owl:DatatypeProperty ; + rdfs:label "title"@en ; + rdfs:range xsd:string ; + rdfs:comment "Brief title (2-8 words)"@en . + +sk:priority a owl:DatatypeProperty ; + rdfs:label "priority"@en ; + rdfs:domain sk:UserStory ; + rdfs:range xsd:string ; + rdfs:comment "Priority level: P1 (critical), P2 (important), P3 (nice-to-have)"@en . + +sk:description a owl:DatatypeProperty ; + rdfs:label "description"@en ; + rdfs:range xsd:string ; + rdfs:comment "Plain language description"@en . + +sk:priorityRationale a owl:DatatypeProperty ; + rdfs:label "priority rationale"@en ; + rdfs:domain sk:UserStory ; + rdfs:range xsd:string ; + rdfs:comment "Why this priority level was assigned"@en . + +sk:independentTest a owl:DatatypeProperty ; + rdfs:label "independent test"@en ; + rdfs:domain sk:UserStory ; + rdfs:range xsd:string ; + rdfs:comment "How to test this story independently for MVP delivery"@en . + +# ---------------------------------------------------------------------------- +# Acceptance Scenario Properties +# ---------------------------------------------------------------------------- + +sk:scenarioIndex a owl:DatatypeProperty ; + rdfs:label "scenario index"@en ; + rdfs:domain sk:AcceptanceScenario ; + rdfs:range xsd:integer ; + rdfs:comment "Scenario number within user story"@en . + +sk:given a owl:DatatypeProperty ; + rdfs:label "given"@en ; + rdfs:domain sk:AcceptanceScenario ; + rdfs:range xsd:string ; + rdfs:comment "Initial state/precondition"@en . + +sk:when a owl:DatatypeProperty ; + rdfs:label "when"@en ; + rdfs:domain sk:AcceptanceScenario ; + rdfs:range xsd:string ; + rdfs:comment "Action or event trigger"@en . + +sk:then a owl:DatatypeProperty ; + rdfs:label "then"@en ; + rdfs:domain sk:AcceptanceScenario ; + rdfs:range xsd:string ; + rdfs:comment "Expected outcome or postcondition"@en . + +# ---------------------------------------------------------------------------- +# Requirement Properties +# ---------------------------------------------------------------------------- + +sk:requirementId a owl:DatatypeProperty ; + rdfs:label "requirement ID"@en ; + rdfs:domain sk:FunctionalRequirement ; + rdfs:range xsd:string ; + rdfs:comment "Requirement identifier (FR-001 format)"@en . + +sk:category a owl:DatatypeProperty ; + rdfs:label "category"@en ; + rdfs:domain sk:FunctionalRequirement ; + rdfs:range xsd:string ; + rdfs:comment "Requirement category (e.g., Configuration, Validation, Pipeline)"@en . + +# ---------------------------------------------------------------------------- +# Success Criterion Properties +# ---------------------------------------------------------------------------- + +sk:criterionId a owl:DatatypeProperty ; + rdfs:label "criterion ID"@en ; + rdfs:domain sk:SuccessCriterion ; + rdfs:range xsd:string ; + rdfs:comment "Success criterion identifier (SC-001 format)"@en . + +sk:measurable a owl:DatatypeProperty ; + rdfs:label "measurable"@en ; + rdfs:domain sk:SuccessCriterion ; + rdfs:range xsd:boolean ; + rdfs:comment "Whether criterion has quantifiable metric"@en . + +sk:metric a owl:DatatypeProperty ; + rdfs:label "metric"@en ; + rdfs:domain sk:SuccessCriterion ; + rdfs:range xsd:string ; + rdfs:comment "Measurement dimension (e.g., time, accuracy, throughput)"@en . + +sk:target a owl:DatatypeProperty ; + rdfs:label "target"@en ; + rdfs:domain sk:SuccessCriterion ; + rdfs:range xsd:string ; + rdfs:comment "Target value or threshold (e.g., '< 2 minutes')"@en . + +# ---------------------------------------------------------------------------- +# Entity Properties +# ---------------------------------------------------------------------------- + +sk:entityName a owl:DatatypeProperty ; + rdfs:label "entity name"@en ; + rdfs:domain sk:Entity ; + rdfs:range xsd:string ; + rdfs:comment "Entity name (PascalCase)"@en . + +sk:definition a owl:DatatypeProperty ; + rdfs:label "definition"@en ; + rdfs:range xsd:string ; + rdfs:comment "Conceptual definition without implementation"@en . + +sk:keyAttributes a owl:DatatypeProperty ; + rdfs:label "key attributes"@en ; + rdfs:domain sk:Entity ; + rdfs:range xsd:string ; + rdfs:comment "Key attributes described conceptually"@en . + +# ---------------------------------------------------------------------------- +# Edge Case Properties +# ---------------------------------------------------------------------------- + +sk:scenario a owl:DatatypeProperty ; + rdfs:label "scenario"@en ; + rdfs:domain sk:EdgeCase ; + rdfs:range xsd:string ; + rdfs:comment "Boundary condition or error scenario description"@en . + +sk:expectedBehavior a owl:DatatypeProperty ; + rdfs:label "expected behavior"@en ; + rdfs:domain sk:EdgeCase ; + rdfs:range xsd:string ; + rdfs:comment "How system should handle this edge case"@en . + +# ---------------------------------------------------------------------------- +# Implementation Plan Properties +# ---------------------------------------------------------------------------- + +sk:language a owl:DatatypeProperty ; + rdfs:label "language"@en ; + rdfs:domain sk:TechnicalContext ; + rdfs:range xsd:string ; + rdfs:comment "Programming language and version (e.g., Python 3.11)"@en . + +sk:primaryDependencies a owl:DatatypeProperty ; + rdfs:label "primary dependencies"@en ; + rdfs:domain sk:TechnicalContext ; + rdfs:range xsd:string ; + rdfs:comment "Key frameworks/libraries (e.g., FastAPI, UIKit)"@en . + +sk:storage a owl:DatatypeProperty ; + rdfs:label "storage"@en ; + rdfs:domain sk:TechnicalContext ; + rdfs:range xsd:string ; + rdfs:comment "Storage technology (e.g., PostgreSQL, files, N/A)"@en . + +sk:testing a owl:DatatypeProperty ; + rdfs:label "testing"@en ; + rdfs:domain sk:TechnicalContext ; + rdfs:range xsd:string ; + rdfs:comment "Testing framework (e.g., pytest, cargo test)"@en . + +sk:targetPlatform a owl:DatatypeProperty ; + rdfs:label "target platform"@en ; + rdfs:domain sk:TechnicalContext ; + rdfs:range xsd:string ; + rdfs:comment "Deployment platform (e.g., Linux server, iOS 15+)"@en . + +sk:projectType a owl:DatatypeProperty ; + rdfs:label "project type"@en ; + rdfs:domain sk:TechnicalContext ; + rdfs:range xsd:string ; + rdfs:comment "Architecture type (single, web, mobile)"@en . + +# ---------------------------------------------------------------------------- +# Task Properties +# ---------------------------------------------------------------------------- + +sk:taskId a owl:DatatypeProperty ; + rdfs:label "task ID"@en ; + rdfs:domain sk:Task ; + rdfs:range xsd:string ; + rdfs:comment "Task identifier (T001 format)"@en . + +sk:taskDescription a owl:DatatypeProperty ; + rdfs:label "task description"@en ; + rdfs:domain sk:Task ; + rdfs:range xsd:string ; + rdfs:comment "Concrete actionable task with file paths"@en . + +sk:parallel a owl:DatatypeProperty ; + rdfs:label "parallel"@en ; + rdfs:domain sk:Task ; + rdfs:range xsd:boolean ; + rdfs:comment "Can run in parallel with other [P] tasks"@en . + +sk:userStoryRef a owl:DatatypeProperty ; + rdfs:label "user story reference"@en ; + rdfs:domain sk:Task ; + rdfs:range xsd:string ; + rdfs:comment "User story this task belongs to (US1, US2, etc.)"@en . + +sk:phase a owl:DatatypeProperty ; + rdfs:label "phase"@en ; + rdfs:domain sk:Task ; + rdfs:range xsd:string ; + rdfs:comment "Implementation phase (Setup, Foundational, User Story N)"@en . + +sk:filePath a owl:DatatypeProperty ; + rdfs:label "file path"@en ; + rdfs:domain sk:Task ; + rdfs:range xsd:string ; + rdfs:comment "Exact file path for implementation"@en . + +# ---------------------------------------------------------------------------- +# Clarification Properties +# ---------------------------------------------------------------------------- + +sk:question a owl:DatatypeProperty ; + rdfs:label "question"@en ; + rdfs:domain sk:Clarification ; + rdfs:range xsd:string ; + rdfs:comment "Clarification question text"@en . + +sk:context a owl:DatatypeProperty ; + rdfs:label "context"@en ; + rdfs:domain sk:Clarification ; + rdfs:range xsd:string ; + rdfs:comment "Relevant spec section or background"@en . + +sk:optionA a owl:DatatypeProperty ; + rdfs:label "option A"@en ; + rdfs:domain sk:Clarification ; + rdfs:range xsd:string . + +sk:optionB a owl:DatatypeProperty ; + rdfs:label "option B"@en ; + rdfs:domain sk:Clarification ; + rdfs:range xsd:string . + +sk:optionC a owl:DatatypeProperty ; + rdfs:label "option C"@en ; + rdfs:domain sk:Clarification ; + rdfs:range xsd:string . + +sk:userResponse a owl:DatatypeProperty ; + rdfs:label "user response"@en ; + rdfs:domain sk:Clarification ; + rdfs:range xsd:string ; + rdfs:comment "User's selected or custom answer"@en . + +# ---------------------------------------------------------------------------- +# Object Properties (Relationships) +# ---------------------------------------------------------------------------- + +sk:hasUserStory a owl:ObjectProperty ; + rdfs:label "has user story"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:UserStory ; + rdfs:comment "Feature contains user stories"@en . + +sk:hasAcceptanceScenario a owl:ObjectProperty ; + rdfs:label "has acceptance scenario"@en ; + rdfs:domain sk:UserStory ; + rdfs:range sk:AcceptanceScenario ; + rdfs:comment "User story defines acceptance scenarios"@en . + +sk:hasFunctionalRequirement a owl:ObjectProperty ; + rdfs:label "has functional requirement"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:FunctionalRequirement ; + rdfs:comment "Feature specifies functional requirements"@en . + +sk:hasSuccessCriterion a owl:ObjectProperty ; + rdfs:label "has success criterion"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:SuccessCriterion ; + rdfs:comment "Feature defines success criteria"@en . + +sk:hasEntity a owl:ObjectProperty ; + rdfs:label "has entity"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:Entity ; + rdfs:comment "Feature involves key entities"@en . + +sk:hasEdgeCase a owl:ObjectProperty ; + rdfs:label "has edge case"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:EdgeCase ; + rdfs:comment "Feature identifies edge cases"@en . + +sk:hasDependency a owl:ObjectProperty ; + rdfs:label "has dependency"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:Dependency ; + rdfs:comment "Feature depends on external dependencies"@en . + +sk:hasAssumption a owl:ObjectProperty ; + rdfs:label "has assumption"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:Assumption ; + rdfs:comment "Feature documents assumptions"@en . + +sk:hasImplementationPlan a owl:ObjectProperty ; + rdfs:label "has implementation plan"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:ImplementationPlan ; + rdfs:comment "Feature has technical implementation plan"@en . + +sk:hasTask a owl:ObjectProperty ; + rdfs:label "has task"@en ; + rdfs:domain sk:ImplementationPlan ; + rdfs:range sk:Task ; + rdfs:comment "Implementation plan breaks down into tasks"@en . + +sk:hasTechnicalContext a owl:ObjectProperty ; + rdfs:label "has technical context"@en ; + rdfs:domain sk:ImplementationPlan ; + rdfs:range sk:TechnicalContext ; + rdfs:comment "Plan specifies technical environment"@en . + +sk:hasClarification a owl:ObjectProperty ; + rdfs:label "has clarification"@en ; + rdfs:domain sk:Feature ; + rdfs:range sk:Clarification ; + rdfs:comment "Feature requires clarifications"@en . + +# ============================================================================ +# SHACL Validation Shapes +# ============================================================================ + +# ---------------------------------------------------------------------------- +# Feature Shape +# ---------------------------------------------------------------------------- + +sk:FeatureShape a shacl:NodeShape ; + shacl:targetClass sk:Feature ; + shacl:property [ + shacl:path sk:featureBranch ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:pattern "^[0-9]{3}-[a-z0-9-]+$" ; + shacl:description "Feature branch must match NNN-feature-name format"@en ; + ] ; + shacl:property [ + shacl:path sk:featureName ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 5 ; + shacl:description "Feature name required (at least 5 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:created ; + shacl:datatype xsd:date ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:description "Creation date required"@en ; + ] ; + shacl:property [ + shacl:path sk:status ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:in ("Draft" "In Progress" "Complete" "Deprecated") ; + shacl:description "Status must be Draft, In Progress, Complete, or Deprecated"@en ; + ] ; + shacl:property [ + shacl:path sk:hasUserStory ; + shacl:class sk:UserStory ; + shacl:minCount 1 ; + shacl:description "Feature must have at least one user story"@en ; + ] ; + shacl:property [ + shacl:path sk:hasFunctionalRequirement ; + shacl:class sk:FunctionalRequirement ; + shacl:minCount 1 ; + shacl:description "Feature must have at least one functional requirement"@en ; + ] ; + shacl:property [ + shacl:path sk:hasSuccessCriterion ; + shacl:class sk:SuccessCriterion ; + shacl:minCount 1 ; + shacl:description "Feature must have at least one success criterion"@en ; + ] . + +# ---------------------------------------------------------------------------- +# User Story Shape +# ---------------------------------------------------------------------------- + +sk:UserStoryShape a shacl:NodeShape ; + shacl:targetClass sk:UserStory ; + shacl:property [ + shacl:path sk:storyIndex ; + shacl:datatype xsd:integer ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minInclusive 1 ; + shacl:description "Story index required (positive integer)"@en ; + ] ; + shacl:property [ + shacl:path sk:title ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 5 ; + shacl:maxLength 100 ; + shacl:description "Story title required (5-100 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:priority ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:in ("P1" "P2" "P3") ; + shacl:description "Priority must be P1, P2, or P3"@en ; + ] ; + shacl:property [ + shacl:path sk:description ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 20 ; + shacl:description "Description required (at least 20 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:priorityRationale ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 10 ; + shacl:description "Priority rationale required (at least 10 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:independentTest ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 10 ; + shacl:description "Independent test description required (at least 10 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:hasAcceptanceScenario ; + shacl:class sk:AcceptanceScenario ; + shacl:minCount 1 ; + shacl:description "User story must have at least one acceptance scenario"@en ; + ] . + +# ---------------------------------------------------------------------------- +# Acceptance Scenario Shape +# ---------------------------------------------------------------------------- + +sk:AcceptanceScenarioShape a shacl:NodeShape ; + shacl:targetClass sk:AcceptanceScenario ; + shacl:property [ + shacl:path sk:scenarioIndex ; + shacl:datatype xsd:integer ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minInclusive 1 ; + shacl:description "Scenario index required (positive integer)"@en ; + ] ; + shacl:property [ + shacl:path sk:given ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 5 ; + shacl:description "Given clause required (at least 5 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:when ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 5 ; + shacl:description "When clause required (at least 5 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:then ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 5 ; + shacl:description "Then clause required (at least 5 characters)"@en ; + ] . + +# ---------------------------------------------------------------------------- +# Functional Requirement Shape +# ---------------------------------------------------------------------------- + +sk:FunctionalRequirementShape a shacl:NodeShape ; + shacl:targetClass sk:FunctionalRequirement ; + shacl:property [ + shacl:path sk:requirementId ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:pattern "^FR-[0-9]{3}$" ; + shacl:description "Requirement ID must match FR-XXX format"@en ; + ] ; + shacl:property [ + shacl:path sk:category ; + shacl:datatype xsd:string ; + shacl:maxCount 1 ; + shacl:description "Optional category for grouping requirements"@en ; + ] ; + shacl:property [ + shacl:path sk:description ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 15 ; + shacl:description "Requirement description required (at least 15 characters)"@en ; + ] . + +# ---------------------------------------------------------------------------- +# Success Criterion Shape +# ---------------------------------------------------------------------------- + +sk:SuccessCriterionShape a shacl:NodeShape ; + shacl:targetClass sk:SuccessCriterion ; + shacl:property [ + shacl:path sk:criterionId ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:pattern "^SC-[0-9]{3}$" ; + shacl:description "Criterion ID must match SC-XXX format"@en ; + ] ; + shacl:property [ + shacl:path sk:measurable ; + shacl:datatype xsd:boolean ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:description "Measurable flag required"@en ; + ] ; + shacl:property [ + shacl:path sk:description ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 15 ; + shacl:description "Success criterion description required (at least 15 characters)"@en ; + ] . + +# ---------------------------------------------------------------------------- +# Task Shape +# ---------------------------------------------------------------------------- + +sk:TaskShape a shacl:NodeShape ; + shacl:targetClass sk:Task ; + shacl:property [ + shacl:path sk:taskId ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:pattern "^T[0-9]{3}$" ; + shacl:description "Task ID must match TXXX format"@en ; + ] ; + shacl:property [ + shacl:path sk:taskDescription ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:minLength 10 ; + shacl:description "Task description required (at least 10 characters)"@en ; + ] ; + shacl:property [ + shacl:path sk:parallel ; + shacl:datatype xsd:boolean ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:description "Parallel flag required (indicates if task can run in parallel)"@en ; + ] ; + shacl:property [ + shacl:path sk:phase ; + shacl:datatype xsd:string ; + shacl:minCount 1 ; + shacl:maxCount 1 ; + shacl:description "Implementation phase required"@en ; + ] . + +# ============================================================================ +# End of Spec-Kit Ontology Schema +# ============================================================================ From 840cf96c4d376a73ac63041a2cd034c8b4d18735 Mon Sep 17 00:00:00 2001 From: Sean Chatman <136349053+seanchatmangpt@users.noreply.github.com> Date: Sat, 20 Dec 2025 10:53:39 -0800 Subject: [PATCH 3/3] chore: Ignore .claude-flow directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1ed573622d..ac8a51e40b 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ env/ .genreleases/ *.zip sdd-*/ +.claude-flow/