aero-agent-roles 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/NOTICE +18 -0
  2. package/README.md +49 -0
  3. package/bin/aero-agent-roles.js +127 -0
  4. package/lib/catalog.js +97 -0
  5. package/lib/install.js +48 -0
  6. package/lib/mcp.js +199 -0
  7. package/manifest.json +516 -0
  8. package/package.json +44 -0
  9. package/roles/aerodynamics-engineer/ROLE.md +153 -0
  10. package/roles/aerodynamics-engineer/SOURCES.md +12 -0
  11. package/roles/aerodynamics-engineer/cli.py +143 -0
  12. package/roles/aerodynamics-engineer/core/aerodynamics_core.py +1218 -0
  13. package/roles/aerodynamics-engineer/templates/aero-design-report-template.md +72 -0
  14. package/roles/aerodynamics-engineer/tests/test_aerodynamics_core.py +227 -0
  15. package/roles/aerodynamics-engineer/tests/test_role_aerodynamics.py +94 -0
  16. package/roles/aircraft-design-engineer/ROLE.md +138 -0
  17. package/roles/aircraft-design-engineer/SOURCES.md +12 -0
  18. package/roles/aircraft-design-engineer/cli.py +152 -0
  19. package/roles/aircraft-design-engineer/core/aircraft_design_core.py +1278 -0
  20. package/roles/aircraft-design-engineer/templates/concept-design-template.md +99 -0
  21. package/roles/aircraft-design-engineer/tests/test_aircraft_design_core.py +269 -0
  22. package/roles/aircraft-design-engineer/tests/test_role_aircraft_design_engineer.py +106 -0
  23. package/roles/airworthiness-compliance-engineer/ROLE.md +122 -0
  24. package/roles/airworthiness-compliance-engineer/SOURCES.md +16 -0
  25. package/roles/airworthiness-compliance-engineer/cli.py +146 -0
  26. package/roles/airworthiness-compliance-engineer/core/airworthiness_core.py +894 -0
  27. package/roles/airworthiness-compliance-engineer/templates/compliance-matrix-template.md +46 -0
  28. package/roles/airworthiness-compliance-engineer/tests/test_airworthiness_core.py +224 -0
  29. package/roles/airworthiness-compliance-engineer/tests/test_role_airworthiness.py +85 -0
  30. package/roles/as9100-quality-auditor/ROLE.md +128 -0
  31. package/roles/as9100-quality-auditor/SOURCES.md +16 -0
  32. package/roles/as9100-quality-auditor/cli.py +136 -0
  33. package/roles/as9100-quality-auditor/core/as9100_core.py +857 -0
  34. package/roles/as9100-quality-auditor/templates/findings-report-template.md +119 -0
  35. package/roles/as9100-quality-auditor/tests/test_as9100_cli_profile.py +105 -0
  36. package/roles/as9100-quality-auditor/tests/test_as9100_core.py +204 -0
  37. package/roles/as9100-quality-auditor/tests/test_role_as9100.py +90 -0
  38. package/roles/data-bus-avionics-engineer/ROLE.md +146 -0
  39. package/roles/data-bus-avionics-engineer/SOURCES.md +23 -0
  40. package/roles/data-bus-avionics-engineer/cli.py +311 -0
  41. package/roles/data-bus-avionics-engineer/core/data_bus_avionics_core.py +1121 -0
  42. package/roles/data-bus-avionics-engineer/templates/bus-assessment-template.md +134 -0
  43. package/roles/data-bus-avionics-engineer/tests/test_bundle_protocol.py +137 -0
  44. package/roles/data-bus-avionics-engineer/tests/test_data_bus_avionics_core.py +261 -0
  45. package/roles/data-bus-avionics-engineer/tests/test_role_data_bus_avionics_engineer.py +121 -0
  46. package/roles/do160-environmental-engineer/ROLE.md +136 -0
  47. package/roles/do160-environmental-engineer/SOURCES.md +30 -0
  48. package/roles/do160-environmental-engineer/cli.py +147 -0
  49. package/roles/do160-environmental-engineer/core/do160_environmental_core.py +1246 -0
  50. package/roles/do160-environmental-engineer/templates/environmental-qualification-plan-template.md +114 -0
  51. package/roles/do160-environmental-engineer/tests/test_do160_environmental_core.py +312 -0
  52. package/roles/do160-environmental-engineer/tests/test_role_do160_environmental_engineer.py +281 -0
  53. package/roles/do178c-cert-engineer/ROLE.md +120 -0
  54. package/roles/do178c-cert-engineer/SOURCES.md +16 -0
  55. package/roles/do178c-cert-engineer/cli.py +129 -0
  56. package/roles/do178c-cert-engineer/core/do178c_core.py +411 -0
  57. package/roles/do178c-cert-engineer/templates/psac-template.md +74 -0
  58. package/roles/do178c-cert-engineer/tests/test_do178c_cert_engineer_core.py +91 -0
  59. package/roles/do178c-cert-engineer/tests/test_role_do178c.py +109 -0
  60. package/roles/do254-hardware-engineer/ROLE.md +127 -0
  61. package/roles/do254-hardware-engineer/SOURCES.md +19 -0
  62. package/roles/do254-hardware-engineer/cli.py +308 -0
  63. package/roles/do254-hardware-engineer/core/do254_hardware_core.py +761 -0
  64. package/roles/do254-hardware-engineer/templates/phac-template.md +87 -0
  65. package/roles/do254-hardware-engineer/tests/test_do254_bundle_profile.py +152 -0
  66. package/roles/do254-hardware-engineer/tests/test_do254_hardware_core.py +200 -0
  67. package/roles/do254-hardware-engineer/tests/test_role_do254_hardware.py +108 -0
  68. package/roles/engineering-analysis-engineer/ROLE.md +154 -0
  69. package/roles/engineering-analysis-engineer/SOURCES.md +15 -0
  70. package/roles/engineering-analysis-engineer/cli.py +151 -0
  71. package/roles/engineering-analysis-engineer/core/engineering_analysis_engineer_core.py +866 -0
  72. package/roles/engineering-analysis-engineer/templates/analysis-memo-template.md +73 -0
  73. package/roles/engineering-analysis-engineer/tests/test_engineering_analysis_engineer_core.py +367 -0
  74. package/roles/engineering-analysis-engineer/tests/test_role_engineering_analysis_engineer.py +113 -0
  75. package/roles/flight-management-engineer/ROLE.md +160 -0
  76. package/roles/flight-management-engineer/SOURCES.md +30 -0
  77. package/roles/flight-management-engineer/cli.py +258 -0
  78. package/roles/flight-management-engineer/core/flight_management_core.py +1473 -0
  79. package/roles/flight-management-engineer/templates/route-assessment-template.md +94 -0
  80. package/roles/flight-management-engineer/tests/test_flight_management_core.py +437 -0
  81. package/roles/flight-management-engineer/tests/test_role_flight_management_engineer.py +123 -0
  82. package/roles/flight-mechanics-engineer/ROLE.md +162 -0
  83. package/roles/flight-mechanics-engineer/SOURCES.md +51 -0
  84. package/roles/flight-mechanics-engineer/cli.py +149 -0
  85. package/roles/flight-mechanics-engineer/core/flight_mechanics_core.py +1507 -0
  86. package/roles/flight-mechanics-engineer/templates/perf-sc-report-template.md +82 -0
  87. package/roles/flight-mechanics-engineer/tests/test_flight_mechanics_core.py +277 -0
  88. package/roles/flight-mechanics-engineer/tests/test_role_flight_mechanics_engineer.py +141 -0
  89. package/roles/flight-test-engineer/ROLE.md +137 -0
  90. package/roles/flight-test-engineer/SOURCES.md +24 -0
  91. package/roles/flight-test-engineer/cli.py +135 -0
  92. package/roles/flight-test-engineer/core/flight_test_core.py +931 -0
  93. package/roles/flight-test-engineer/templates/flight-test-template.md +143 -0
  94. package/roles/flight-test-engineer/tests/test_flight_test_engineer_core.py +227 -0
  95. package/roles/flight-test-engineer/tests/test_role_flight_test_engineer.py +150 -0
  96. package/roles/flight-test-performance-engineer/ROLE.md +165 -0
  97. package/roles/flight-test-performance-engineer/SOURCES.md +20 -0
  98. package/roles/flight-test-performance-engineer/cli.py +319 -0
  99. package/roles/flight-test-performance-engineer/core/flight_test_performance_core.py +1398 -0
  100. package/roles/flight-test-performance-engineer/templates/performance-report-template.md +105 -0
  101. package/roles/flight-test-performance-engineer/tests/test_flight_test_performance_engineer_core.py +308 -0
  102. package/roles/flight-test-performance-engineer/tests/test_role_flight_test_performance_engineer.py +165 -0
  103. package/roles/gnc-engineer/ROLE.md +141 -0
  104. package/roles/gnc-engineer/SOURCES.md +35 -0
  105. package/roles/gnc-engineer/cli.py +141 -0
  106. package/roles/gnc-engineer/core/gnc_core.py +1074 -0
  107. package/roles/gnc-engineer/templates/gnc-report-template.md +105 -0
  108. package/roles/gnc-engineer/tests/test_gnc_engineer_core.py +238 -0
  109. package/roles/gnc-engineer/tests/test_role_gnc_engineer.py +142 -0
  110. package/roles/guidance-engineer/ROLE.md +156 -0
  111. package/roles/guidance-engineer/SOURCES.md +43 -0
  112. package/roles/guidance-engineer/cli.py +280 -0
  113. package/roles/guidance-engineer/core/guidance_core.py +820 -0
  114. package/roles/guidance-engineer/templates/guidance-report-template.md +70 -0
  115. package/roles/guidance-engineer/tests/test_guidance_engineer_core.py +269 -0
  116. package/roles/guidance-engineer/tests/test_role_guidance_engineer.py +146 -0
  117. package/roles/high-speed-aerodynamics-engineer/ROLE.md +161 -0
  118. package/roles/high-speed-aerodynamics-engineer/SOURCES.md +18 -0
  119. package/roles/high-speed-aerodynamics-engineer/cli.py +282 -0
  120. package/roles/high-speed-aerodynamics-engineer/core/high_speed_aero_core.py +1566 -0
  121. package/roles/high-speed-aerodynamics-engineer/templates/high-speed-memo-template.md +75 -0
  122. package/roles/high-speed-aerodynamics-engineer/tests/test_bundle_protocol.py +103 -0
  123. package/roles/high-speed-aerodynamics-engineer/tests/test_high_speed_aero_core.py +280 -0
  124. package/roles/high-speed-aerodynamics-engineer/tests/test_role_high_speed_aerodynamics.py +125 -0
  125. package/roles/ndt-engineer/ROLE.md +157 -0
  126. package/roles/ndt-engineer/SOURCES.md +18 -0
  127. package/roles/ndt-engineer/cli.py +316 -0
  128. package/roles/ndt-engineer/core/ndt_core.py +1590 -0
  129. package/roles/ndt-engineer/templates/ndt-plan-template.md +109 -0
  130. package/roles/ndt-engineer/tests/test_ndt_cli_bundle.py +183 -0
  131. package/roles/ndt-engineer/tests/test_ndt_core.py +437 -0
  132. package/roles/ndt-engineer/tests/test_role_ndt_engineer.py +148 -0
  133. package/roles/numerical-analysis-engineer/ROLE.md +158 -0
  134. package/roles/numerical-analysis-engineer/SOURCES.md +19 -0
  135. package/roles/numerical-analysis-engineer/cli.py +414 -0
  136. package/roles/numerical-analysis-engineer/core/numerical_analysis_core.py +1220 -0
  137. package/roles/numerical-analysis-engineer/templates/verification-memo-template.md +120 -0
  138. package/roles/numerical-analysis-engineer/tests/test_bundle_protocol.py +157 -0
  139. package/roles/numerical-analysis-engineer/tests/test_numerical_analysis_core.py +337 -0
  140. package/roles/numerical-analysis-engineer/tests/test_role_numerical_analysis_engineer.py +117 -0
  141. package/roles/propulsion-engineer/ROLE.md +163 -0
  142. package/roles/propulsion-engineer/SOURCES.md +15 -0
  143. package/roles/propulsion-engineer/cli.py +168 -0
  144. package/roles/propulsion-engineer/core/propulsion_core.py +1291 -0
  145. package/roles/propulsion-engineer/templates/propulsion-report-template.md +92 -0
  146. package/roles/propulsion-engineer/tests/test_propulsion_engineer_core.py +294 -0
  147. package/roles/propulsion-engineer/tests/test_role_propulsion_engineer.py +106 -0
  148. package/roles/space-systems-engineer/ROLE.md +161 -0
  149. package/roles/space-systems-engineer/SOURCES.md +49 -0
  150. package/roles/space-systems-engineer/cli.py +173 -0
  151. package/roles/space-systems-engineer/core/space_systems_core.py +980 -0
  152. package/roles/space-systems-engineer/templates/space-systems-template.md +88 -0
  153. package/roles/space-systems-engineer/tests/test_role_space_systems_engineer.py +117 -0
  154. package/roles/space-systems-engineer/tests/test_space_systems_engineer_core.py +247 -0
  155. package/roles/state-estimation-engineer/ROLE.md +154 -0
  156. package/roles/state-estimation-engineer/SOURCES.md +27 -0
  157. package/roles/state-estimation-engineer/cli.py +326 -0
  158. package/roles/state-estimation-engineer/core/state_estimation_core.py +958 -0
  159. package/roles/state-estimation-engineer/templates/nav-state-estimator-design-template.md +76 -0
  160. package/roles/state-estimation-engineer/tests/test_bundle_protocol.py +110 -0
  161. package/roles/state-estimation-engineer/tests/test_role_state_estimation_engineer.py +127 -0
  162. package/roles/state-estimation-engineer/tests/test_state_estimation_engineer_core.py +231 -0
  163. package/roles/structures-loads-engineer/ROLE.md +171 -0
  164. package/roles/structures-loads-engineer/SOURCES.md +44 -0
  165. package/roles/structures-loads-engineer/cli.py +219 -0
  166. package/roles/structures-loads-engineer/core/structures_loads_core.py +1112 -0
  167. package/roles/structures-loads-engineer/templates/loads-strength-report-template.md +96 -0
  168. package/roles/structures-loads-engineer/tests/test_bundle_protocol.py +101 -0
  169. package/roles/structures-loads-engineer/tests/test_role_structures_loads_engineer.py +147 -0
  170. package/roles/structures-loads-engineer/tests/test_structures_loads_core.py +261 -0
