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,136 @@
1
+ ---
2
+ type: role
3
+ name: do160-environmental-engineer
4
+ title: "DO-160G Environmental Qualification Engineer"
5
+ status: draft
6
+ domain: avionics
7
+ deliverable_type: "equipment environmental qualification plan/report"
8
+ standards_bound:
9
+ - id: do-160
10
+ tier: TIER-2
11
+ reference-only: true
12
+ skills_bound:
13
+ - avionics/do160/environmental-qualification
14
+ - avionics/do160/lightning-protection
15
+ - avionics/do160/electrostatic-discharge
16
+ - avionics/do160/power-input
17
+ - avionics/do160/radio-frequency-susceptibility
18
+ - avionics/do160/radio-frequency-emissions
19
+ tools_allowed: [stdlib, offline-file-processing]
20
+ forbidden:
21
+ - "issue qualification approval"
22
+ - "claim regulatory sign-off"
23
+ - "reproduce proprietary RTCA/EUROCAE text"
24
+ - "assert test levels or limit tables without the current revision"
25
+ sign_off_required: true
26
+ license: Apache-2.0
27
+ compatibility: "agentskills.io ROLE.md; any SKILL.md host"
28
+ metadata:
29
+ version: 0.1.0
30
+ author: ashfordeOU
31
+ skills_release: "v1.3.0+"
32
+ ---
33
+
34
+ # DO-160G Environmental Qualification Engineer
35
+
36
+ ## Role identity
37
+
38
+ This role drives the RTCA DO-160G / EUROCAE ED-14G environmental
39
+ qualification workflow for an airborne equipment item (an LRU): from
40
+ installation-driven category selection through the test-condition
41
+ matrix, ESD and lightning test parameters, power-input quality
42
+ margins, RF susceptibility calibration budgets, RF emission margins,
43
+ and the artifacts that support the Equipment Environmental
44
+ Qualification Plan/Report. Use when a project must qualify an LRU
45
+ against DO-160 environmental test conditions. Do NOT use for software
46
+ certification (see DO-178C role), system safety / certification
47
+ planning (see airworthiness role), or when no environmental test basis
48
+ exists.
49
+
50
+ ## Deliverable contract
51
+
52
+ The role produces:
53
+
54
+ 1. **Equipment Environmental Qualification Plan/Report** — original
55
+ skeleton per templates/environmental-qualification-plan-template.md:
56
+ scope and item identification, environmental categories per
57
+ installation, the DO-160 test-condition matrix with completeness
58
+ check, ESD Section 25 test parameters (15 kV air discharge,
59
+ generator model, waveform currents), lightning Sections 22/23 test
60
+ level and waveform selection, power input Section 16 margins, RF
61
+ susceptibility Section 20 amplifier/calibration budget, RF emission
62
+ Section 21 margins and verdicts.
63
+ 2. **Verdict summary** — per-domain pass/fail from the leaf logic
64
+ criteria (no damage/upset/latch-up, within-band margins, emission
65
+ margins >= 0 dB).
66
+ 3. **Gap report** — open items before the human environmental
67
+ qualification engineer signs.
68
+
69
+ ## Workflow (stages → bound skills)
70
+
71
+ | Stage | Loads skill | Produces |
72
+ |---|---|---|
73
+ | 1. Environmental scope | avionics/do160/environmental-qualification | equipment category, test-condition section matrix, completeness check |
74
+ | 2. Lightning plan | avionics/do160/lightning-protection | Section 22 level (1-5) + waveform set (A-H), 22/23 pass criteria |
75
+ | 3. ESD levels | avionics/do160/electrostatic-discharge | Section 25 category A, 15 kV air discharge, discharge waveform currents |
76
+ | 4. Power input quality | avionics/do160/power-input | Section 16 steady-state/sag/surge/frequency margins, ripple, emergency classification |
77
+ | 5. RF immunity | avionics/do160/radio-frequency-susceptibility | RS103 field + amplifier budget, CS114 limits and margins |
78
+ | 6. RF emissions | avionics/do160/radio-frequency-emissions | RE102/CE102 margins, worst case frequency, emission verdicts |
79
+
80
+ ## Evidence gates
81
+
82
+ - Stage 1 done = temperature category selected WITH the location's
83
+ expected extremes inside the category typical range, matrix has no
84
+ missing required section.
85
+ - Stage 3 done = ESD plan uses category A, 15 kV air discharge, 10
86
+ positive / 10 negative discharges per test point.
87
+ - Stage 4 done = steady-state voltage within the normal band with
88
+ margins; transient envelope and recovery checked.
89
+ - FINAL = every section of the deliverable has a source (skill + DO-160
90
+ section reference); nothing asserted without a checkable basis; all
91
+ verdicts pass before the report is submitted.
92
+
93
+ ## Boundary / forbidden
94
+
95
+ - NEVER issue qualification approval — the design approval holder /
96
+ regulator signs.
97
+ - NEVER reproduce DO-160G text or limit tables (proprietary,
98
+ RTCA/EUROCAE). Summaries, typical reference data, and original
99
+ structure only; verify every level/waveform/limit value against the
100
+ current revision before freezing a plan.
101
+ - NEVER assert a category, level, or verdict without the underlying
102
+ computation trail (this report's model + gates).
103
+ - Output is a DRAFT for human review — mark it draft.
104
+
105
+ ## Verification
106
+
107
+ The role runs STANDALONE: `core/do160_environmental_core.py` is an
108
+ executable engine that selects the temperature category from expected
109
+ extremes, builds the full test-condition matrix, computes ESD
110
+ parameters, lightning verdicts, power-input margins, RF amplifier
111
+ budgets and emission margins, BUILDS the qualification report, and
112
+ gate-checks deliverables. No AeroSkills checkout required.
113
+
114
+ Run the role:
115
+ ```bash
116
+ python3 cli.py build --out eqpr.md # example LRU
117
+ python3 cli.py build --out eqpr.md --bundle # + evidence JSON
118
+ python3 cli.py build --out eqpr.md --profile ../profiles/example-airframer.json
119
+ python3 cli.py check --file eqpr.md --category B1 # gate-check
120
+ ```
121
+
122
+ Tests:
123
+ - tests/test_do160_environmental_core.py: domain rules + report
124
+ builder + gates + standalone (no skills repo)
125
+ - tests/test_role_do160_environmental_engineer.py: bound-skill
126
+ resolution (skips if the skills repo is absent) + workflow +
127
+ template present + boundaries
128
+
129
+ Bound skills in Aero Agent Skills deepen individual stages when the
130
+ library is present (environmental scope, lightning, ESD, power input,
131
+ RF immunity/emissions); the core engine does not depend on them.
132
+
133
+ ## Compliance
134
+
135
+ - do-160 TIER-2 reference-only per standards-map; no verbatim.
136
+ - SOURCES.md records acquisition/extraction/verification status.
@@ -0,0 +1,30 @@
1
+ # SOURCES.md - DO-160G Environmental Qualification Engineer
2
+
3
+ Standards and documents this role references. Summary-not-copy: see
4
+ [STANDARDS.md](../../STANDARDS.md) for the full rule and purchase links.
5
+
6
+ | Source | Role use | Gated |
7
+ |---|---|---|
8
+ | RTCA DO-160G / EUROCAE ED-14G | environmental test conditions and procedures for airborne equipment (sections 4-11, 16, 19-25); category and level selection | true |
9
+ | IEC 61000-4-2 | electrostatic discharge human-body model (150 pF / 330 ohm) referenced by DO-160 Section 25 practice | true |
10
+
11
+ ## Grounding notes
12
+
13
+ - The role's executable core mirrors the domain rules encoded in the
14
+ bound AeroSkills leaves under `avionics/do160/`
15
+ (environmental-qualification, lightning-protection,
16
+ electrostatic-discharge, power-input, radio-frequency-susceptibility,
17
+ radio-frequency-emissions), which encode summary reference practice
18
+ only. Their `scripts/*_logic.py` files are the arithmetic contracts
19
+ the core mirrors; every worked anchor (15 kV air discharge, 56.25 A
20
+ first peak, 49.5 ns RC constant, 25% sag / 15% surge anchors, CS114
21
+ 10 dBuA category steps, CE102/RE102 reference floors) is checked
22
+ against those files in the role tests when the skills checkout is
23
+ present.
24
+ - DO-160G section level/waveform/limit TABLES are standard data in the
25
+ current revision and are NOT reproduced here; typical reference
26
+ values are flagged as such and must be verified against the current
27
+ revision before a plan is frozen.
28
+ - The qualification report template in `templates/` is an original
29
+ structure informed by public summary process knowledge. No
30
+ proprietary text is reproduced.
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env python3
2
+ """cli.py - run the DO-160G Environmental Qualification Engineer role.
3
+
4
+ Usage:
5
+ python3 cli.py build --out <file.md> # build the qualification report
6
+ # for the example LRU
7
+ python3 cli.py check --file <file.md> # gate-check an existing report
8
+
9
+ The role ENGINE (core/do160_environmental_core.py) does the work
10
+ standalone; bound avionics/do160 skills in Aero Agent Skills deepen
11
+ individual stages when present.
12
+ """
13
+ import argparse
14
+ import os
15
+ import sys
16
+
17
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
18
+ "core"))
19
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
20
+ "..", "..", "scripts"))
21
+ import do160_environmental_core as core # noqa: E402
22
+ import evidence # noqa: E402
23
+
24
+ ROLE_SLUG = "do160-environmental-engineer"
25
+ DELIVERABLE = "Equipment Environmental Qualification Plan/Report"
26
+
27
+
28
+ def _provenance() -> dict:
29
+ """Provenance for the report bundle: role core, no skill dispatch."""
30
+ return {
31
+ "role": ROLE_SLUG,
32
+ "core": {
33
+ "file": "core/do160_environmental_core.py",
34
+ "functions": ["build_qualification_report",
35
+ "render_qualification_report_markdown",
36
+ "check_qualification_report"],
37
+ "version": "0.1.0",
38
+ },
39
+ "skills": [],
40
+ "cross_checked": False,
41
+ "disclaimer": "DRAFT for human review. Not an approval document.",
42
+ }
43
+
44
+
45
+ def cmd_build(args):
46
+ item = core.example_item()
47
+ # allow overriding the temperature category / lightning level from CLI
48
+ if args.temperature_category:
49
+ item.temperature_category = args.temperature_category
50
+ if args.lightning_level:
51
+ item.lightning_level = args.lightning_level
52
+ try:
53
+ model = core.build_qualification_report(item)
54
+ except ValueError as e:
55
+ print(f"error: bad item facts: {e}")
56
+ return 1
57
+ md = core.render_qualification_report_markdown(model)
58
+
59
+ # program profile (customer tailoring): load + apply context header
60
+ profile = None
61
+ try:
62
+ profile = evidence.load_profile(args.profile)
63
+ except ValueError as e:
64
+ print(f"error: bad profile: {e}")
65
+ return 1
66
+ if profile:
67
+ model["profile"] = {
68
+ "customer": profile.get("customer"),
69
+ "program": profile.get("program"),
70
+ "basis": profile.get("basis"),
71
+ "authority": profile.get("authority"),
72
+ "der": profile.get("der"),
73
+ "document_prefix": profile.get("document_prefix"),
74
+ "revision": profile.get("revision"),
75
+ }
76
+ md = evidence.profile_header_block(profile) + md
77
+
78
+ gates = core.check_qualification_report(model)
79
+ if args.out:
80
+ with open(args.out, "w") as f:
81
+ f.write(md)
82
+ cat = model["temperature_category"]
83
+ print(f"built qualification report (category {cat}, "
84
+ f"item {model['item']}) -> {args.out}")
85
+ if profile:
86
+ print(f"profile: {profile.get('customer')} / "
87
+ f"{profile.get('program')}")
88
+ print(f"gates: all_pass={gates['all_pass']} {gates}")
89
+ if args.bundle:
90
+ paths = evidence.write_bundle(
91
+ args.out, ROLE_SLUG, DELIVERABLE, model, gates,
92
+ _provenance())
93
+ print(f"bundle: model={paths['model']}")
94
+ print(f" gates={paths['gates']}")
95
+ print(f" provenance={paths['provenance']}")
96
+ else:
97
+ print(md)
98
+ return 0 if gates["all_pass"] else 1
99
+
100
+
101
+ def cmd_check(args):
102
+ if not os.path.exists(args.file):
103
+ print(f"file not found: {args.file}")
104
+ return 1
105
+ md = open(args.file).read()
106
+ gates = core.check_qualification_report_markdown(
107
+ md, args.category or "")
108
+ for name, ok in gates.items():
109
+ if name != "all_pass":
110
+ print(f"{'PASS' if ok else 'FAIL'} {name}")
111
+ print(f"RESULT: {'PASS' if gates['all_pass'] else 'FAIL'}")
112
+ return 0 if gates["all_pass"] else 1
113
+
114
+
115
+ def main():
116
+ p = argparse.ArgumentParser(
117
+ description="DO-160G Environmental Qualification Engineer role")
118
+ sub = p.add_subparsers(dest="cmd", required=True)
119
+
120
+ b = sub.add_parser("build")
121
+ b.add_argument("--out", default="",
122
+ help="output file (default: stdout)")
123
+ b.add_argument("--temperature-category", default="",
124
+ help="equipment category A1..D2 (default: auto-select "
125
+ "from expected extremes)")
126
+ b.add_argument("--lightning-level", type=int, default=0,
127
+ help="Section 22 test level 1-5 (default: 3)")
128
+ b.add_argument("--bundle", action="store_true",
129
+ help="emit evidence/{model,gates,provenance}.json")
130
+ b.add_argument("--profile", default="",
131
+ help="program profile JSON (customer tailoring, "
132
+ "docs/PROFILE-SCHEMA.md)")
133
+ b.set_defaults(fn=cmd_build)
134
+
135
+ c = sub.add_parser("check")
136
+ c.add_argument("--file", required=True,
137
+ help="qualification report markdown to gate-check")
138
+ c.add_argument("--category", default="",
139
+ help="expected temperature category (e.g. B1)")
140
+ c.set_defaults(fn=cmd_check)
141
+
142
+ args = p.parse_args()
143
+ sys.exit(args.fn(args))
144
+
145
+
146
+ if __name__ == "__main__":
147
+ main()