# Implementation Plan: Fix Template Rendering Engine

**Branch**: `005-fix-rendering-engine` | **Date**: 2025-12-13 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/005-fix-rendering-engine/spec.md`

## Summary

Fix the `ggen template generate` CLI command to execute SPARQL queries from frontmatter and inject results as `sparql_results.*` into the Tera context. The root cause is that `template generate` uses `GenerateFileOptions` → `generate_file()` which bypasses RDF/SPARQL processing, while `project generate` correctly uses `RenderWithRdfOptions` → `render_with_rdf()`.

**Solution**: Modify `template generate` to auto-detect RDF/SPARQL in templates and route to `render_with_rdf()` when present.

## Technical Context

**Language/Version**: Rust 1.74+ (edition 2021)
**Primary Dependencies**: Oxigraph (RDF/SPARQL), Tera (templating), serde_yaml (frontmatter), gray-matter (parsing)
**Storage**: In-memory Oxigraph store per generation, filesystem for templates/output
**Testing**: Chicago TDD with `cargo make test`, 1,168+ existing tests
**Target Platform**: CLI (macOS, Linux, Windows)
**Project Type**: Workspace with 12 crates
**Performance Goals**: Template parsing ≤5ms, SPARQL queries ≤10ms, generation memory ≤100MB
**Constraints**: Backward compatible with existing templates, deterministic output
**Scale/Scope**: Single crate modification (ggen-cli), ~50 lines changed

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

Verify compliance with ggen Constitution v1.0.0 (`.specify/memory/constitution.md`):

- [x] **I. Crate-First Architecture**: Modification is within existing `ggen-cli` crate, no new crates needed. Change is self-contained in `template.rs` command handler.
- [x] **II. Deterministic RDF Projections**: Same template + RDF → same output. SPARQL execution is deterministic via Oxigraph.
- [x] **III. Chicago TDD**: Will write tests first that verify `sparql_queries_executed > 0` for templates with SPARQL. Tests use real Oxigraph, not mocks.
- [x] **IV. cargo make Protocol**: All commands use `cargo make test`, `cargo make check`. SLOs will be verified.
- [x] **V. Type-First Thinking**: Using existing `RenderWithRdfOptions` struct. No new types needed—reusing proven abstractions.
- [x] **VI. Andon Signal Protocol**: Will monitor `cargo make check` for RED signals during implementation.
- [x] **VII. Error Handling**: All code uses `Result<T, E>`. Existing `render_with_rdf()` already has proper error handling.
- [x] **VIII. Concurrent Execution**: Will batch TodoWrite and file operations. All changes in `crates/` not root.
- [x] **IX. Lean Six Sigma Quality**: Pre-commit hooks enabled, clippy lints clean, type coverage maintained.

**Quality Gates Pass?**: [x] YES

## Project Structure

### Documentation (this feature)

```text
specs/005-fix-rendering-engine/
├── spec.md              # Feature specification (complete)
├── plan.md              # This file
├── research.md          # Root cause analysis (complete)
├── data-model.md        # Entity relationships
├── quickstart.md        # Usage examples
├── checklists/          # Quality validation
│   └── requirements.md  # Spec quality checklist
└── tasks.md             # Generated by /speckit.tasks
```

### Source Code (repository root)

```text
crates/ggen-cli/
├── src/
│   └── cmds/
│       └── template.rs     # MODIFY: generate() function (lines 228-272)
└── tests/
    └── template_rdf_test.rs  # ADD: Integration tests for RDF generation

crates/ggen-domain/
└── src/
    └── template/
        └── render_with_rdf.rs  # Reference: RenderWithRdfOptions struct
```

**Structure Decision**: Minimal change to existing workspace structure. Single file modification in ggen-cli with new test file.

## Implementation Approach

### Step 1: Detect RDF/SPARQL in Template

Before calling `generate_file()`, parse the template frontmatter to check for:
- `rdf:` field (external RDF files)
- `rdf_inline:` field (inline RDF triples)
- `sparql:` field (named SPARQL queries)

If any are present, route to `render_with_rdf()` instead.

### Step 2: Construct RenderWithRdfOptions

When RDF is detected:
```rust
let options = RenderWithRdfOptions {
    template_path: template.clone(),
    output_path: output.clone(),
    variables: vars_map,
    rdf_files: Vec::new(),  // Will be loaded from frontmatter
    force_overwrite: force,
    use_preprocessor: false,
};
template::render_with_rdf(&options)?
```

### Step 3: Handle Multi-File Output

The `render_with_rdf()` function already handles `{# FILE: path #}` markers. No additional changes needed.

### Step 4: Verify Metrics

Ensure result includes:
- `sparql_queries_executed: N` (N > 0 when SPARQL present)
- `rdf_files_loaded: M` (M > 0 when RDF files used)

## Complexity Tracking

> No violations. Implementation uses existing patterns and crates.

| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| None | N/A | N/A |