@@ -0,0 +1,411 @@
1
+ #!/usr/bin/env python3
2
+ """do178c_core.py - DO-178C Certification Engineer executable core.
3
+
4
+ This is the role's ENGINE: given a software item's project facts it
5
+ computes DAL requirements, coverage targets, independence, the life
6
+ cycle data set, verification objectives, and BUILDS the Plan for
7
+ Software Aspects of Certification (PSAC) content. It also gate-checks
8
+ deliverables. Standalone: no external repo needed.
9
+
10
+ Domain rules encoded here are public process knowledge (DAL levels,
11
+ coverage metrics, independence practice as published in FAA AC 20-115D /
12
+ EASA AMC 20-115C and standard certification practice). DO-178C text is
13
+ never reproduced - the plan structure is an original synthesis.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import re
19
+ from dataclasses import dataclass, field
20
+ from datetime import date
21
+
22
+ def _today() -> str:
23
+ import os
24
+ from datetime import date
25
+ return os.environ.get("ROLE_GEN_DATE", date.today().isoformat())
26
+
27
+ # ---------------------------------------------------------------------------
28
+ # Domain tables (public process knowledge)
29
+ # ---------------------------------------------------------------------------
30
+
31
+ # Software level from failure-condition severity (FAR 25.1309 / CS-25.1309
32
+ # standard severity categories -> DAL mapping used in certification practice).
33
+ SEVERITY_TO_DAL = {
34
+ "catastrophic": "A",
35
+ "hazardous": "B",
36
+ "major": "C",
37
+ "minor": "D",
38
+ "no-safety-effect": "E",
39
+ }
40
+ DALS = ("A", "B", "C", "D", "E")
41
+
42
+ # Coverage targets by DAL (requirements-based coverage ratios, as used in
43
+ # verification practice: A/B 0.98, C/D 0.95 per measured requirements).
44
+ COVERAGE_TARGET = {"A": 0.98, "B": 0.98, "C": 0.95, "D": 0.95, "E": None}
45
+
46
+ # Structural coverage requirements by DAL (standard practice): MC/DC at A,
47
+ # decision coverage at B, statement coverage at C.
48
+ STRUCTURAL = {
49
+ "A": ["statement", "decision", "mc-dc", "data-coupling", "control-coupling"],
50
+ "B": ["statement", "decision", "data-coupling", "control-coupling"],
51
+ "C": ["statement"],
52
+ "D": [],
53
+ "E": [],
54
+ }
55
+
56
+ # Independence expectations by DAL (verification independence for A/B).
57
+ INDEPENDENT = {"A": True, "B": True, "C": False, "D": False, "E": False}
58
+
59
+ # Life cycle data set by DAL: the data items a PSAC must name. Levels with
60
+ # more rigor require the full set; E is minimal. (Original synthesis of the
61
+ # standard plan-of-attack categories, not reproduced text.)
62
+ LIFE_CYCLE_DATA = {
63
+ "A": [
64
+ "plan for software aspects of certification",
65
+ "software development plan",
66
+ "software verification plan",
67
+ "software configuration management plan",
68
+ "software quality assurance plan",
69
+ "software requirements standards",
70
+ "software design standards",
71
+ "software code standards",
72
+ "software requirements data",
73
+ "software design data",
74
+ "software source code",
75
+ "executable object code",
76
+ "software verification results",
77
+ "software life cycle environment configuration index",
78
+ "software configuration index",
79
+ "software accomplishment summary",
80
+ "software conformity review records",
81
+ ],
82
+ "B": [
83
+ "plan for software aspects of certification",
84
+ "software development plan",
85
+ "software verification plan",
86
+ "software configuration management plan",
87
+ "software quality assurance plan",
88
+ "software requirements standards",
89
+ "software design standards",
90
+ "software code standards",
91
+ "software requirements data",
92
+ "software design data",
93
+ "software source code",
94
+ "executable object code",
95
+ "software verification results",
96
+ "software life cycle environment configuration index",
97
+ "software configuration index",
98
+ "software accomplishment summary",
99
+ ],
100
+ "C": [
101
+ "plan for software aspects of certification",
102
+ "software development plan",
103
+ "software verification plan",
104
+ "software configuration management plan",
105
+ "software quality assurance plan",
106
+ "software requirements data",
107
+ "software design data",
108
+ "software source code",
109
+ "executable object code",
110
+ "software verification results",
111
+ "software life cycle environment configuration index",
112
+ "software configuration index",
113
+ "software accomplishment summary",
114
+ ],
115
+ "D": [
116
+ "plan for software aspects of certification",
117
+ "software development plan",
118
+ "software verification plan",
119
+ "software configuration management plan",
120
+ "software quality assurance plan",
121
+ "software requirements data",
122
+ "software design data",
123
+ "software source code",
124
+ "executable object code",
125
+ "software verification results",
126
+ "software life cycle environment configuration index",
127
+ "software configuration index",
128
+ ],
129
+ "E": [
130
+ "software requirements data",
131
+ "software design data",
132
+ "software source code",
133
+ "software verification results",
134
+ ],
135
+ }
136
+
137
+ # Verification objectives by DAL: the objective families expected per level
138
+ # (public practice: completeness/independence/coverage expectations).
139
+ VERIFICATION_FAMILIES = {
140
+ "A": ["planning", "development", "verification", "cm", "sqa", "cert-liaison"],
141
+ "B": ["planning", "development", "verification", "cm", "sqa", "cert-liaison"],
142
+ "C": ["planning", "development", "verification", "cm", "sqa"],
143
+ "D": ["planning", "development", "verification", "cm", "sqa"],
144
+ "E": ["development", "verification"],
145
+ }
146
+
147
+
148
+ @dataclass
149
+ class SoftwareItem:
150
+ """Project facts the role needs to build the PSAC."""
151
+ item_name: str
152
+ description: str = ""
153
+ failure_condition: str = "major" # severity category
154
+ system_safety_ref: str = "" # FHA/PSSA reference
155
+ life_cycle_model: str = "waterfall"
156
+ programming_languages: list = field(default_factory=lambda: ["C"])
157
+ target_platform: str = ""
158
+ development_tools: list = field(default_factory=list)
159
+ verification_tools: list = field(default_factory=list)
160
+ tool_qualification_approach: str = "criteria-based per DO-330"
161
+ previously_developed: bool = False
162
+ pds_origin_standard: str = ""
163
+ certification_basis: str = "FAR/CS-25"
164
+
165
+ def software_level(self) -> str:
166
+ return SEVERITY_TO_DAL.get(self.failure_condition.lower(), "E")
167
+
168
+
169
+ # ---------------------------------------------------------------------------
170
+ # Core computations
171
+ # ---------------------------------------------------------------------------
172
+
173
+ def _check_dal(dal: str) -> None:
174
+ if dal not in DALS:
175
+ raise ValueError(f"invalid DAL {dal!r}")
176
+
177
+
178
+ def coverage_target(dal: str) -> float | None:
179
+ _check_dal(dal)
180
+ return COVERAGE_TARGET[dal]
181
+
182
+
183
+ def structural_coverage(dal: str) -> list[str]:
184
+ _check_dal(dal)
185
+ return STRUCTURAL[dal]
186
+
187
+
188
+ def independence_required(dal: str) -> bool:
189
+ _check_dal(dal)
190
+ return INDEPENDENT[dal]
191
+
192
+
193
+ def life_cycle_data(dal: str) -> list[str]:
194
+ _check_dal(dal)
195
+ return LIFE_CYCLE_DATA[dal]
196
+
197
+
198
+ def coverage_adequate(dal: str, measured_pct: float) -> bool:
199
+ """True when measured requirements-based coverage meets the DAL target."""
200
+ target = coverage_target(dal)
201
+ if target is None:
202
+ return True
203
+ return measured_pct >= target
204
+
205
+
206
+ def verification_independence_note(dal: str) -> str:
207
+ return ("independent" if independence_required(dal)
208
+ else "may be conducted by the developer")
209
+
210
+
211
+ def structural_methods_text(dal: str) -> str:
212
+ cov = structural_coverage(dal)
213
+ if not cov:
214
+ return "No structural coverage required at this level."
215
+ return "Required: " + ", ".join(cov) + "."
216
+
217
+
218
+ # ---------------------------------------------------------------------------
219
+ # PSAC builder: produces the actual deliverable content
220
+ # ---------------------------------------------------------------------------
221
+
222
+ def build_psac(item: SoftwareItem) -> dict:
223
+ """Build the complete PSAC content model from project facts."""
224
+ dal = item.software_level()
225
+ return {
226
+ "document_type": "Plan for Software Aspects of Certification",
227
+ "status": "draft-for-review",
228
+ "item": item.item_name,
229
+ "item_description": item.description,
230
+ "certification_basis": item.certification_basis,
231
+ "software_level": dal,
232
+ "severity_source": item.failure_condition,
233
+ "system_safety_reference": item.system_safety_ref,
234
+ "life_cycle_model": item.life_cycle_model,
235
+ "coverage_target": coverage_target(dal),
236
+ "structural_coverage": structural_coverage(dal),
237
+ "independence": verification_independence_note(dal),
238
+ "life_cycle_data": life_cycle_data(dal),
239
+ "languages": item.programming_languages,
240
+ "target_platform": item.target_platform,
241
+ "development_tools": item.development_tools,
242
+ "verification_tools": item.verification_tools,
243
+ "tool_qualification_approach": item.tool_qualification_approach,
244
+ "previously_developed": item.previously_developed,
245
+ "pds_origin_standard": item.pds_origin_standard,
246
+ "objectives": VERIFICATION_FAMILIES[dal],
247
+ "generated": _today(),
248
+ }
249
+
250
+
251
+ def render_psac_markdown(model: dict) -> str:
252
+ """Render the PSAC content model as the deliverable markdown document."""
253
+ lines = [
254
+ "# Plan for Software Aspects of Certification",
255
+ "",
256
+ f"**Item:** {model['item']}",
257
+ f"**Software level:** {model['software_level']} "
258
+ f"(from {model['severity_source']} failure condition)",
259
+ f"**Certification basis:** {model['certification_basis']}",
260
+ f"**Status:** {model['status']}",
261
+ "",
262
+ "## 1. Scope",
263
+ "",
264
+ f"This plan covers the software item {model['item']}."
265
+ + (f" {model['item_description']}" if model['item_description'] else ""),
266
+ f"The software level is {model['software_level']} based on the "
267
+ f"{model['severity_source']} failure condition"
268
+ + (f" (system safety reference {model['system_safety_reference']})"
269
+ if model['system_safety_reference'] else "") + ".",
270
+ "",
271
+ "## 2. Software life cycle",
272
+ "",
273
+ f"The {model['life_cycle_model']} life cycle is used. The life cycle "
274
+ "data set for this level is:",
275
+ "",
276
+ *[f"- {d}" for d in model["life_cycle_data"]],
277
+ "",
278
+ "## 3. Software life cycle environment",
279
+ "",
280
+ f"- Development tools: {', '.join(model['development_tools']) or 'none'}"
281
+ if model["development_tools"] else "- Development tools: to be defined",
282
+ f"- Verification tools: {', '.join(model['verification_tools']) or 'none'}"
283
+ if model["verification_tools"] else "- Verification tools: to be defined",
284
+ f"- Tool qualification: {model['tool_qualification_approach']}",
285
+ "",
286
+ "## 4. Software development standards",
287
+ "",
288
+ "- Requirements standards: project-defined, referenced in the "
289
+ "software development plan.",
290
+ "- Design standards: project-defined.",
291
+ f"- Code standards: {', '.join(model['languages'])} subset and "
292
+ "metrics defined in the software code standard.",
293
+ "",
294
+ "## 5. Software verification strategy",
295
+ "",
296
+ f"- Requirements-based coverage target: "
297
+ f"{model['coverage_target']:.2f} (level {model['software_level']}).",
298
+ f"- Structural coverage: {', '.join(model['structural_coverage']) or 'none required'}.",
299
+ f"- Verification independence: {model['independence']}.",
300
+ "",
301
+ "## 6. Software configuration management",
302
+ "",
303
+ "The configuration management plan defines baselines, change "
304
+ "control, archiving, and the configuration index for this item.",
305
+ "",
306
+ "## 7. Software quality assurance",
307
+ "",
308
+ "The software quality assurance plan defines SQA process, audits, "
309
+ "and conformity review for this level.",
310
+ "",
311
+ "## 8. Liaison with airworthiness",
312
+ "",
313
+ "Certification authority liaison and the means of compliance are "
314
+ "defined in the certification plan.",
315
+ "",
316
+ "## 9. Objectives summary",
317
+ "",
318
+ *[f"- {o}" for o in model["objectives"]],
319
+ "",
320
+ "---",
321
+ f"*Generated by Aero Agent Roles do178c-cert-engineer core "
322
+ f"({model['generated']}). DRAFT for human certification engineer "
323
+ "review. Not an approval document.*",
324
+ ]
325
+ return "\n".join(lines)
326
+
327
+
328
+ # ---------------------------------------------------------------------------
329
+ # Evidence gate checkers: verify a deliverable meets the role's gates
330
+ # ---------------------------------------------------------------------------
331
+
332
+ GATE_CHECKS = {
333
+ "level_identified": "software_level is a single valid DAL letter",
334
+ "coverage_target_present": "requirements-based coverage target is a number",
335
+ "structural_stated": "structural coverage list is present for the DAL",
336
+ "life_cycle_data_present": "life cycle data set is non-empty and level-appropriate",
337
+ "sign_off_honest": "document is marked draft-for-review, not approval",
338
+ }
339
+
340
+
341
+ def check_psac(model: dict) -> dict:
342
+ """Run the evidence gates against a PSAC model. Returns pass/fail per gate."""
343
+ dal = model.get("software_level", "")
344
+ results = {
345
+ "level_identified": dal in DALS,
346
+ "coverage_target_present": isinstance(model.get("coverage_target"), (int, float)),
347
+ "structural_stated": isinstance(model.get("structural_coverage"), list),
348
+ "life_cycle_data_present": bool(model.get("life_cycle_data")),
349
+ "sign_off_honest": model.get("status") == "draft-for-review",
350
+ }
351
+ results["all_pass"] = all(results.values())
352
+ return results
353
+
354
+
355
+ def check_psac_markdown(md_text: str, dal: str) -> dict:
356
+ """Gate-check the rendered markdown deliverable."""
357
+ low = md_text.lower()
358
+ level_pat = re.compile(r"software level[:\*]*\s*" + dal.lower() + r"\b")
359
+ checks = {
360
+ "has_title": "plan for software aspects of certification" in low,
361
+ "has_level": bool(level_pat.search(low)),
362
+ "has_coverage": "coverage target" in low,
363
+ "has_draft_marker": "draft" in low,
364
+ "has_not_approval": "not an approval" in low,
365
+ }
366
+ checks["all_pass"] = all(checks.values())
367
+ return checks
368
+
369
+
370
+ def validate_deliverable_text(md_text: str, dal: str) -> dict:
371
+ """Public entry point used by gate tooling: check a PSAC document."""
372
+ return check_psac_markdown(md_text, dal)
373
+
374
+
375
+ # ---------------------------------------------------------------------------
376
+ # Example project (for tests and worked-example generation)
377
+ # ---------------------------------------------------------------------------
378
+
379
+ def example_item() -> SoftwareItem:
380
+ return SoftwareItem(
381
+ item_name="Autopilot Flight Guidance System (FGS) software",
382
+ description="DAL-B autopilot software hosted on the flight "
383
+ "guidance computer.",
384
+ failure_condition="hazardous",
385
+ system_safety_ref="FHA-FGS-001 / PSSA rev C",
386
+ life_cycle_model="waterfall",
387
+ programming_languages=["C"],
388
+ target_platform="PowerPC-based flight guidance computer",
389
+ development_tools=["host compiler", "static analyzer"],
390
+ verification_tools=["requirements-based test harness",
391
+ "code coverage tool"],
392
+ tool_qualification_approach="criteria-based qualification per DO-330",
393
+ certification_basis="FAR/CS-25",
394
+ )
395
+
396
+
397
+ def example_psac_markdown() -> str:
398
+ return render_psac_markdown(build_psac(example_item()))
399
+
400
+
401
+ if __name__ == "__main__":
402
+ import sys
403
+ item = example_item()
404
+ model = build_psac(item)
405
+ md = render_psac_markdown(model)
406
+ print(f"SOFTWARE LEVEL: {model['software_level']}")
407
+ print(f"COVERAGE TARGET: {model['coverage_target']:.2f}")
408
+ print(f"INDEPENDENCE: {model['independence']}")
409
+ print(f"LIFE CYCLE DATA: {len(model['life_cycle_data'])} items")
410
+ print(f"GATES: {check_psac(model)}")
411
+ print(f"RENDERED: {len(md)} chars")
@@ -0,0 +1,74 @@
1
+ # Plan for Software Aspects of Certification
2
+
3
+ **Item:** Autopilot Flight Guidance System (FGS) software
4
+ **Software level:** B (from hazardous failure condition)
5
+ **Certification basis:** FAR/CS-25
6
+ **Status:** draft-for-review
7
+
8
+ ## 1. Scope
9
+
10
+ This plan covers the software item Autopilot Flight Guidance System (FGS) software. DAL-B autopilot software hosted on the flight guidance computer.
11
+ The software level is B based on the hazardous failure condition (system safety reference FHA-FGS-001 / PSSA rev C).
12
+
13
+ ## 2. Software life cycle
14
+
15
+ The waterfall life cycle is used. The life cycle data set for this level is:
16
+
17
+ - plan for software aspects of certification
18
+ - software development plan
19
+ - software verification plan
20
+ - software configuration management plan
21
+ - software quality assurance plan
22
+ - software requirements standards
23
+ - software design standards
24
+ - software code standards
25
+ - software requirements data
26
+ - software design data
27
+ - software source code
28
+ - executable object code
29
+ - software verification results
30
+ - software life cycle environment configuration index
31
+ - software configuration index
32
+ - software accomplishment summary
33
+
34
+ ## 3. Software life cycle environment
35
+
36
+ - Development tools: host compiler, static analyzer
37
+ - Verification tools: requirements-based test harness, code coverage tool
38
+ - Tool qualification: criteria-based qualification per DO-330
39
+
40
+ ## 4. Software development standards
41
+
42
+ - Requirements standards: project-defined, referenced in the software development plan.
43
+ - Design standards: project-defined.
44
+ - Code standards: C subset and metrics defined in the software code standard.
45
+
46
+ ## 5. Software verification strategy
47
+
48
+ - Requirements-based coverage target: 0.98 (level B).
49
+ - Structural coverage: statement, decision, data-coupling, control-coupling.
50
+ - Verification independence: independent.
51
+
52
+ ## 6. Software configuration management
53
+
54
+ The configuration management plan defines baselines, change control, archiving, and the configuration index for this item.
55
+
56
+ ## 7. Software quality assurance
57
+
58
+ The software quality assurance plan defines SQA process, audits, and conformity review for this level.
59
+
60
+ ## 8. Liaison with airworthiness
61
+
62
+ Certification authority liaison and the means of compliance are defined in the certification plan.
63
+
64
+ ## 9. Objectives summary
65
+
66
+ - planning
67
+ - development
68
+ - verification
69
+ - cm
70
+ - sqa
71
+ - cert-liaison
72
+
73
+ ---
74
+ *Generated by Aero Agent Roles do178c-cert-engineer core (2026-09-05). DRAFT for human certification engineer review. Not an approval document.*
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env python3
2
+ """Test do178c_core: the executable engine of the DO-178C role.
3
+
4
+ Proves the role can DO its job standalone (no AeroSkills needed):
5
+ DAL determination, coverage targets, independence, life cycle data,
6
+ PSAC generation, and evidence-gate checks.
7
+ """
8
+ import os
9
+ import sys
10
+ import unittest
11
+
12
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "core"))
13
+ from do178c_core import (
14
+ SEVERITY_TO_DAL, build_psac, check_psac, check_psac_markdown,
15
+ coverage_adequate, coverage_target, example_item,
16
+ example_psac_markdown, independence_required, life_cycle_data,
17
+ render_psac_markdown, structural_coverage,
18
+ )
19
+
20
+
21
+ class TestCoreDomainRules(unittest.TestCase):
22
+
23
+ def test_severity_to_dal_mapping(self):
24
+ self.assertEqual(SEVERITY_TO_DAL["catastrophic"], "A")
25
+ self.assertEqual(SEVERITY_TO_DAL["hazardous"], "B")
26
+ self.assertEqual(SEVERITY_TO_DAL["major"], "C")
27
+ self.assertEqual(SEVERITY_TO_DAL["minor"], "D")
28
+
29
+ def test_coverage_targets(self):
30
+ self.assertEqual(coverage_target("A"), 0.98)
31
+ self.assertEqual(coverage_target("C"), 0.95)
32
+ self.assertIsNone(coverage_target("E"))
33
+
34
+ def test_structural_by_dal(self):
35
+ self.assertIn("mc-dc", structural_coverage("A"))
36
+ self.assertIn("decision", structural_coverage("B"))
37
+ self.assertEqual(structural_coverage("C"), ["statement"])
38
+ self.assertEqual(structural_coverage("D"), [])
39
+
40
+ def test_independence(self):
41
+ self.assertTrue(independence_required("A"))
42
+ self.assertTrue(independence_required("B"))
43
+ self.assertFalse(independence_required("C"))
44
+
45
+ def test_life_cycle_scope(self):
46
+ self.assertGreater(len(life_cycle_data("A")), len(life_cycle_data("D")))
47
+ self.assertIn("plan for software aspects of certification",
48
+ life_cycle_data("B"))
49
+
50
+ def test_coverage_adequate(self):
51
+ self.assertTrue(coverage_adequate("A", 0.99))
52
+ self.assertFalse(coverage_adequate("A", 0.97))
53
+ self.assertTrue(coverage_adequate("E", 0.0)) # no target
54
+
55
+
56
+ class TestPsacBuilder(unittest.TestCase):
57
+
58
+ def test_example_level_b(self):
59
+ model = build_psac(example_item())
60
+ self.assertEqual(model["software_level"], "B")
61
+ self.assertEqual(model["coverage_target"], 0.98)
62
+ self.assertEqual(model["status"], "draft-for-review")
63
+
64
+ def test_psac_has_required_sections(self):
65
+ md = example_psac_markdown()
66
+ for sec in ["## 1. Scope", "## 5. Software verification strategy",
67
+ "## 6. Software configuration management", "## 9. Objectives"]:
68
+ self.assertIn(sec, md)
69
+ self.assertIn("not an approval", md.lower())
70
+
71
+ def test_core_gates_all_pass(self):
72
+ model = build_psac(example_item())
73
+ gates = check_psac(model)
74
+ self.assertTrue(gates["all_pass"], gates)
75
+
76
+ def test_markdown_gates_all_pass(self):
77
+ md = example_psac_markdown()
78
+ gates = check_psac_markdown(md, "B")
79
+ self.assertTrue(gates["all_pass"], gates)
80
+
81
+ def test_standalone_no_skills_repo(self):
82
+ # Core must work with no AeroSkills present: set env to a bad path.
83
+ os.environ["AEROSKILLS_DEV"] = "/nonexistent"
84
+ model = build_psac(example_item())
85
+ self.assertTrue(model["software_level"] in "ABCDE")
86
+ md = render_psac_markdown(model)
87
+ self.assertGreater(len(md), 1000)
88
+
89
+
90
+ if __name__ == "__main__":
91
+ unittest.main()
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+ """Role test: DO-178C Certification Engineer.
3
+
4
+ Verifies (offline, no network):
5
+ 1. Every skill bound in ROLE.md frontmatter RESOLVES to a real leaf in
6
+ the aero-agent-skills repo (the pinned skills_release band).
7
+ 2. The workflow stage order is deterministic and complete.
8
+ 3. Evidence-gate smoke: a synthetic project (mock requirements + tests)
9
+ produces a complete PSAC skeleton with no blank sections.
10
+ """
11
+ import os
12
+ import re
13
+ import sys
14
+ import tempfile
15
+ import unittest
16
+
17
+ ROLES_REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(
18
+ os.path.abspath(__file__))))) # repo root (4 up from tests/)
19
+ # Bound-skill resolution requires the Aero Agent Skills checkout. It is a
20
+ # cross-repo dev check: when the skills repo is absent (fresh public clone),
21
+ # skip resolution rather than fail - the role's bound list is verified in CI.
22
+ AEROSKILLS = os.environ.get("AEROSKILLS_DEV", os.path.expanduser("~/AeroSkills"))
23
+ HAS_SKILLS = os.path.isdir(os.path.join(AEROSKILLS, "skills"))
24
+ ROLE_DIR = os.path.join(ROLES_REPO, "roles", "do178c-cert-engineer")
25
+ PSAC_TEMPLATE = os.path.join(ROLE_DIR, "templates", "psac-template.md")
26
+
27
+ EXPECTED_BOUND = [
28
+ "avionics/do178c/planning",
29
+ "avionics/do178c/development",
30
+ "avionics/do178c/verification",
31
+ "avionics/do178c/software-testing",
32
+ "avionics/do178c/configuration-management",
33
+ "avionics/do178c/tool-qualification",
34
+ "avionics/do178c/previously-developed-software",
35
+ "avionics/do178c/data-control-coupling-analysis",
36
+ "avionics/do178c/airworthiness-liaison",
37
+ ]
38
+
39
+ EXPECTED_STAGES = [
40
+ "Planning", "Dev framework", "Verification strategy", "Test evidence",
41
+ "CM", "Tool qualification", "PDS check", "Coupling analysis",
42
+ "Airworthiness liaison",
43
+ ]
44
+
45
+
46
+ def read_role_md():
47
+ p = os.path.join(ROLE_DIR, "ROLE.md")
48
+ if not os.path.exists(p):
49
+ return None
50
+ return open(p).read()
51
+
52
+
53
+ class TestDo178cRole(unittest.TestCase):
54
+
55
+ def test_bound_skills_resolve_in_aeroskills(self):
56
+ if not HAS_SKILLS:
57
+ self.skipTest("Aero Agent Skills checkout not present (cross-repo dev check)")
58
+ for leaf in EXPECTED_BOUND:
59
+ sk = os.path.join(AEROSKILLS, "skills", leaf, "SKILL.md")
60
+ self.assertTrue(
61
+ os.path.exists(sk),
62
+ f"bound skill not found in aero-agent-skills: {leaf}")
63
+
64
+ def test_bound_skills_listed_in_frontmatter(self):
65
+ role = read_role_md()
66
+ self.assertIsNotNone(role)
67
+ for leaf in EXPECTED_BOUND:
68
+ self.assertIn(leaf, role, f"missing in ROLE.md skills_bound: {leaf}")
69
+
70
+ def test_workflow_stages_deterministic(self):
71
+ role = read_role_md()
72
+ # every expected stage appears in order (indexes ascending)
73
+ idx = [role.find(stage) for stage in EXPECTED_STAGES]
74
+ self.assertTrue(all(i >= 0 for i in idx), "a stage is missing")
75
+ self.assertEqual(idx, sorted(idx), "stage order not deterministic")
76
+
77
+ def test_deliverable_template_complete(self):
78
+ if not os.path.exists(PSAC_TEMPLATE):
79
+ self.fail("psac-template.md missing")
80
+ text = open(PSAC_TEMPLATE).read()
81
+ # all 9 numbered sections present
82
+ for n in range(1, 10):
83
+ self.assertTrue(
84
+ re.search(rf"^## {n}\. ", text, re.M),
85
+ f"section {n} missing")
86
+ self.assertIn("DRAFT", text)
87
+ low = text.lower()
88
+ self.assertIn("not an approval", low)
89
+ self.assertIn("document", low)
90
+
91
+ def test_forbidden_lines_present(self):
92
+ role = read_role_md()
93
+ for phrase in ["issue certification approval", "regulatory sign-off",
94
+ "reproduce proprietary", "sign_off_required: true"]:
95
+ self.assertIn(phrase, role, f"missing boundary: {phrase}")
96
+
97
+ def test_sources_register_exists(self):
98
+ p = os.path.join(ROLE_DIR, "SOURCES.md")
99
+ self.assertTrue(os.path.exists(p), "SOURCES.md missing for role")
100
+
101
+ def test_core_engine_exists(self):
102
+ """100% standard: every role ships an executable core + cli."""
103
+ for f in ["core", "cli.py"]:
104
+ self.assertTrue(os.path.exists(os.path.join(ROLE_DIR, f)),
105
+ f"{f} missing - role is not executable")
106
+
107
+
108
+ if __name__ == "__main__":
109
+ unittest.main()