# ADR-016: Schema-Driven Accessor Generation Pattern\n\n**Status**: Proposed\n**Date**: 2026-01-13\n**Author**: Architecture Team\n**Supersedes**: Manual accessor maintenance in `lib_provisioning/config/accessor.nu`\n\n## Context\n\nThe `lib_provisioning/config/accessor.nu` file contains 1567 lines across 187 accessor functions. Analysis reveals that 95% of these functions follow\nan identical mechanical pattern:\n\n```\nexport def get-{field-name} [--config: record] {\n    config-get "{path.to.field}" {default_value} --config $config\n}\n```\n\nThis represents significant technical debt:\n\n1. **Manual Maintenance Burden**: Adding a new config field requires manually writing a new accessor function\n2. **Schema Drift Risk**: No automated validation that accessor matches the actual Nickel schema\n3. **Code Duplication**: Nearly identical functions across 187 definitions\n4. **Testing Complexity**: Each accessor requires manual testing\n\n## Problem Statement\n\n**Current Architecture**:\n- Nickel schemas define configuration structure (source of truth)\n- Accessor functions manually mirror the schema structure\n- No automated synchronization between schema and accessors\n- High risk of accessor-schema mismatch\n\n**Key Metrics**:\n- 1567 lines of accessor code\n- 187 repetitive functions\n- ~95% code similarity\n\n## Decision\n\nImplement **Schema-Driven Accessor Generation**: automatically generate accessor functions from Nickel schema definitions.\n\n### Architecture\n\n```\nNickel Schema (contracts.ncl)\n    ↓\n[Parse & Extract Schema Structure]\n    ↓\n[Generate Nushell Functions]\n    ↓\naccessor_generated.nu (800 lines)\n    ↓\n[Validation & Integration]\n    ↓\nCI/CD enforces: schema hash == generated code\n```\n\n### Generation Process\n\n1. **Schema Parsing**: Extract field paths, types, and defaults from Nickel contracts\n2. **Code Generation**: Create accessor functions with Nushell 0.109 compliance\n3. **Validation**: Verify generated code against schema\n4. **CI Integration**: Detect schema changes, validate generated code matches\n\n### Compliance Requirements\n\n**Nushell 0.109 Guidelines**:\n- No `try-catch` blocks (use `do-complete` pattern)\n- No `reduce --init` (use `reduce --fold`)\n- No mutable variables (use immutable bindings)\n- No type annotations on boolean flags\n- Use `each` not `map`, `is-not-empty` not `length`\n\n**Nickel Compliance**:\n- Schema-first design (schema is source of truth)\n- Type contracts enforce structure\n- `| doc` before `| default` ordering\n\n## Consequences\n\n### Positive\n\n- **Elimination of Manual Maintenance**: New config fields automatically get accessors\n- **Zero Schema Drift**: Automatic validation ensures accessors match schema\n- **Reduced Code Size**: 1567 lines → ~400 lines (manual core) + ~800 lines (generated)\n- **Type Safety**: Generated code guarantees type correctness\n- **Consistency**: All 187 functions use identical pattern\n\n### Negative\n\n- **Tool Complexity**: Generator must parse Nickel and emit valid Nushell\n- **CI/CD Changes**: Build must validate schema hash\n- **Initial Migration**: One-time effort to verify generated code matches manual versions\n\n## Implementation Strategy\n\n1. **Create Generator** (`tools/codegen/accessor_generator.nu`)\n   - Parse Nickel schema files\n   - Extract paths, types, defaults\n   - Generate valid Nushell code\n   - Emit with proper formatting\n\n2. **Generate Accessors** (`lib_provisioning/config/accessor_generated.nu`)\n   - Run generator on `provisioning/schemas/config/settings/contracts.ncl`\n   - Output 187 accessor functions\n   - Verify compatibility with existing code\n\n3. **Validation**\n   - Integration tests comparing manual vs generated output\n   - Signature validator ensuring generated functions match patterns\n   - CI check for schema hash validity\n\n4. **Gradual Adoption**\n   - Keep manual accessors temporarily\n   - Feature flag to switch between manual and generated\n   - Gradual migration of dependent code\n\n## Testing Strategy\n\n1. **Unit Tests**\n   - Each generated accessor returns correct type\n   - Default values applied correctly\n   - Path resolution handles nested fields\n\n2. **Integration Tests**\n   - Generated accessors produce identical output to manual versions\n   - Config loading pipeline works with generated accessors\n   - Fallback behavior preserved\n\n3. **Regression Tests**\n   - All existing config access patterns work\n   - Performance within 5% of manual version\n   - No breaking changes to public API\n\n## Related ADRs\n\n- **ADR-010**: Configuration Format Strategy (TOML/YAML/Nickel)\n- **ADR-011**: Nickel Migration (schema-first architecture)\n\n## Open Questions\n\n1. Should accessors be regenerated on every build or only on schema changes?\n2. How do we handle conditional fields (if X then Y)?\n3. What's the fallback strategy if generator fails?\n\n## Timeline\n\n- **Phase 1**: Generator implementation (foundation)\n- **Phase 2**: Generate and validate accessor functions\n- **Phase 3**: Integration tests and feature flags\n- **Phase 4**: Full migration and manual code removal\n\n## References\n\n- Nickel Language: [https://nickel-lang.org/](https://nickel-lang.org/)\n- Nushell 0.109 Guidelines: `.claude/guidelines/nushell.md`\n- Current Accessor Implementation: `provisioning/core/nulib/lib_provisioning/config/accessor.nu`\n- Schema Source: `provisioning/schemas/config/settings/contracts.ncl`\n
