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,72 @@
1
+ # Aerodynamic Design Report
2
+
3
+ **Aircraft:** TAC-150 twin-jet transport (reference configuration)
4
+ **Status:** draft-for-review (generated 2026-09-05)
5
+
6
+ ## 1. Configuration summary
7
+
8
+ - Aircraft: TAC-150 twin-jet transport (reference configuration) - 150-seat short/medium-haul transport, wing-body-tail configuration, underlying podded engines
9
+ - Mission: short/medium-haul transport - cruise M 0.78 at 10668 m; dive M 0.89 (V_D 263.9 m/s TAS); MTOW 735 kN, cruise weight 622 kN
10
+ - Selected airfoil + rationale: representative supercritical section (t/c 0.105), Korn drag-divergence benefit over a conventional section; section cl_max 1.55 from the stage-1 XFOIL-style analysis
11
+ - Wing planform: area 122.6 m2 - AR 8.0 - span 31.3 m - MAC 3.91 m - quarter-chord sweep 25 deg - taper 0.30
12
+ - High-lift system: full-span leading-edge slat + single-slotted trailing-edge flap (deflections in section 4)
13
+
14
+ ## 2. Airfoil analysis
15
+
16
+ - Operating Reynolds range (MAC-based, clean wing): 2.36e+07 (sea-level low-speed) to 2.40e+07 (cruise M 0.78)
17
+ - Section: representative supercritical section; thin-airfoil section slope a0 = 6.283/rad
18
+ - CL_max clean (wing-level): 1.264 (0.9 x section 1.55 x cos(sweep)); with high-lift: 2.273 landing / 1.910 takeoff
19
+ - Drag divergence (Korn rule, supercritical t/c 0.105 at cruise CL 0.500): M_DD = 0.795
20
+ - Source tool + settings: stage-1 XFOIL viscous analysis (transition) on the candidate sections; tool sanity anchor NACA 0012 at Re = 6e6 (cl ~0.82 at 10 deg, cd0 ~0.0079 band, xfoil-analysis leaf) recorded in the analysis evidence set
21
+
22
+ ## 3. Drag buildup
23
+
24
+ | Component | Cf | FF | Q | S_wet (m2) | Cd0 term | Basis |
25
+ |---|---|---|---|---|---|---|
26
+ | wing | 0.00255 | 1.2222 | 1.00 | 218.5 | 0.005562 | Cf x FF x Q x S_wet/S_ref (Re 2.40e+07) |
27
+ | fuselage | 0.00189 | 1.0934 | 1.00 | 401.0 | 0.006764 | Cf x FF x Q x S_wet/S_ref (Re 2.30e+08) |
28
+ | nacelles x2 | 0.00265 | 1.2414 | 1.20 | 29.0 | 0.000935 | Cf x FF x Q x S_wet/S_ref (Re 1.78e+07) |
29
+ | horizontal tail | 0.00270 | 1.2100 | 1.00 | 50.6 | 0.001347 | Cf x FF x Q x S_wet/S_ref (Re 1.56e+07) |
30
+ | vertical tail | 0.00264 | 1.2100 | 1.00 | 39.4 | 0.001028 | Cf x FF x Q x S_wet/S_ref (Re 1.84e+07) |
31
+ - Total Cd0: 0.01564 - Oswald/span efficiency: 0.80 - equivalent skin friction Cf_e = 0.00260 (Cd0 x S_ref / S_wet_total = 738 m2)
32
+ - Full polar: CD = 0.01564 + 0.04974 x CL^2; at cruise CL 0.500: CD = 0.02805, L/D = 17.81; polar peak L/D 17.93 at CL_opt 0.561
33
+
34
+ ## 4. High-lift assessment
35
+
36
+ - Device + deflections: full-span slat (span fraction 0.85) + slotted flap (chord fraction 0.25, span fraction 0.70); takeoff 15 deg, landing 35 deg (max 40 deg for the slotted flap)
37
+ - Section increments: flap +0.366 (TO) / +0.812 (landing), slat +0.425 (K_delta x K_chord x K_span x reference increment, high-lift leaf)
38
+ - CL_max with device: takeoff 1.910, landing 2.273 (0.9 x section cl_max x cos(sweep)) vs clean 1.264
39
+ - Stall speeds (sea level): clean 88.0 m/s at MTOW, takeoff 71.6 m/s at MTOW, landing 60.9 m/s at landing weight; landing reference speed 1.23 x V_S = 74.9 m/s (CS/FAR 25.125 minimum reference-speed practice)
40
+
41
+ ## 5. CFD evidence
42
+
43
+ - Case: ONERA M6 wing validation + 3-mesh grid study on the transport wing-body at cruise M 0.78 / CL 0.500
44
+ - Validation target: ONERA M6 wing at M 0.84, Re 1.17e+07, alpha 3.06 deg (reference CD 0.0163); computed CD 0.0169 -> relative error 3.7% vs 5% band: PASS
45
+ - Mesh convergence: 1.9e+07 / 4.8e+06 / 1.2e+06 cells (refinement ratio 2.0); CD 0.02840 / 0.02910 / 0.03060; apparent order 1.10, Richardson-extrapolated CD 0.02779, GCI 0.00077 (2.7% of the fine-mesh value)
46
+ - Turbulence model + wall treatment: RANS (SA) on the fine mesh, resolved near-wall layer (y+ <= 1); fine-mesh total drag 0.02840 vs component-buildup polar 0.02805 at the same condition (1.2% apart)
47
+
48
+ ## 6. Transonic behavior
49
+
50
+ - Effective section Mach at cruise: M cos(sweep) = M 0.78 x cos(25 deg) = 0.707
51
+ - Drag-divergence Mach (Korn, supercritical): M_DD = 0.95 - t/c (0.105) - CL/10 (0.0500) = 0.7950
52
+ - Wave drag at cruise: 0.0000 penalty index (0 below M_DD; (M - M_DD)^3 above) - cruise holds 0.0150 below drag divergence; shock location: no terminating shock at cruise (no supercritical pocket closure case)
53
+ - Supercritical behavior notes: flat-top section holds the local Mach just-supersonic with a weak terminating shock; transonic similarity parameter K = (1 - M^2)/tau^(2/3) = 1.759
54
+
55
+ ## 7. Aeroelastic screening
56
+
57
+ - Flutter speed estimate: 364.2 m/s (V-g typical-section flutter speed, outboard wing at the dive condition, flutter-speed-prediction leaf analysis) vs V_D 263.9 m/s -> margin 1.38 (PASS >= 1.15)
58
+ - Static divergence: no static-divergence mechanism for the swept-back wing (aerodynamic center aft of the elastic axis, divergence-speed leaf domain e <= 0)
59
+ - Gust response (load factor): discrete-gust screening at cruise, U_de = 12.5 m/s, quasi-steady Delta CL = a x U_de/V -> Delta n = 0.49, n = 1.49 g. NOTE: aeroelastic results are SCREENING inputs for the loads/structures role - not final flutter or gust clearance
60
+
61
+ ## 8. Margin summary
62
+
63
+ | Margin | Value | Requirement | Source (stage) |
64
+ |---|---|---|---|
65
+ | Flutter margin (V_F / V_D) | 1.380 | >= 1.15 x V_D (flutter-speed leaf clearance practice) | stage 10: V-g typical-section flutter speed 364.2 m/s vs design dive speed 263.9 m/s |
66
+ | Drag-divergence margin (M_DD - M_cruise) | 0.015 | > 0 (cruise below drag divergence; wave-drag penalty = 0) | stage 8: Korn rule M_DD = 0.795 at cruise C_L 0.4996 |
67
+ | Stall margin, clean (CL_max clean / C_L cruise) | 2.530 | > 1 (no stall at the cruise point, sea-level MTOW V_s = 88 m/s) | stage 4: wing CLmax = 0.9 x section clmax x cos(sweep) |
68
+ | High-lift CL_max gain (landing - clean) | 1.009 | > 0 (flap + slat increments from high-lift leaf) | stage 4: slotted flap dcl 0.812 + slat dcl 0.425 (section), 3D/sweep factor 0.9 x cos(25 deg) |
69
+ | L/D efficiency margin ((L/D_max - L/D_cruise) / L/D_max) | 0.007 | >= 0 (cruise lift coefficient within the polar peak) | stage 5: polar peak L/D 17.93 at C_L 0.561 vs cruise L/D 17.81 |
70
+
71
+ ---
72
+ *DRAFT - for human aerodynamics lead review. Not an approval document.*
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env python3
2
+ """Test aerodynamics_core: the executable engine of the Aerodynamics role.
3
+
4
+ Proves the role can DO its job standalone (no AeroSkills checkout needed):
5
+ formula correctness against known values (the same anchors used by the
6
+ bound Aero Agent Skills leaves), ISA atmosphere, drag buildup, drag polar,
7
+ lift curve slope, high lift, transonic limits, aeroelastic margins, CFD
8
+ validation metrics, report generation, and evidence-gate checks.
9
+ """
10
+ import math
11
+ import os
12
+ import re
13
+ import sys
14
+ import unittest
15
+
16
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "core"))
17
+ import aerodynamics_core as ac
18
+
19
+
20
+ class TestFormulaKnownValues(unittest.TestCase):
21
+ """Formula anchors from the bound AeroSkills leaf contract tests."""
22
+
23
+ def test_reynolds_and_skin_friction_anchors(self):
24
+ # Re = rho*V*L/mu: sea-level air, V = 70 m/s, length 2.5 m
25
+ # (parasite-drag leaf test).
26
+ self.assertAlmostEqual(ac.reynolds(1.225, 70.0, 2.5, 1.7894e-5),
27
+ 11980272.717, delta=1.0)
28
+ with self.assertRaises(ValueError):
29
+ ac.reynolds(0.0, 70.0, 2.5, 1.7894e-5)
30
+ # Blasius, Schlichting and the mixed transition formula (leaf tests).
31
+ self.assertAlmostEqual(ac.cf_laminar(1e5), 0.0041995047, delta=1e-9)
32
+ self.assertAlmostEqual(ac.cf_turbulent(1e7), 0.0030037131, delta=1e-9)
33
+ self.assertAlmostEqual(ac.cf_mixed(1e7, 5e5), 0.0028423311, delta=1e-9)
34
+ with self.assertRaises(ValueError):
35
+ ac.cf_turbulent(5.0)
36
+
37
+ def test_form_factor_and_component_drag_anchors(self):
38
+ # FF wing = 1 + 2(t/c) + 100(t/c)^4, fuselage/nacelle l/d forms.
39
+ self.assertAlmostEqual(ac.form_factor("wing", t_over_c=0.12), 1.260736)
40
+ self.assertAlmostEqual(ac.form_factor("tail", t_over_c=0.10), 1.21)
41
+ self.assertAlmostEqual(ac.form_factor("fuselage", l_over_d=8.0), 1.1371875)
42
+ self.assertAlmostEqual(ac.form_factor("nacelle", l_over_d=3.0),
43
+ 1.1166666667, delta=1e-9)
44
+ # CD_i = Cf * FF * Q * S_wet / S_ref (leaf test value).
45
+ self.assertAlmostEqual(ac.component_drag(0.003, 1.26, 1.1, 50.0, 20.0),
46
+ 0.010395)
47
+ # assembled buildup: total Cd0 is the sum of the component terms
48
+ buildup = ac.parasite_drag(
49
+ [{"name": "wing", "kind": "wing", "length": 2.5, "s_wet": 218.5,
50
+ "t_over_c": 0.105, "q": 1.0},
51
+ {"name": "fuselage", "kind": "fuselage", "length": 37.6,
52
+ "s_wet": 401.0, "l_over_d": 9.5, "q": 1.0}],
53
+ s_ref=122.6, rho=1.225, v=70.0, mu=1.7894e-5)
54
+ self.assertEqual(len(buildup["components"]), 2)
55
+ self.assertAlmostEqual(buildup["cd0"],
56
+ sum(r["cd"] for r in buildup["components"]))
57
+ self.assertGreater(buildup["cd0"], 0.0)
58
+
59
+ def test_drag_polar_and_lift_slope_formulas(self):
60
+ # k = 1/(pi*e*AR) with e = 0.8, AR = 8; CD = Cd0 + k*CL^2
61
+ e, ar, cd0 = 0.8, 8.0, 0.01564
62
+ k = 1.0 / (math.pi * e * ar)
63
+ self.assertAlmostEqual(ac.induced_drag_factor(e, ar), k)
64
+ cl = 0.5
65
+ polar = ac.drag_polar(cd0, e, ar, cl)
66
+ self.assertAlmostEqual(polar["cd"], cd0 + k * cl * cl)
67
+ # cl_opt = sqrt(cd0/k), L/D_max = 1/(2*sqrt(cd0*k))
68
+ self.assertAlmostEqual(polar["cl_opt"], math.sqrt(cd0 / k))
69
+ self.assertAlmostEqual(polar["ld_max"], 1.0 / (2.0 * math.sqrt(cd0 * k)))
70
+ self.assertAlmostEqual(polar["l_over_d"], cl / (cd0 + k * cl * cl))
71
+ # lifting line with a0 = 2*pi and e = 1 reduces to a = a0*AR/(AR+2)
72
+ slope = ac.lift_curve_slope(8.0, e=1.0, sweep_deg=0.0, mach=0.0)
73
+ self.assertAlmostEqual(slope["a_finite"], 2 * math.pi * 8.0 / 10.0)
74
+ # simple sweep theory: a_swept = a * cos(sweep)
75
+ self.assertAlmostEqual(slope["a_finite"] * math.cos(math.radians(25.0)),
76
+ ac.lift_curve_slope(8.0, e=1.0,
77
+ sweep_deg=25.0)["a_swept"])
78
+ # Prandtl-Glauert: a_mach = a / sqrt(1 - M^2), valid M < 0.7
79
+ base = ac.lift_curve_slope(8.0, e=1.0, sweep_deg=25.0, mach=0.0)
80
+ pg = ac.lift_curve_slope(8.0, e=1.0, sweep_deg=25.0, mach=0.5)
81
+ self.assertAlmostEqual(pg["a_mach"], base["a_swept"] / math.sqrt(0.75))
82
+ with self.assertRaises(ValueError):
83
+ ac.lift_curve_slope(8.0, mach=0.8) # P-G valid only M < 0.7
84
+
85
+ def test_flutter_and_divergence_margins(self):
86
+ # Classic typical-section anchors (flutter-speed leaf tests):
87
+ # V_F = 88.8511 m/s.
88
+ margin, ok = ac.flutter_margin(88.8511, 80.0)
89
+ self.assertAlmostEqual(margin, 1.1106, delta=1e-3)
90
+ self.assertFalse(ok)
91
+ margin, ok = ac.flutter_margin(88.8511, 70.0)
92
+ self.assertAlmostEqual(margin, 1.2693, delta=1e-3)
93
+ self.assertTrue(ok)
94
+ # Divergence: 40000/(16*2*5.0*0.2) = 1250 Pa exactly (divergence leaf)
95
+ q = ac.divergence_dynamic_pressure(40000.0, 16.0, 2.0, 5.0, 0.2)
96
+ self.assertAlmostEqual(q, 1250.0)
97
+ self.assertAlmostEqual(ac.divergence_speed(q), 45.1754, delta=1e-3)
98
+ with self.assertRaises(ValueError):
99
+ ac.divergence_dynamic_pressure(40000.0, 16.0, 2.0, 5.0, 0.0)
100
+
101
+ def test_high_lift_formulas(self):
102
+ # Slotted flap at full deflection: reference increment 1.3 at the
103
+ # reference flap chord fraction and full span.
104
+ self.assertAlmostEqual(ac.flap_clmax_increment("slotted", 40.0), 1.3)
105
+ # partial deflection scales with sin(delta)/sin(delta_max)
106
+ inc_20 = ac.flap_clmax_increment("slotted", 20.0)
107
+ self.assertAlmostEqual(inc_20, 1.3 * math.sin(math.radians(20.0))
108
+ / math.sin(math.radians(40.0)))
109
+ # wing CLmax = 0.9 * clmax_section * cos(sweep)
110
+ self.assertAlmostEqual(ac.wing_clmax(1.55, 25.0),
111
+ 0.9 * 1.55 * math.cos(math.radians(25.0)))
112
+ # stall speed sqrt(2W/(rho*S*CLmax)) - clean config ~88 m/s example
113
+ vs = ac.stall_speed(735000.0, 122.6, 1.225,
114
+ ac.wing_clmax(1.55, 25.0))
115
+ self.assertAlmostEqual(vs, 88.0, delta=1.5)
116
+
117
+ def test_transonic_rules(self):
118
+ # Korn rule: M_DD = 0.95 - t/c - CL/10 (supercritical base)
119
+ self.assertAlmostEqual(ac.drag_divergence_mach(0.105, 0.5, True),
120
+ 0.95 - 0.105 - 0.05)
121
+ # conventional section uses the 0.90 base
122
+ self.assertAlmostEqual(ac.drag_divergence_mach(0.105, 0.5, False),
123
+ 0.90 - 0.105 - 0.05)
124
+ # wave drag penalty: 0 below M_DD, (M - M_DD)^3 above
125
+ self.assertEqual(ac.wave_drag_penalty(0.78, 0.795), 0.0)
126
+ self.assertAlmostEqual(ac.wave_drag_penalty(0.84, 0.795), 0.045 ** 3)
127
+ # effective Mach M*cos(sweep)
128
+ self.assertAlmostEqual(ac.effective_mach(0.78, 25.0),
129
+ 0.78 * math.cos(math.radians(25.0)))
130
+
131
+ def test_cfd_validation_metrics(self):
132
+ # Richardson on the example mesh series [fine, medium, coarse]
133
+ rich = ac.richardson_extrapolation([0.02840, 0.02910, 0.03060], 2.0)
134
+ p = math.log(0.0015 / 0.0007) / math.log(2.0)
135
+ self.assertAlmostEqual(rich["apparent_order"], p)
136
+ denom = 2.0 ** p - 1.0
137
+ self.assertAlmostEqual(rich["extrapolated"], 0.02840 - 0.0007 / denom)
138
+ self.assertAlmostEqual(rich["gci"], 1.25 * 0.0007 / denom)
139
+ self.assertTrue(rich["monotone"])
140
+ # validation verdict PASS inside the 5% band, FAIL outside
141
+ v = ac.validation_verdict(0.0169, 0.0163)
142
+ self.assertEqual(v["verdict"], "PASS")
143
+ self.assertAlmostEqual(v["error"], 0.0006 / 0.0163)
144
+ v2 = ac.validation_verdict(0.0185, 0.0163)
145
+ self.assertEqual(v2["verdict"], "FAIL")
146
+ with self.assertRaises(ValueError):
147
+ ac.richardson_extrapolation([0.03, 0.02, 0.03]) # non-monotone
148
+
149
+
150
+ class TestIsaAtmosphere(unittest.TestCase):
151
+
152
+ def test_isa_sea_level_and_cruise(self):
153
+ sl = ac.atmosphere(0.0)
154
+ self.assertAlmostEqual(sl["density"], 1.225, delta=1e-3)
155
+ self.assertAlmostEqual(sl["pressure"], 101325.0, delta=5.0)
156
+ self.assertAlmostEqual(sl["speed_of_sound"], 340.29, delta=0.2)
157
+ # cruise at 10668 m (FL 350): rho ~0.38, a ~296.5 (used by the report)
158
+ cr = ac.atmosphere(10668.0)
159
+ self.assertAlmostEqual(cr["density"], 0.3796, delta=0.005)
160
+ self.assertAlmostEqual(cr["speed_of_sound"], 296.5, delta=0.5)
161
+ with self.assertRaises(ValueError):
162
+ ac.atmosphere(-5.0)
163
+
164
+
165
+ class TestReportBuilder(unittest.TestCase):
166
+
167
+ def test_example_report_numbers(self):
168
+ model = ac.build_report(ac.example_item())
169
+ # cruise CL ~0.50 at M 0.78/FL350 with W_cruise/S = 622000/122.6
170
+ self.assertAlmostEqual(model["cl_cruise"], 0.5, delta=1e-2)
171
+ self.assertAlmostEqual(model["span"], math.sqrt(8.0 * 122.6), delta=1e-6)
172
+ self.assertAlmostEqual(model["mac"], 122.6 / math.sqrt(8.0 * 122.6),
173
+ delta=1e-6)
174
+ # polar consistency: CD = Cd0 + k*CL^2 with k = 1/(pi*e*AR)
175
+ expected_cd = (model["cd0"]
176
+ + model["cl_cruise"] ** 2
177
+ / (math.pi * model["oswald_e"] * model["aspect_ratio"]))
178
+ self.assertAlmostEqual(model["cd_cruise"], expected_cd, delta=1e-6)
179
+ self.assertGreater(model["ld_max"], model["ld_cruise"])
180
+ # transonic: cruise below Korn M_DD, penalty zero
181
+ self.assertGreater(model["m_dd"], model["cruise_mach"])
182
+ self.assertEqual(model["wave_drag_penalty"], 0.0)
183
+ # high lift: landing CLmax above clean; stall speeds ordered
184
+ hl = model["high_lift"]
185
+ self.assertGreater(hl["clmax_wing_land"], hl["clmax_wing_clean"])
186
+ self.assertLess(hl["vs_land"], hl["vs_to"])
187
+ self.assertLess(hl["vs_to"], hl["vs_clean"])
188
+
189
+ def test_core_gates_all_pass(self):
190
+ model = ac.build_report(ac.example_item())
191
+ gates = ac.check_report(model)
192
+ self.assertTrue(gates["all_pass"], gates)
193
+ self.assertTrue(model["flutter_ok"])
194
+ self.assertGreaterEqual(model["flutter_margin"], 1.15)
195
+ self.assertGreaterEqual(len(model["margins"]), 4)
196
+ # every margin names its workflow-stage source
197
+ for m in model["margins"]:
198
+ self.assertIn("stage ", m["source"])
199
+
200
+ def test_report_markdown_complete_gates_and_no_blanks(self):
201
+ md = ac.example_report_markdown()
202
+ for n in range(1, 9):
203
+ self.assertTrue(re.search(rf"^## {n}\. ", md, re.M),
204
+ "section %d missing" % n)
205
+ for banned in ["___", "TBD", "OPEN item"]:
206
+ self.assertNotIn(banned, md)
207
+ self.assertIn("DRAFT", md)
208
+ self.assertIn("not an approval", md.lower())
209
+ self.assertIn("Flutter margin", md)
210
+ self.assertIn("Drag-divergence Mach", md)
211
+ self.assertGreater(len(md), 3000)
212
+ gates = ac.check_report_markdown(md)
213
+ self.assertTrue(gates["all_pass"], gates)
214
+ self.assertTrue(gates["has_no_blanks"])
215
+
216
+ def test_standalone_no_skills_repo(self):
217
+ # Core must work with no AeroSkills present: env points nowhere.
218
+ os.environ["AEROSKILLS_DEV"] = "/nonexistent"
219
+ model = ac.build_report(ac.example_item())
220
+ md = ac.render_report_markdown(model)
221
+ self.assertTrue(ac.check_report(model)["all_pass"])
222
+ self.assertGreater(len(md), 3000)
223
+ self.assertIn("TAC-150", md)
224
+
225
+
226
+ if __name__ == "__main__":
227
+ unittest.main()
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env python3
2
+ """Role test: Aerodynamics Engineer.
3
+
4
+ Offline verification: bound skills resolve, workflow deterministic,
5
+ report template complete, boundaries present, SOURCES present.
6
+ """
7
+ import os
8
+ import re
9
+ import unittest
10
+
11
+ ROLES_REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(
12
+ os.path.abspath(__file__)))))
13
+ AEROSKILLS = os.environ.get("AEROSKILLS_DEV", os.path.expanduser("~/AeroSkills"))
14
+ HAS_SKILLS = os.path.isdir(os.path.join(AEROSKILLS, "skills"))
15
+ ROLE_DIR = os.path.join(ROLES_REPO, "roles", "aerodynamics-engineer")
16
+ TEMPLATE = os.path.join(ROLE_DIR, "templates", "aero-design-report-template.md")
17
+
18
+ EXPECTED_BOUND = [
19
+ "aerodynamics/airfoil/xfoil-analysis",
20
+ "aerodynamics/airfoil/airfoil-selection",
21
+ "aerodynamics/wing-design/wing-planform-design",
22
+ "aerodynamics/drag-polars/drag-polar",
23
+ "aerodynamics/drag-polars/parasite-drag",
24
+ "aerodynamics/drag-polars/lift-curve-slope",
25
+ "aerodynamics/high-lift/high-lift-systems",
26
+ "aerodynamics/cfd/vortex-lattice-method",
27
+ "aerodynamics/cfd/cfd-validation",
28
+ "aerodynamics/cfd/cfd-convergence",
29
+ "aerodynamics/cfd/cfd-mesh-generation",
30
+ "aerodynamics/cfd/cfd-turbulence-modeling",
31
+ "aerodynamics/high-speed/swept-wing-aerodynamics",
32
+ "aerodynamics/high-speed/transonic-similarity",
33
+ "aerodynamics/high-speed/supercritical-airfoil",
34
+ "aerodynamics/high-speed/wave-drag-area-rule",
35
+ "aerodynamics/high-speed/normal-shock",
36
+ "aerodynamics/boundary-layer/boundary-layer-theory",
37
+ "aerodynamics/boundary-layer/boundary-layer-transition",
38
+ "aerodynamics/aeroelasticity/flutter-speed-prediction",
39
+ "aerodynamics/aeroelasticity/aeroelastic-gust-response",
40
+ "aerodynamics/ground-effects/ground-effect",
41
+ "aerodynamics/wind-tunnel/windtunnel-data-reduction",
42
+ "aerodynamics/wind-tunnel/windtunnel-wall-corrections",
43
+ ]
44
+
45
+ STAGES = ["Airfoil analysis", "Airfoil optimization", "Wing planform",
46
+ "High-lift", "Drag buildup", "Winglet / 3D", "CFD validation",
47
+ "Transonic", "Boundary layer", "Aeroelastic screen",
48
+ "Ground/wind tunnel", "Report"]
49
+
50
+
51
+ def role_text():
52
+ p = os.path.join(ROLE_DIR, "ROLE.md")
53
+ return open(p).read() if os.path.exists(p) else None
54
+
55
+
56
+ class TestAerodynamicsRole(unittest.TestCase):
57
+
58
+ def test_bound_skills_resolve(self):
59
+ if not HAS_SKILLS:
60
+ self.skipTest("skills checkout absent")
61
+ for leaf in EXPECTED_BOUND:
62
+ self.assertTrue(
63
+ os.path.exists(os.path.join(AEROSKILLS, "skills", leaf, "SKILL.md")),
64
+ f"bound skill missing: {leaf}")
65
+
66
+ def test_stages_ordered(self):
67
+ role = role_text()
68
+ self.assertIsNotNone(role)
69
+ # check order within the Workflow section only
70
+ wf = role[role.find("## Workflow"):role.find("## Evidence gates")]
71
+ idx = [wf.find(s) for s in STAGES]
72
+ self.assertTrue(all(i >= 0 for i in idx), "a stage missing in workflow")
73
+ self.assertEqual(idx, sorted(idx), "stage order not deterministic")
74
+
75
+ def test_template_sections(self):
76
+ if not os.path.exists(TEMPLATE):
77
+ self.fail("template missing")
78
+ text = open(TEMPLATE).read()
79
+ for n in range(1, 9):
80
+ self.assertTrue(re.search(rf"^## {n}\. ", text, re.M), f"section {n}")
81
+ self.assertIn("DRAFT", text)
82
+
83
+ def test_boundaries(self):
84
+ role = role_text()
85
+ self.assertIsNotNone(role)
86
+ for phrase in ["claim certification approval", "sign_off_required: true"]:
87
+ self.assertIn(phrase, role)
88
+
89
+ def test_sources(self):
90
+ self.assertTrue(os.path.exists(os.path.join(ROLE_DIR, "SOURCES.md")))
91
+
92
+
93
+ if __name__ == "__main__":
94
+ unittest.main()
@@ -0,0 +1,138 @@
1
+ ---
2
+ type: role
3
+ name: aircraft-design-engineer
4
+ title: "Aircraft Conceptual Design Engineer"
5
+ status: draft
6
+ domain: vehicle-design
7
+ deliverable_type: "concept design package (sizing + layout + cost)"
8
+ standards_bound:
9
+ - id: far-25
10
+ tier: TIER-1
11
+ reference-only: false
12
+ skills_bound:
13
+ - vehicle-design/conceptual/constraint-analysis
14
+ - vehicle-design/conceptual/sizing-mission-profile
15
+ - vehicle-design/conceptual/payload-range-diagram
16
+ - vehicle-design/conceptual/tow-estimation
17
+ - vehicle-design/conceptual/openvsp-geometry
18
+ - vehicle-design/sizing/ws-tw-trade
19
+ - vehicle-design/sizing/weight-estimation
20
+ - vehicle-design/sizing/engine-sizing
21
+ - vehicle-design/sizing/fuselage-sizing
22
+ - vehicle-design/sizing/wing-planform-sizing
23
+ - vehicle-design/sizing/tail-sizing
24
+ - vehicle-design/sizing/landing-gear-sizing
25
+ - vehicle-design/sizing/control-surface-sizing
26
+ - vehicle-design/sizing/fuel-tank-sizing
27
+ - vehicle-design/sizing/battery-sizing
28
+ - vehicle-design/sizing/environmental-control-sizing
29
+ - vehicle-design/sizing/electrical-wire-sizing
30
+ - vehicle-design/sizing/apu-fuel-burn-sizing
31
+ - vehicle-design/sizing/bleed-air-system-sizing
32
+ - vehicle-design/sizing/fire-protection-sizing
33
+ - vehicle-design/sizing/ice-protection-sizing
34
+ - vehicle-design/sizing/hydraulic-system-sizing
35
+ - vehicle-design/sizing/landing-gear-retraction-sizing
36
+ - vehicle-design/mass-properties/mass-budget
37
+ - vehicle-design/mass-properties/cg-envelope
38
+ - vehicle-design/mass-properties/inertia-estimation
39
+ - vehicle-design/mdo/design-of-experiments
40
+ - vehicle-design/mdo/multidisciplinary-optimization
41
+ - vehicle-design/mdo/surrogate-modeling
42
+ - vehicle-design/cost-estimation/parametric-cost
43
+ - vehicle-design/cost-estimation/operating-cost
44
+ - vehicle-design/cost-estimation/life-cycle-cost
45
+ - vehicle-design/structures-integration/wing-box-sizing
46
+ - vehicle-design/structures-integration/fuselage-skin-stringer
47
+ tools_allowed: [stdlib, offline-file-processing, openvsp-cli]
48
+ forbidden:
49
+ - "claim certification approval"
50
+ - "release a configuration for production"
51
+ - "reproduce proprietary standard text"
52
+ sign_off_required: true
53
+ license: Apache-2.0
54
+ compatibility: "agentskills.io ROLE.md; any SKILL.md host"
55
+ metadata:
56
+ version: 0.1.0
57
+ author: Aero Agent Roles
58
+ skills_release: "v1.3.0+"
59
+ ---
60
+
61
+ # Aircraft Conceptual Design Engineer
62
+
63
+ ## Role identity
64
+
65
+ Owns the conceptual design phase: turn a top-level requirement (payload,
66
+ range, speed, field length) into a sized, balanced, costed aircraft
67
+ configuration. Runs the sizing loop, the W/S vs T/W trade, mass and CG
68
+ buildup, subsystem sizing, and the MDO exploration that closes the
69
+ design. Use when a project must produce a defensible concept with a
70
+ takeoff weight, a wing/engine selection, and a cost estimate. Do NOT use
71
+ for detailed structural analysis (structures role), aerodynamic
72
+ refinement (aero role), or certification workflow (cert roles).
73
+
74
+ ## Deliverable contract
75
+
76
+ 1. **Concept design package** - requirements, constraint diagram
77
+ (W/S vs T/W), sizing mission, selected configuration, mass statement,
78
+ CG envelope, subsystem summary, cost estimate.
79
+ 2. **Sensitivity/MDO evidence** - the trade studies and optimization
80
+ runs that justify the selection.
81
+
82
+ ## Workflow (stages -> bound skills)
83
+
84
+ | Stage | Loads skill | Produces |
85
+ |---|---|---|
86
+ | 1. Requirements framing | constraint-analysis | constraint diagram, feasible design space |
87
+ | 2. Sizing mission | sizing-mission-profile | mission segments, reserves, fuel fractions |
88
+ | 3. Initial layout | openvsp-geometry | 3-view baseline geometry |
89
+ | 4. W/S vs T/W trade | ws-tw-trade | design point selection |
90
+ | 5. Weight iteration | weight-estimation + tow-estimation | MTOW convergence |
91
+ | 6. Component sizing | engine-sizing + fuselage-sizing + wing-planform-sizing + tail-sizing + landing-gear-sizing + control-surface-sizing | component dimensions/weights |
92
+ | 7. Subsystem sizing | fuel-tank-sizing + battery-sizing + environmental-control-sizing + electrical-wire-sizing + apu-fuel-burn-sizing + bleed-air-system-sizing + fire-protection-sizing + ice-protection-sizing + hydraulic-system-sizing + landing-gear-retraction-sizing | subsystem sizes/power/weight |
93
+ | 8. Mass + CG | mass-budget + cg-envelope + inertia-estimation | mass statement, CG travel, inertias |
94
+ | 9. MDO exploration | design-of-experiments + multidisciplinary-optimization + surrogate-modeling | trade space, chosen optimum |
95
+ | 10. Payload-range | payload-range-diagram | payload-range curve |
96
+ | 11. Cost | parametric-cost + operating-cost + life-cycle-cost | DOC/LCC estimates |
97
+ | 12. Structures check | wing-box-sizing + fuselage-skin-stringer | structural feasibility input |
98
+ | 13. Package | (all above) | the concept design package |
99
+
100
+ ## Evidence gates
101
+
102
+ - Stage 5 done = MTOW converged (two iterations within tolerance).
103
+ - Stage 8 done = mass statement sums to MTOW; CG within limits at
104
+ critical loading conditions.
105
+ - Stage 9 done = the chosen point is a real optimum in the trade data,
106
+ not an arbitrary pick.
107
+ - FINAL = every configuration choice traces to a trade study result.
108
+
109
+ ## Boundary / forbidden
110
+
111
+ - NEVER release a configuration for production or claim certification
112
+ approval.
113
+ - Conceptual results are FEASIBILITY, not detailed design.
114
+ - Cost estimates are parametric-class (accuracy band stated), not quotes.
115
+
116
+ ## Verification
117
+
118
+ - Engine suite `tests/test_aircraft_design_core.py` (stdlib unittest,
119
+ offline, standalone): constraint T/W formulas match the bound
120
+ constraint-analysis/ws-tw-trade leaves; segment fuel fractions match
121
+ the sizing-mission-profile models (Breguet cruise + endurance holds,
122
+ weight chaining); class-I empty-weight fraction fit sits inside the
123
+ transport band; the MTOW loop genuinely iterates and converges within
124
+ 0.5%; the concept package model is complete and its mass statement
125
+ balances; core + markdown evidence gates all pass with zero blanks.
126
+ - Run: `python3 -m unittest tests.test_aircraft_design_core -v`
127
+ - CLI contract: `python3 cli.py build --out package.md` (exit 0, gates
128
+ all_pass) and `python3 cli.py check --file package.md` (prints PASS).
129
+ - Standalone proof: `AEROSKILLS_DEV=/nonexistent python3 cli.py build`
130
+ produces a converged concept package - no AeroSkills checkout needed.
131
+ - tests/test_role_aircraft_design_engineer.py (offline): bound skills
132
+ resolve; workflow deterministic; package template complete (filled
133
+ generated deliverable, zero blanks); boundaries present.
134
+
135
+ ## Compliance
136
+
137
+ - far-25 TIER-1 context. Data references summary-not-copy.
138
+ - SOURCES.md records standards referenced.
@@ -0,0 +1,12 @@
1
+ # SOURCES.md - Aircraft Conceptual Design Engineer
2
+
3
+ | Source | Role use | Gated |
4
+ |---|---|---|
5
+ | 14 CFR Part 25 | certification context for sizing constraints | false |
6
+ | Raymer, Aircraft Design: A Conceptual Approach | sizing methodology reference (book) | true |
7
+ | Torenbeek, Synthesis of Subsonic Airplane Design | synthesis methods reference (book) | true |
8
+ | Roskam, Airplane Design series | component sizing reference (book) | true |
9
+ | NASA OpenVSP docs | geometry tooling docs | false |
10
+
11
+ Summary-not-copy per STANDARDS.md. Methodology is encoded as original
12
+ workflow; book content is referenced, never reproduced.