feat: Add AI-discoverable documentation headers to all template files (#308)#311
Merged
josecelano merged 22 commits intoJan 28, 2026
Merged
Conversation
- Fix dynamic templates list with correct paths from tree output - Remove JSON files from static templates (no comment support) - Update static templates table with 21 files - Add exclusion note for JSON format in Phase 3 - Fix metadata reference in domain module temporarily
- Add TemplateMetadata struct with DateTime<Utc> field - Use generated_at_iso8601() for template rendering - Remove from_clock() to avoid coupling with Clock trait - Complete Phase 1 of implementation plan docs: [#308] update spec for incremental template implementation - Restructure phases: Phase 1 (infrastructure) is now complete - Phase 2 now processes one template at a time - For each template: update generator → add header → test → commit - Remove bulk infrastructure updates from Phase 1
- Add TemplateMetadata struct with DateTime<Utc> and ISO 8601 serialization
- Update TrackerContext with metadata field (flattened for template compatibility)
- Integrate clock service through generator chain (SystemClock for production)
- Add 22-line AI-discoverable header to tracker.toml.tera template
- Use {%- and -%} delimiters to prevent extra blank lines from control flow
- Fix doctest in TrackerContext to include Clock trait import
- Update specification with detailed process for each Tera template:
* Add AI-discoverable header
* Review and clean up comments (keep config guidance, move implementation details to wrapper)
* Fix Tera delimiters to avoid extra line breaks
* Verify rendered output with pre-commit checks
- First dynamic template complete (9 dynamic + 21 static remaining)
Added template metadata infrastructure to InventoryContext: - Added metadata field with timestamp to InventoryContext - Updated InventoryContextBuilder with metadata support - Integrated Clock service through command handlers and steps - Added clock field to RegisterCommandHandler - Updated all handler constructors to pass clock - Fixed presentation controller to pass clock to handlers Template changes: - Added 20-line AI-discoverable header to inventory.yml.tera - Includes Generated timestamp, Repository, Template path, Rust Wrapper, API Docs - Maintains existing comprehensive comments for dual infrastructure support All tests pass with metadata integration.
Added template metadata infrastructure to AnsibleVariablesContext: - Added metadata field with timestamp to AnsibleVariablesContext - Updated constructor signature to accept metadata as first parameter - Reuses metadata from InventoryContext for consistent timestamps - Added metadata() getter to InventoryContext for access - Updated all test calls to include metadata parameter Template changes: - Added 20-line AI-discoverable header to variables.yml.tera - Includes Generated timestamp, Repository, Template path, Rust Wrapper, API Docs - Maintains existing comments about vars_files usage and consistency All tests pass with metadata integration.
Added explicit '---' delimiter after AI-discoverable header for consistency with variables.yml.tera and YAML best practices. This clearly separates file-level metadata (generation info, documentation) from the YAML document content.
…tera - Added metadata field to DockerComposeContext with #[serde(flatten)] - Added with_metadata() method to DockerComposeContextBuilder - Integrated Clock service through RenderDockerComposeTemplatesStep - Created default metadata fallback using SystemClock for backward compatibility - Added 20-line standardized header matching tracker.toml.tera format - Updated all tests to pass clock parameter to step constructor - All 107 docker_compose tests pass
…limiters
- Add AI-discoverable header with metadata to .env.tera template
- Fix Tera delimiters in .env.tera and variables.yml.tera (use {%- to trim whitespace)
- Update EnvContext to accept TemplateMetadata parameter in constructors
- Fix doctest in env.rs renderer to include metadata parameter
- Update all test helpers to use create_test_metadata() function
- All 406 tests pass successfully
- Add TemplateMetadata field to CaddyContext struct with #[serde(flatten)]
- Update CaddyContext::new() to accept TemplateMetadata as first parameter
- Update RenderCaddyTemplatesStep to accept and use clock service
- Inject SystemClock in release command handler for timestamp generation
- Add custom Default implementation for CaddyContext (metadata with epoch timestamp)
- Add 20-line AI-discoverable header to Caddyfile.tera template
- Header includes: repository URL, template path, wrapper path, API docs, description
- Description: "Caddy reverse proxy configuration with automatic HTTPS. Provides TLS
termination for tracker services using Let's Encrypt. Includes X-Forwarded-For
header configuration critical for peer IP tracking when running behind a proxy."
- Update all tests to use create_test_metadata() helper function
- Fix doctest import to include Clock trait for SystemClock usage
- Delimiters already correct (using {%- format to prevent extra blank lines)
All 406 tests passing.
…urce template - Add TemplateMetadata field to DatasourceContext struct with #[serde(flatten)] - Update DatasourceContext::new() to accept TemplateMetadata as first parameter - Update GrafanaProjectGenerator to accept and use clock service - Update RenderGrafanaTemplatesStep to accept and use clock service - Inject SystemClock in grafana release command handler for timestamp generation - Add custom Default implementation for DatasourceContext (metadata with epoch timestamp) - Add 20-line AI-discoverable header to prometheus.yml.tera template - Header includes: repository URL, template path, wrapper path, API docs, description - Description: "Grafana datasource configuration for Prometheus. Defines the connection settings and query parameters for Grafana to access Prometheus metrics data." - Update all tests to use create_test_metadata() helper function - Template already had no delimiters (no control flow statements) All 406 tests passing.
This commit completes template 8 of 11 dynamic templates, adding metadata infrastructure and AI-discoverable documentation headers. Changes: - Added TemplateMetadata field to PrometheusContext with flattened serialization - Updated PrometheusContext constructor to accept metadata as first parameter - Added custom Default implementation using epoch timestamp (1970-01-01) - Updated PrometheusProjectGenerator to accept Clock service in constructor - Made build_context() non-static to use self.clock for timestamp generation - Updated RenderPrometheusTemplatesStep to accept and inject clock service - Updated release command handler to inject SystemClock - Added create_test_metadata() helper in all test files - Updated all test call sites (18 total) to use metadata parameter - Added 20-line AI-discoverable header to prometheus.yml.tera template - Header includes: repository URL, template path, Rust wrapper path, docs.rs link, description Verified: - All 406 unit tests passing - E2E deployment tests passing (1m 50s) - Pre-commit checks passing (5m 6s) - Rendered output includes timestamp in ISO 8601 format Template count: 8 of 11 dynamic templates complete (73%)
- Add TemplateMetadata with timestamp to CloudInitContext - Inject Clock service through architecture layers: * CloudInitRenderer accepts clock and generates metadata * TofuProjectGenerator passes clock to renderer * Provision handler injects SystemClock * All tests updated with MockClock - Add AI-discoverable header following spec format: * Repository URL and template path * Rust wrapper and API docs links * Template description - CRITICAL: #cloud-config must stay on line 1 for cloud-init - Header placed after #cloud-config with warning comment - All 2089 tests passing - E2E tests passing (infrastructure + deployment workflows)
- Add TemplateMetadata with timestamp to HetznerVariablesContext - Add metadata field to VariablesContext struct (flattened for JSON output) - Add metadata field to VariablesContextBuilder with with_metadata() method - Add MissingMetadata error variant for validation - Update build() method to validate and include metadata - Inject metadata generation in TofuProjectGenerator.render_hetzner_variables_template() - Update all context tests to include metadata (create_test_metadata helper) - Update template wrapper tests to include metadata in test context - Update doc comment example to show with_metadata() usage - Add AI-discoverable header to templates/tofu/hetzner/variables.tfvars.tera - Header follows spec format: Torrust Tracker Deployer - Generated Configuration - Includes: Repository URL, template path, Rust wrapper path, API docs, description - Uses generated_at variable for timestamp in rendered output All 2089 tests passing, E2E tests successful (54s + 1m 59s)
- Add TemplateMetadata with timestamp to LxdVariablesContext - Add metadata field to VariablesContext struct (flattened for JSON output) - Add metadata field to VariablesContextBuilder with with_metadata() method - Add MissingMetadata error variant for validation - Update build() method to validate and include metadata - Inject metadata generation in TofuProjectGenerator.render_lxd_variables_template() - Update all context tests to include metadata (create_test_metadata helper) - Update template wrapper tests to include metadata in test context - Update doc comment example to show with_metadata() usage - Add AI-discoverable header to templates/tofu/lxd/variables.tfvars.tera - Header follows spec format: Torrust Tracker Deployer - Generated Configuration - Includes: Repository URL, template path, Rust wrapper path, API docs, description - Uses generated_at variable for timestamp in rendered output All 2089 tests passing, E2E tests successful (54s + 1m 59s)
All 11 dynamic Tera templates now have AI-discoverable headers
All 11 dynamic Tera templates have been successfully updated with: - AI-discoverable documentation headers - TemplateMetadata infrastructure with timestamps - Rendered output verification - All tests passing (2089 unit tests + E2E tests) Templates completed: - tracker.toml.tera - inventory.yml.tera - variables.yml.tera - docker-compose.yml.tera - .env.tera - Caddyfile.tera - prometheus.yml.tera (Grafana datasource) - prometheus.yml.tera (Prometheus config) - cloud-init.yml.tera - hetzner/variables.tfvars.tera - lxd/variables.tfvars.tera Next: Phase 3 - Static template headers
Move AI-discoverable headers BEFORE the '---' YAML document marker to match the convention used in dynamic templates (e.g., variables.yml.tera). The '---' marker indicates the start of a YAML document and should come after the header metadata, not before it. This ensures consistency across all Ansible templates. Files corrected (17 YAML playbooks): - configure-firewall.yml - configure-security-updates.yml - create-grafana-storage.yml - create-mysql-storage.yml - create-prometheus-storage.yml - create-tracker-storage.yml - deploy-caddy-config.yml - deploy-compose-files.yml - deploy-grafana-provisioning.yml - deploy-prometheus-config.yml - deploy-tracker-config.yml - init-tracker-database.yml - install-docker.yml - install-docker-compose.yml - run-compose-services.yml - update-apt-cache.yml - wait-cloud-init.yml All YAML linters passing
Created comprehensive documentation for YAML template conventions at
docs/contributing/templates/yml.md covering:
Key Conventions:
- Header placement BEFORE '---' YAML document marker (critical rule)
- Rationale: Header is metadata, '---' marks document start
- Consistency across dynamic (.yml.tera) and static (.yml) templates
YAML-Specific Tera Patterns:
- Whitespace control with {%- and -%} to prevent blank lines
- Conditional indentation patterns
- List generation with proper formatting
- Multi-line string handling
Common Pitfalls:
- Wrong document marker placement
- Extra blank lines from control flow
- Breaking YAML indentation
- Unquoted special characters
Best Practices:
- Validate rendered output in build/ directory
- Use comments for user guidance
- Group related configuration
- Test rendered output for blank lines
Also updated:
- docs/contributing/templates/README.md - Added yml.md to documentation index
- docs/issues/308-add-ai-discoverable-documentation-headers-to-templates.md -
Added reference to YAML conventions
All markdown linters passing
Phase 4 Documentation Complete: - Added comprehensive 'AI-Discoverable Documentation Headers' section to template-system-architecture.md covering purpose, format, metadata infrastructure, and YAML placement conventions - Cross-referenced yml.md for YAML-specific patterns - Documented both dynamic and static template header formats Acceptance Criteria Updates: - Marked all quality checks as complete (pre-commit passes) - Verified all task-specific criteria: * TemplateMetadata struct implementation * Clock service injection in all project generators * Metadata fields in all template contexts * Headers in all .tera templates with correct URLs * ISO 8601 timestamps in rendered output * E2E tests passing with headers * Documentation complete - Verified all architectural constraints met Rendered Output Verification: - Confirmed dynamic templates show timestamps (tracker.toml, variables.yml) - Confirmed YAML headers placed before --- marker - Confirmed static templates use simplified headers (install-docker.yml) - All headers include correct repository URLs and API docs links Issue #308 - All 4 phases complete - Phase 1: Infrastructure Setup ✅ - Phase 2: Dynamic Templates (11 files) ✅ - Phase 3: Static Templates (21 files) ✅ - Phase 4: Documentation ✅ Ready for final review and issue closure
Problem:
The CreateCommandHandlerError::InvalidConfiguration error message was
"Configuration validation failed" without including the source error.
This made it impossible for users to see what actual validation failed.
Example of what users saw:
"Create command execution failed: Configuration validation failed"
What they should see:
"Configuration validation failed: Cross-service configuration validation
failed: HTTPS section is defined but no service has TLS configured"
Solution:
Changed error format from:
#[error("Configuration validation failed")]
To:
#[error("Configuration validation failed: {0}")]
This includes the source CreateConfigError in the display, which contains
the specific validation failure (e.g., missing TLS config, invalid port,
etc.).
Impact:
Users now see actionable error messages that tell them exactly what's
wrong with their configuration, not just "validation failed".
Related to: Issue #308 Phase 5 manual E2E testing - discovered while
testing full-stack configuration with MySQL + Prometheus + Grafana + HTTPS
Phase 5: Full-Stack Manual E2E Test - Complete
Test Configuration:
- Provider: LXD (local)
- Database: MySQL (not default SQLite)
- Monitoring: Prometheus + Grafana enabled
- Reverse Proxy: Caddy with HTTPS support
- All optional services: MySQL, Prometheus, Grafana, Caddy
Deployment Performance:
- Infrastructure provisioned: 26.7s
- Software configured: 45s (Docker, security, firewall)
- Application released: 18.4s
- Services started: 39.9s
All Services Verified Healthy:
✓ Tracker (HTTP API): Responding with {status: Ok}
✓ MySQL: 4 tables created, database initialized
✓ Prometheus: Both jobs (metrics + stats) scraping successfully
✓ Grafana: v12.3.1 running, database ok
✓ Caddy: HTTPS configured, certificate obtained (staging)
AI-Discoverable Headers Verified:
✓ Dynamic templates show timestamps (tracker.toml, docker-compose.yml)
✓ Static templates use simplified headers (install-docker.yml)
✓ YAML headers correctly placed BEFORE --- marker
✓ All headers include repository URLs and API docs links
Bugfix Discovered:
- Error messages were hiding validation details
- Fixed InvalidConfiguration to show underlying error: {0}
- Users now see actionable messages like 'HTTPS section defined but
no service has TLS configured'
- Commit: 9a3bab1
Conclusion:
All 32 template files (11 dynamic + 21 static) successfully render
with correct AI-discoverable headers in real-world full-stack
deployment. Headers verified in production-like environment with
all services enabled.
Issue #308 - All 5 phases complete:
- Phase 1: Infrastructure ✅
- Phase 2: Dynamic Templates (11 files) ✅
- Phase 3: Static Templates (21 files) ✅
- Phase 4: Documentation ✅
- Phase 5: Full-Stack E2E Test ✅
Ready for issue closure.
Markdown linting was failing because the Docker containers output code block was missing a language specifier. Added 'text' as the language for the code block showing docker ps output to comply with MD040/fenced-code-language rule. Fixes CI linting workflow failure.
Member
Author
|
ACK 17d07ca |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds AI-discoverable documentation headers to all 32 template files (11 dynamic
.teratemplates + 21 static templates) to improve documentation discoverability for both development-time and production-time scenarios.Issue: Closes #308
Problem
AI agents helping with configuration troubleshooting only see rendered output files, without context about:
Solution
Added standardized documentation headers to all templates containing:
Header Format
Dynamic templates (
.terafiles) - with timestamp:Static templates - simplified (no timestamp, no Rust path):
Implementation
Phase 1: Infrastructure Setup
TemplateMetadatastruct withgenerated_atfield (ISO 8601 format)SystemClockservice into all project generatorsmetadatafield (flattened) to all template contextsPhase 2: Dynamic Templates (11 files)
Updated all
.teratemplates:tracker.toml.tera,inventory.yml.tera,variables.yml.teradocker-compose.yml.tera,.env.tera,Caddyfile.teraprometheus.yml.tera(2 files),cloud-init.yml.terahetzner/variables.tfvars.tera,lxd/variables.tfvars.teraPhase 3: Static Templates (21 files)
Updated with simplified headers:
install-docker.yml,deploy-*.yml, etc.)main.tffiles (LXD + Hetzner)Phase 4: Documentation
template-system-architecture.mdyml.mdfor YAML-specific conventions (header placement before---)Phase 5: Full-Stack Manual E2E Test
Verified headers in real-world deployment with all services:
Bonus: Bugfix
Fixed error message display (discovered during testing):
Testing
✅ Pre-commit checks: All passing (2089 unit tests + E2E + linting)
✅ Manual E2E Test Results:
---markerDocumentation
Files Changed
Breaking Changes
None. Headers are additive and don't change existing functionality.
Migration Guide
Not applicable - backward compatible change.