Skip to content

Commit 6a9af5a

Browse files
nesonoclaude
andauthored
Design: Configurable document types (#224) (#225)
## Summary - Adds a design document for issue #224: making FIRE's document types consumer-configurable via YAML - Covers YAML config schema, dynamic Pydantic model generation, Bazel integration, and auto-generated FORMAT_SPECIFICATION.md - Outlines 5 implementation phases with backwards compatibility as a key constraint ## Purpose This PR is for team discussion and review of the proposed design before implementation begins. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1c35553 commit 6a9af5a

1 file changed

Lines changed: 184 additions & 0 deletions

File tree

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# Design: Configurable Document Types for FIRE (Issue #224)
2+
3+
## Context
4+
5+
FIRE currently hardcodes three document types (`.sysreq.md`, `.swreq.md`, `.regreq.md`)
6+
with validation rules embedded in Python Pydantic models. Systems engineering teams need
7+
many more document types (`.handbook.md`, `.hara.md`, `.tara.md`, `.opman.md`, etc.) each with
8+
different mandatory/optional fields. The issue asks for a consumer-configurable system
9+
where document formats are defined in YAML, validated by FIRE tooling via Bazel, and
10+
auto-generated into a FORMAT_SPECIFICATION.md usable as LLM context.
11+
12+
## Design: YAML Config Schema
13+
14+
A `fire_config.yaml` in the consumer's repo defines field types and document types:
15+
16+
```yaml
17+
fire_config_version: 1
18+
19+
field_definitions:
20+
sil:
21+
display_name: "SIL"
22+
type: enum
23+
values:
24+
[
25+
"ASIL-A",
26+
"ASIL-B",
27+
"ASIL-C",
28+
"ASIL-D",
29+
"SIL-1",
30+
"SIL-2",
31+
"SIL-3",
32+
"SIL-4",
33+
"DAL-A",
34+
"DAL-B",
35+
"DAL-C",
36+
"DAL-D",
37+
"DAL-E",
38+
"PL-a",
39+
"PL-b",
40+
"PL-c",
41+
"PL-d",
42+
"QM",
43+
]
44+
allow_todo: true
45+
description: "Safety Integrity Level (ISO 26262, IEC 61508, DO-178C/DO-254, ISO 13849, QM)"
46+
47+
sec:
48+
display_name: "Sec"
49+
type: bool
50+
allow_todo: true
51+
description: "Security relevance flag"
52+
53+
version:
54+
display_name: "Version"
55+
type: int
56+
min_value: 1
57+
allow_todo: false
58+
description: "Requirement version, positive integer >= 1"
59+
60+
parent:
61+
display_name: "Parent"
62+
type: parent_link
63+
allow_todo: true
64+
allow_multiple: true
65+
description: "Markdown link(s) to parent requirement(s)"
66+
67+
document_types:
68+
sysreq:
69+
suffix: ".sysreq.md"
70+
display_name: "System Requirement"
71+
description: "High-level system requirements"
72+
required_fields: [sil, sec, version]
73+
optional_fields: [parent]
74+
75+
swreq:
76+
suffix: ".swreq.md"
77+
display_name: "Software Requirement"
78+
description: "Implementation-level software requirements"
79+
required_fields: [sil, sec, version]
80+
optional_fields: [parent]
81+
82+
regreq:
83+
suffix: ".regreq.md"
84+
display_name: "Regulatory Requirement"
85+
description: "Regulatory obligations (SIL/Sec optional)"
86+
required_fields: [version]
87+
optional_fields: [sil, sec, parent]
88+
```
89+
90+
Consumers extend this by adding their own types:
91+
92+
```yaml
93+
handbook:
94+
suffix: ".handbook.md"
95+
display_name: "Handbook Entry"
96+
description: "Product handbook entries"
97+
required_fields: [version]
98+
optional_fields: []
99+
```
100+
101+
## Key Architectural Decisions
102+
103+
- **`field_definitions`** are reusable across document types (sil is identical for sysreq and swreq)
104+
- **Field types**: `enum`, `bool`, `int`, `parent_link` — matching existing Pydantic validators. Extensible later with `string`, `float`, `regex`
105+
- **Default config** ships with FIRE and matches current hardcoded behavior — backwards compatible with no consumer config
106+
- **Dynamic Pydantic models** built at runtime from config, preserving error reporting quality and `extra: "forbid"` behavior
107+
108+
## Files to Create
109+
110+
| File | Purpose |
111+
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
112+
| `fire/starlark/config_models.py` | Pydantic models for config schema (`FireConfig`, `FieldDefinition`, `DocumentType`) + `load_config()` + embedded default |
113+
| `fire/starlark/config_models_test.py` | Tests for config parsing and validation |
114+
| `fire/starlark/dynamic_requirement_model.py` | Factory: config -> Pydantic BaseModel subclass at runtime |
115+
| `fire/starlark/dynamic_requirement_model_test.py` | Tests proving dynamic models match static ones |
116+
| `fire/starlark/default_fire_config.yaml` | Default config file shipped with FIRE |
117+
| `fire/starlark/generate_format_spec.py` | Reads config, produces FORMAT_SPECIFICATION.md |
118+
| `fire/starlark/generate_format_spec_test.py` | Tests for spec generation |
119+
| `fire/starlark/format_spec.bzl` | Bazel rule `generate_format_specification()` |
120+
121+
## Files to Modify
122+
123+
| File | Change |
124+
| -------------------------------------------- | ---------------------------------------------------------------------------------------- |
125+
| `fire/starlark/validate_cross_references.py` | `_metadata_model_for_file()` -> config-driven suffix lookup; `main()` accepts `--config` |
126+
| `fire/starlark/requirements.bzl` | `requirement_library()` gains optional `config` attr, passed to Python script |
127+
| `fire/starlark/release_report.py` | `main()` accepts `--config`; passes to metadata parsing |
128+
| `fire/starlark/reports.bzl` | `release_report` rule gains optional `config` attr |
129+
| `fire/starlark/BUILD.bazel` | New build targets for new files |
130+
| `FORMAT_SPECIFICATION.md` | Replaced by auto-generated output |
131+
132+
## Bazel Integration
133+
134+
```text
135+
fire_config.yaml ─┬──> requirement_library(config=":fire_config")
136+
│ └─> validate_cross_references.py --config fire_config.yaml
137+
138+
├──> release_report(config=":fire_config")
139+
│ └─> release_report.py --config fire_config.yaml
140+
141+
└──> generate_format_specification(config=":fire_config", out="FORMAT_SPEC.md")
142+
└─> generate_format_spec.py --config fire_config.yaml
143+
```
144+
145+
Config is `attr.label(allow_single_file=[".yaml",".yml"], default=None)`. When None, Python scripts use the embedded default.
146+
147+
## Implementation Phases
148+
149+
### Phase 1: Config Models (no behavior change)
150+
151+
1. Create `config_models.py` with Pydantic models for config schema
152+
2. Create `default_fire_config.yaml` matching current behavior
153+
3. Add `load_config()` that loads YAML or returns default
154+
4. Tests: config parses correctly, invalid configs rejected
155+
156+
### Phase 2: Dynamic Model Factory (no behavior change)
157+
158+
1. Create `dynamic_requirement_model.py` — builds Pydantic model from config
159+
2. Tests: dynamic models produce identical validation to static `RequirementMetadata` and `RegulatoryRequirementMetadata` for all existing test cases
160+
161+
### Phase 3: Wire Config into Validation
162+
163+
1. Modify `validate_cross_references.py`: config-driven `_metadata_model_for_file()` and `--config` arg
164+
2. Modify `requirements.bzl`: optional `config` attr
165+
3. Modify `release_report.py` and `reports.bzl`: optional `config` attr
166+
4. Tests: existing tests still pass, new test with custom document type
167+
168+
### Phase 4: Format Specification Generator
169+
170+
1. Create `generate_format_spec.py` and `format_spec.bzl`
171+
2. Replace hand-written `FORMAT_SPECIFICATION.md` with auto-generated output
172+
3. Tests: generated output covers all document types and fields
173+
174+
### Phase 5: Documentation and Examples
175+
176+
1. Update README.md with config section
177+
2. Add example with custom document type
178+
179+
## Verification
180+
181+
- All existing tests pass unchanged (backwards compatibility)
182+
- New unit tests for config parsing, dynamic model generation, format spec generation
183+
- Integration test: add custom document type to `integration_test/`, validate it works end-to-end
184+
- Verify generated FORMAT_SPECIFICATION.md is equivalent to current hand-written one

0 commit comments

Comments
 (0)