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,165 @@
1
+ ---
2
+ type: role
3
+ name: flight-test-performance-engineer
4
+ title: "Flight Test Performance Engineer"
5
+ status: draft
6
+ domain: flight-test-operations
7
+ deliverable_type: "flight test performance data analysis report"
8
+ standards_bound:
9
+ - id: far-25
10
+ tier: TIER-1
11
+ reference-only: false
12
+ - id: cs-25
13
+ tier: TIER-1
14
+ reference-only: false
15
+ skills_bound:
16
+ - flight-test-operations/performance/takeoff-distance-determination
17
+ - flight-test-operations/performance/accelerate-stop-distance
18
+ - flight-test-operations/performance/engine-failure-takeoff-flight-test
19
+ - flight-test-operations/performance/landing-distance-determination
20
+ - flight-test-operations/performance/level-acceleration-test
21
+ - flight-test-operations/performance/cruise-performance-flight-test
22
+ - flight-test-operations/performance/climb-performance-flight-test
23
+ - flight-test-operations/performance/engine-flight-test
24
+ - flight-test-operations/performance/stall-speed-determination
25
+ - flight-test-operations/performance/glide-flight-test
26
+ - flight-test-operations/performance/fuel-jettison-flight-test
27
+ - flight-test-operations/performance/in-flight-engine-relight-test
28
+ - flight-test-operations/performance/rotorcraft-performance-flight-test
29
+ - flight-test-operations/performance/rotorcraft-forward-flight-performance-test
30
+ - flight-test-operations/planning/flight-test-data-reduction
31
+ tools_allowed: [stdlib, offline-file-processing]
32
+ forbidden:
33
+ - "clear an envelope"
34
+ - "declare airworthiness"
35
+ - "authorize flight"
36
+ - "issue a performance guarantee"
37
+ - "reproduce proprietary standard text"
38
+ sign_off_required: true
39
+ license: Apache-2.0
40
+ compatibility: "agentskills.io ROLE.md; any SKILL.md host"
41
+ metadata:
42
+ version: 0.1.0
43
+ author: ashfordeOU
44
+ skills_release: "v1.3.0+"
45
+ ---
46
+
47
+ # Flight Test Performance Engineer
48
+
49
+ ## Role identity
50
+
51
+ Reduces and analyzes flight-test PERFORMANCE data: recorded takeoff,
52
+ landing, level-acceleration, cruise fuel-flow, climb, and stall-speed
53
+ runs are corrected to standard conditions and reference weight, reduced
54
+ to the discipline quantities (takeoff/landing distance legs, determined
55
+ thrust, range-performance curve, corrected speeds), and compared with
56
+ the predicted values as computed-vs-predicted scatter. Use when a sortie
57
+ data set (or a worked-example stand-in) must become a performance data
58
+ analysis report with every number traceable to a measured value and a
59
+ documented reduction method. Do NOT use for envelope expansion/flutter
60
+ (the Flight Test Engineer role), design-level performance analysis (the
61
+ Flight Mechanics Engineer role), or cert-authority sign-off.
62
+
63
+ ## Deliverable contract
64
+
65
+ The role produces:
66
+
67
+ 1. **Flight Test Performance Data Analysis Report** — per templates/
68
+ performance-report-template.md: test conditions and data quality,
69
+ takeoff performance (ground roll, rotation, 35-ft climb, engine-out
70
+ and accelerate-stop checks), landing performance (demonstrated +
71
+ 1.67 certified field length vs runway), level-acceleration thrust
72
+ determination (total energy method, reduced to reference conditions),
73
+ cruise fuel-flow reduction (range-performance curve, MRC/LRC Mach),
74
+ stall speeds and V-speed corrections, and the computed-vs-predicted
75
+ scatter table.
76
+ 2. **Evidence bundle** — model.json (every number as data), gates.json
77
+ (gate verdicts), provenance.json (each number's source + skill
78
+ cross-checks) per docs/PROTOCOL.md.
79
+ 3. **Findings** — agreement/out-of-band flags per discipline; never a
80
+ clearance or a guarantee.
81
+
82
+ ## Workflow (stages → bound skills)
83
+
84
+ | Stage | Loads skill | Produces |
85
+ |---|---|---|
86
+ | 1. Data reduction prep | flight-test-data-reduction | calibrated/smoothed traces, quality verdict, combined uncertainty |
87
+ | 2. Conditions | (ISA physics, climb leaf method) | test-day sigma, density altitude, ISA deviation |
88
+ | 3. Takeoff | takeoff-distance-determination + engine-failure-takeoff-flight-test + accelerate-stop-distance | ground roll / rotation / 35-ft climb legs, OEI takeoff, accelerate-stop |
89
+ | 4. Landing | landing-distance-determination | demonstrated + certified landing distance, runway verdict |
90
+ | 5. Level accel | level-acceleration-test + engine-flight-test | P_s, excess thrust, determined thrust, reference-condition corrections |
91
+ | 6. Cruise | cruise-performance-flight-test | weight-corrected fuel flows, range-performance curve, MRC/LRC |
92
+ | 7. Speeds | stall-speed-determination (+ v-speeds context) | weight-corrected stall speeds, margins |
93
+ | 8. Climb / other | climb-performance-flight-test + glide-flight-test + fuel-jettison-flight-test + in-flight-engine-relight-test + engine-flight-test | supporting performance checks (worked example: climb-rate model) |
94
+ | 9. Rotorcraft (if rotary) | rotorcraft-performance-flight-test + rotorcraft-forward-flight-performance-test | hover/forward-flight power reduction |
95
+ | 10. Report | (all above) | the data analysis report + bundle |
96
+
97
+ ## Evidence gates
98
+
99
+ - Stage 1 done = every trace used carries an ok quality verdict (no
100
+ NaN, no oversize time gaps).
101
+ - Stage 3 done = takeoff legs complete with the measured and predicted
102
+ ground roll both recorded.
103
+ - Stage 4 done = landing demonstrated distance present AND certified
104
+ (1.67) field length computed against the available runway.
105
+ - Stage 5 done = thrust available determined (drag-polar closure) and
106
+ the sustained-acceleration band verdict recorded.
107
+ - Stage 6 done = cruise range-performance fit found its maximum.
108
+ - Stage 7 done = stall speeds weight-corrected to the run weights.
109
+ - FINAL = the scatter table records every computed-vs-predicted delta
110
+ with its band verdict; nothing asserted without a measured value and
111
+ a source (skill leaf + summary method).
112
+
113
+ ## Boundary / forbidden
114
+
115
+ - NEVER clear an envelope, declare airworthiness, authorize flight, or
116
+ issue a performance guarantee — the report is evidence for the human
117
+ flight test / performance lead and the authority.
118
+ - Reports state what the data reduce to and whether the model agrees,
119
+ never "certified performance achieved". Every deliverable carries the
120
+ explicit "not an approval document and not a performance guarantee"
121
+ marker.
122
+ - Results are sortie-specific; never generalize beyond the tested
123
+ configuration, weight, and conditions.
124
+ - Standards (FAR/CS-25) are summarized context only — never reproduced.
125
+
126
+ ## Verification
127
+
128
+ The role runs STANDALONE: `core/flight_test_performance_core.py` is an
129
+ executable engine that computes the test-day density altitude and
130
+ density ratio, the takeoff legs (trapezoid ground roll, rotation,
131
+ 35-ft climb), the OEI takeoff and accelerate-stop distances, the
132
+ demonstrated/certified landing distances, the level-acceleration
133
+ determined thrust (P_s = V*a/g total-energy method, weight and density
134
+ corrections), the weight-corrected cruise fuel flows with the
135
+ quadratic range-performance fit (MRC/LRC Mach), the weight-corrected
136
+ stall speeds, and the computed-vs-predicted scatter table; BUILDS the
137
+ Flight Test Performance Data Analysis Report; and gate-checks the
138
+ deliverable. No AeroSkills checkout required.
139
+
140
+ Run the role:
141
+ ```bash
142
+ python3 cli.py build --out report.md # worked-example sortie
143
+ python3 cli.py build --out report.md --bundle # + evidence bundle
144
+ python3 cli.py build --out report.md --profile ../../profiles/example-airframer.json
145
+ python3 cli.py check --file report.md # gate-check a report
146
+ ```
147
+
148
+ Tests:
149
+ - tests/test_flight_test_performance_engineer_core.py: domain rules +
150
+ reductions + builder + gates + standalone (no skills repo)
151
+ - tests/test_role_flight_test_performance_engineer.py: bound-skill
152
+ resolution (skips if the skills repo is absent) + workflow + template
153
+ filled + executable core + boundaries
154
+
155
+ Bound AeroSkills performance leaves cross-check the core's numbers when
156
+ the library is present (the CLI dispatches up to 10 reduction points and
157
+ records core_value/skill_value/delta/agrees in provenance.json); the
158
+ core engine does not depend on them.
159
+
160
+ ## Compliance
161
+
162
+ - far-25 + cs-25 context; summary-not-copy per STANDARDS.md. Methods
163
+ grounded in the bound performance leaves; conservative defaults cited
164
+ in SOURCES.md.
165
+ - SOURCES.md records the standards referenced and their gated status.
@@ -0,0 +1,20 @@
1
+ # SOURCES.md - Flight Test Performance 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
+ | FAR Part 25 (Subpart B) | takeoff/landing distance definitions context (35 ft obstacle, 1.67 field length factor practice), V-speed context | false |
9
+ | CS-25 (EASA) | EASA counterpart of the Part 25 performance context | false |
10
+ | ICAO Standard Atmosphere (Doc 7488) | ISA temperature/pressure/density model used for all reductions to standard conditions | false |
11
+ | AeroSkills flight-test-operations/performance leaves | the concrete reduction methods (trapezoid ground roll, Vref = 1.23 x Vs0, total-energy P_s, sqrt(w_ref/w_test) fuel-flow correction, sqrt(w/w_ref) speed correction, sigma^0.7 thrust lapse) | true |
12
+
13
+ Domain-logic rule: every number the core produces comes from a REAL
14
+ method in the bound AeroSkills leaves or from quotable public physics
15
+ (ISA atmosphere, FAR/CS-25 summary context). Conservative defaults
16
+ (dry-runway braking friction mu = 0.42, thrust lapse exponent 0.7,
17
+ scatter band +-10%) are documented in the core module docstrings and in
18
+ this table. The worked-example sortie data in the report template are
19
+ SIMULATED (marked as such in the deliverable) and must be replaced by
20
+ recorded flight data before the report leaves draft.
@@ -0,0 +1,319 @@
1
+ #!/usr/bin/env python3
2
+ """cli.py - run the Flight Test Performance Engineer role.
3
+
4
+ Usage:
5
+ python3 cli.py build [--out <file.md>] [--bundle] [--profile <file.json>]
6
+ # build the Flight Test Performance Data Analysis Report for the
7
+ # worked-example sortie data set
8
+ # --bundle also emit evidence/{model,gates,provenance}.json (PROTOCOL.md)
9
+ # --profile program profile JSON for customer tailoring
10
+ # (docs/PROFILE-SCHEMA.md) -> prepended context header
11
+ python3 cli.py check --file <file.md> # gate-check an existing report
12
+
13
+ The role ENGINE (core/flight_test_performance_core.py) does the work
14
+ standalone (real domain rules -> real numbers); bound Aero Agent Skills
15
+ performance leaves cross-check the core's reductions when the checkout is
16
+ present (provenance records core_value/skill_value/delta/agrees per point).
17
+ """
18
+ import argparse
19
+ import importlib.util
20
+ import os
21
+ import sys
22
+
23
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
24
+ "core"))
25
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
26
+ "..", "..", "scripts"))
27
+ import flight_test_performance_core as core # noqa: E402
28
+ import evidence # noqa: E402
29
+
30
+ ROLE_SLUG = "flight-test-performance-engineer"
31
+ SKILLS_RELEASE = "v1.3.0+"
32
+
33
+
34
+ def _leaf_module(rel_leaf):
35
+ """Import the bound AeroSkills leaf's *_logic.py module, or None."""
36
+ root = os.environ.get("AEROSKILLS_DEV", os.path.expanduser("~/AeroSkills"))
37
+ logic_dir = os.path.join(root, "skills", rel_leaf, "scripts")
38
+ if not os.path.isdir(logic_dir):
39
+ return None
40
+ logic_files = sorted(f for f in os.listdir(logic_dir)
41
+ if f.endswith("_logic.py"))
42
+ for lf in logic_files:
43
+ try:
44
+ spec = importlib.util.spec_from_file_location(
45
+ "role_dispatch_leaf", os.path.join(logic_dir, lf))
46
+ mod = importlib.util.module_from_spec(spec)
47
+ if spec is None or spec.loader is None or mod is None:
48
+ continue
49
+ spec.loader.exec_module(mod)
50
+ return mod
51
+ except Exception:
52
+ continue
53
+ return None
54
+
55
+
56
+ def _dispatch_row(rel_leaf, fn_name, kwargs, core_value, tolerance=1e-6,
57
+ label=None, result_key=None):
58
+ """Run the leaf logic fn with the same inputs as the core, compare.
59
+
60
+ Returns a provenance 'skills' row (or None when dispatch unavailable).
61
+ core_value may be a number or a zero-arg callable resolving lazily.
62
+ """
63
+ mod = _leaf_module(rel_leaf)
64
+ if mod is None or not hasattr(mod, fn_name):
65
+ return None
66
+ if callable(core_value) and not isinstance(core_value, (int, float)):
67
+ core_value = core_value()
68
+ try:
69
+ skill_value = getattr(mod, fn_name)(**kwargs)
70
+ if result_key is not None and isinstance(skill_value, dict):
71
+ skill_value = skill_value.get(result_key)
72
+ if not isinstance(skill_value, (int, float)) or \
73
+ not isinstance(core_value, (int, float)):
74
+ return None
75
+ delta = abs(float(core_value) - float(skill_value))
76
+ row = {
77
+ "leaf": rel_leaf,
78
+ "skill_md": "SKILL.md",
79
+ "logic_file": "scripts/%s" % os.path.basename(
80
+ str(mod.__file__)),
81
+ "function": fn_name,
82
+ "dispatched": True,
83
+ "core_value": round(float(core_value), 6),
84
+ "skill_value": round(float(skill_value), 6),
85
+ "delta": round(delta, 9),
86
+ "agrees": delta <= tolerance,
87
+ "tolerance": tolerance,
88
+ "skills_release": SKILLS_RELEASE,
89
+ }
90
+ if label:
91
+ row["cross_check_point"] = label
92
+ return row
93
+ except Exception:
94
+ return None
95
+
96
+
97
+ def _dispatch_crosschecks(model):
98
+ """Cross-check the core reductions against the bound skill leaves.
99
+
100
+ Every point runs the SAME inputs through the role core and the bound
101
+ AeroSkills leaf logic (independent implementations of the same public
102
+ method) and records agreement in the provenance 'skills' list.
103
+ """
104
+ r = model["results"]
105
+ ac = model["aircraft"]
106
+ to_run = r["takeoff"]["run"]
107
+ la = r["level_accel"]
108
+ ld = r["landing"]
109
+ rows = []
110
+
111
+ def add(leaf, fn, kwargs, core_value, label, tol=1e-6,
112
+ result_key=None):
113
+ row = _dispatch_row(leaf, fn, kwargs, core_value, tolerance=tol,
114
+ label=label, result_key=result_key)
115
+ if row:
116
+ rows.append(row)
117
+
118
+ # 1. takeoff ground roll (trapezoid integration of the recorded run)
119
+ add("flight-test-operations/performance/takeoff-distance-determination",
120
+ "ground_roll_distance",
121
+ {"v_m_s_list": to_run["speeds_mps"], "t_s_list": to_run["times_s"]},
122
+ lambda: core.ground_roll_integrate(to_run["speeds_mps"],
123
+ to_run["times_s"]),
124
+ "takeoff ground roll (trapezoid), run TO-1")
125
+
126
+ # 2. rotation leg v_rot * t_rot (takeoff-distance leaf)
127
+ add("flight-test-operations/performance/takeoff-distance-determination",
128
+ "rotation_distance",
129
+ {"v_rot_m_s": to_run["v_rot_mps"],
130
+ "t_rot_s": to_run["rotation_time_s"]},
131
+ lambda: to_run["rotation_m"],
132
+ "rotation leg v_rot*t_rot")
133
+
134
+ # 3. airborne climb to the 35-ft obstacle height (takeoff-distance leaf)
135
+ add("flight-test-operations/performance/takeoff-distance-determination",
136
+ "climb_distance",
137
+ {"v_liftoff_m_s": to_run["liftoff_mps"], "h_target_m": 10.668,
138
+ "climb_rate_m_s": to_run["climb_rate_mps"]},
139
+ lambda: to_run["climb_35ft_m"],
140
+ "airborne climb to 35 ft")
141
+
142
+ # 4. rejected takeoff accelerate-stop distance (accelerate-stop leaf)
143
+ asd = r["takeoff"]["accelerate_stop"]
144
+ add("flight-test-operations/performance/accelerate-stop-distance",
145
+ "accelerate_stop_distance",
146
+ {"v1_m_s": r["takeoff"]["v1_mps"], "a_acc_m_s2": 2.3,
147
+ "a_brake_m_s2": 0.42 * core.G0},
148
+ lambda: asd["total_m"],
149
+ "rejected takeoff accelerate-stop distance", result_key="total_m")
150
+
151
+ # 5. certified landing field length 1.67 x demonstrated
152
+ add("flight-test-operations/performance/landing-distance-determination",
153
+ "certified_field_length",
154
+ {"demonstrated_m": ld["demonstrated_m"],
155
+ "factor": ld["field_length_factor"]},
156
+ lambda: ld["certified_field_length_m"],
157
+ "certified landing field length (1.67 factor)",
158
+ result_key="certified_m")
159
+
160
+ # 6. specific excess power P_s = V*a/g (level-acceleration leaf)
161
+ add("flight-test-operations/performance/level-acceleration-test",
162
+ "specific_excess_power", {"v": 160.0, "a": la["mean_acceleration"]},
163
+ lambda: la["mean_specific_excess_power"],
164
+ "P_s = V*a/g at the assessment mean acceleration", tol=1e-3)
165
+
166
+ # 7. parabolic polar drag at the mid-trace airspeed
167
+ rho_la = la["density_kgm3"]
168
+ add("flight-test-operations/performance/level-acceleration-test",
169
+ "drag_from_polar",
170
+ {"v": 160.0, "rho": rho_la, "s": ac["s_m2"],
171
+ "w": la["weight_n"], "cd0": ac["cd0"], "k": ac["k"]},
172
+ lambda: core.drag_from_polar(160.0, rho_la, ac["s_m2"],
173
+ la["weight_n"], ac["cd0"], ac["k"]),
174
+ "parabolic polar drag at the mid-trace airspeed")
175
+
176
+ # 8. cruise fuel-flow weight correction sqrt(w_ref/w_test)
177
+ pt0 = r["cruise"]["points"][0]
178
+ add("flight-test-operations/performance/cruise-performance-flight-test",
179
+ "corrected_fuel_flow",
180
+ {"wf_measured": pt0["wf_measured_kg_s"],
181
+ "w_test": pt0["w_test_kg"], "w_ref": r["cruise"]["w_ref_kg"]},
182
+ lambda: pt0["wf_corr"],
183
+ "sqrt(w_ref/w_test) fuel-flow correction, M=%.2f" % pt0["mach"])
184
+
185
+ # 9. stall speed weight correction (stall-speed leaf)
186
+ stall = r["speeds"]["stall_rows"][0]
187
+ add("flight-test-operations/performance/stall-speed-determination",
188
+ "weight_corrected_stall_speed",
189
+ {"vs_ref": ac["vs1g_ref_eas_ms"], "w_ref": ac["w_ref_n"],
190
+ "w_new": stall["weight_n"]},
191
+ lambda: stall["vs_predicted_eas_ms"],
192
+ "Vs1g weight-corrected to the stall-run gross weight")
193
+
194
+ # 10. Mach-to-TAS reduction at the cruise altitude (cruise leaf)
195
+ add("flight-test-operations/performance/cruise-performance-flight-test",
196
+ "tas_from_mach",
197
+ {"mach": pt0["mach"], "altitude_m": pt0["altitude_m"]},
198
+ lambda: core.tas_from_mach(pt0["mach"], pt0["altitude_m"]),
199
+ "Mach-to-TAS reduction at FL350", tol=1e-2)
200
+ return rows
201
+
202
+
203
+ def _provenance(model, dispatch_rows):
204
+ return {
205
+ "role": ROLE_SLUG,
206
+ "core": {
207
+ "file": "core/flight_test_performance_core.py",
208
+ "functions": ["analyze_sortie", "build_report",
209
+ "reduce_takeoff_run", "reduce_landing_run",
210
+ "reduce_level_accel_run", "reduce_cruise_points",
211
+ "check_report", "render_report_markdown"],
212
+ "version": "0.1.0",
213
+ },
214
+ "skills": dispatch_rows,
215
+ "cross_checked": bool(dispatch_rows),
216
+ "skills_release": SKILLS_RELEASE,
217
+ "disclaimer": "DRAFT for human review. Not an approval document.",
218
+ }
219
+
220
+
221
+ def cmd_build(args):
222
+ item = core.example_item()
223
+ model = core.build_report(item)
224
+ md = core.render_report_markdown(model)
225
+
226
+ # program profile (customer tailoring): load + apply context header
227
+ profile = None
228
+ try:
229
+ profile = evidence.load_profile(args.profile)
230
+ except ValueError as e:
231
+ print("error: bad profile: %s" % e)
232
+ return 1
233
+ if profile:
234
+ model["profile"] = {
235
+ "customer": profile.get("customer"),
236
+ "program": profile.get("program"),
237
+ "basis": profile.get("basis"),
238
+ "authority": profile.get("authority"),
239
+ "der": profile.get("der"),
240
+ "document_prefix": profile.get("document_prefix"),
241
+ "revision": profile.get("revision"),
242
+ }
243
+ md = evidence.profile_header_block(profile) + md
244
+
245
+ gates = core.check_report(model)
246
+ dispatch_rows = _dispatch_crosschecks(model)
247
+ prov = _provenance(model, dispatch_rows)
248
+
249
+ if args.out:
250
+ with open(args.out, "w") as f:
251
+ f.write(md if md.endswith("\n") else md + "\n")
252
+ res = model["results"]
253
+ print("built Flight Test Performance Data Analysis Report for "
254
+ "%s (%s) -> %s" % (model["item"], model["sortie_id"],
255
+ args.out))
256
+ print("takeoff distance: %.1f m (35 ft); landing certified: "
257
+ "%.1f m" % (res["takeoff"]["run"]["total_m"],
258
+ res["landing"]["certified_field_length_m"]))
259
+ print("level-accel thrust available: %.1f N; cruise MRC M=%.3f"
260
+ % (res["level_accel"]["mean_thrust_available"],
261
+ res["cruise"]["max_rp_mach"]))
262
+ dispatched = [x for x in dispatch_rows if x.get("dispatched")]
263
+ print("cross-checks: %d dispatch row(s); all agree=%s"
264
+ % (len(dispatched),
265
+ all(x.get("agrees", False) for x in dispatched)))
266
+ print("gates: all_pass=%s %s" % (gates["all_pass"], gates))
267
+ if args.bundle:
268
+ paths = evidence.write_bundle(
269
+ args.out, ROLE_SLUG,
270
+ "Flight Test Performance Data Analysis Report",
271
+ model, gates, prov)
272
+ print("bundle: model=%s" % paths["model"])
273
+ print(" gates=%s" % paths["gates"])
274
+ print(" provenance=%s" % paths["provenance"])
275
+ else:
276
+ print(md)
277
+ return 0 if gates["all_pass"] else 1
278
+
279
+
280
+ def cmd_check(args):
281
+ if not os.path.exists(args.file):
282
+ print("file not found: %s" % args.file)
283
+ return 1
284
+ md = open(args.file).read()
285
+ gates = core.check_report_markdown(md)
286
+ for name, ok in gates.items():
287
+ if name != "all_pass":
288
+ print("%s %s" % ("PASS" if ok else "FAIL", name))
289
+ print("RESULT: %s" % ("PASS" if gates["all_pass"] else "FAIL"))
290
+ return 0 if gates["all_pass"] else 1
291
+
292
+
293
+ def main():
294
+ p = argparse.ArgumentParser(
295
+ description="Flight Test Performance Engineer role: performance "
296
+ "data analysis report")
297
+ sub = p.add_subparsers(dest="cmd", required=True)
298
+
299
+ b = sub.add_parser("build")
300
+ b.add_argument("--out", default="",
301
+ help="output file (default: stdout)")
302
+ b.add_argument("--bundle", action="store_true",
303
+ help="emit evidence/{model,gates,provenance}.json")
304
+ b.add_argument("--profile", default="",
305
+ help="program profile JSON (customer tailoring, "
306
+ "docs/PROFILE-SCHEMA.md)")
307
+ b.set_defaults(fn=cmd_build)
308
+
309
+ c = sub.add_parser("check")
310
+ c.add_argument("--file", required=True,
311
+ help="report markdown to gate-check")
312
+ c.set_defaults(fn=cmd_check)
313
+
314
+ args = p.parse_args()
315
+ sys.exit(args.fn(args))
316
+
317
+
318
+ if __name__ == "__main__":
319
+ main()