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.
- package/NOTICE +18 -0
- package/README.md +49 -0
- package/bin/aero-agent-roles.js +127 -0
- package/lib/catalog.js +97 -0
- package/lib/install.js +48 -0
- package/lib/mcp.js +199 -0
- package/manifest.json +516 -0
- package/package.json +44 -0
- package/roles/aerodynamics-engineer/ROLE.md +153 -0
- package/roles/aerodynamics-engineer/SOURCES.md +12 -0
- package/roles/aerodynamics-engineer/cli.py +143 -0
- package/roles/aerodynamics-engineer/core/aerodynamics_core.py +1218 -0
- package/roles/aerodynamics-engineer/templates/aero-design-report-template.md +72 -0
- package/roles/aerodynamics-engineer/tests/test_aerodynamics_core.py +227 -0
- package/roles/aerodynamics-engineer/tests/test_role_aerodynamics.py +94 -0
- package/roles/aircraft-design-engineer/ROLE.md +138 -0
- package/roles/aircraft-design-engineer/SOURCES.md +12 -0
- package/roles/aircraft-design-engineer/cli.py +152 -0
- package/roles/aircraft-design-engineer/core/aircraft_design_core.py +1278 -0
- package/roles/aircraft-design-engineer/templates/concept-design-template.md +99 -0
- package/roles/aircraft-design-engineer/tests/test_aircraft_design_core.py +269 -0
- package/roles/aircraft-design-engineer/tests/test_role_aircraft_design_engineer.py +106 -0
- package/roles/airworthiness-compliance-engineer/ROLE.md +122 -0
- package/roles/airworthiness-compliance-engineer/SOURCES.md +16 -0
- package/roles/airworthiness-compliance-engineer/cli.py +146 -0
- package/roles/airworthiness-compliance-engineer/core/airworthiness_core.py +894 -0
- package/roles/airworthiness-compliance-engineer/templates/compliance-matrix-template.md +46 -0
- package/roles/airworthiness-compliance-engineer/tests/test_airworthiness_core.py +224 -0
- package/roles/airworthiness-compliance-engineer/tests/test_role_airworthiness.py +85 -0
- package/roles/as9100-quality-auditor/ROLE.md +128 -0
- package/roles/as9100-quality-auditor/SOURCES.md +16 -0
- package/roles/as9100-quality-auditor/cli.py +136 -0
- package/roles/as9100-quality-auditor/core/as9100_core.py +857 -0
- package/roles/as9100-quality-auditor/templates/findings-report-template.md +119 -0
- package/roles/as9100-quality-auditor/tests/test_as9100_cli_profile.py +105 -0
- package/roles/as9100-quality-auditor/tests/test_as9100_core.py +204 -0
- package/roles/as9100-quality-auditor/tests/test_role_as9100.py +90 -0
- package/roles/data-bus-avionics-engineer/ROLE.md +146 -0
- package/roles/data-bus-avionics-engineer/SOURCES.md +23 -0
- package/roles/data-bus-avionics-engineer/cli.py +311 -0
- package/roles/data-bus-avionics-engineer/core/data_bus_avionics_core.py +1121 -0
- package/roles/data-bus-avionics-engineer/templates/bus-assessment-template.md +134 -0
- package/roles/data-bus-avionics-engineer/tests/test_bundle_protocol.py +137 -0
- package/roles/data-bus-avionics-engineer/tests/test_data_bus_avionics_core.py +261 -0
- package/roles/data-bus-avionics-engineer/tests/test_role_data_bus_avionics_engineer.py +121 -0
- package/roles/do160-environmental-engineer/ROLE.md +136 -0
- package/roles/do160-environmental-engineer/SOURCES.md +30 -0
- package/roles/do160-environmental-engineer/cli.py +147 -0
- package/roles/do160-environmental-engineer/core/do160_environmental_core.py +1246 -0
- package/roles/do160-environmental-engineer/templates/environmental-qualification-plan-template.md +114 -0
- package/roles/do160-environmental-engineer/tests/test_do160_environmental_core.py +312 -0
- package/roles/do160-environmental-engineer/tests/test_role_do160_environmental_engineer.py +281 -0
- package/roles/do178c-cert-engineer/ROLE.md +120 -0
- package/roles/do178c-cert-engineer/SOURCES.md +16 -0
- package/roles/do178c-cert-engineer/cli.py +129 -0
- package/roles/do178c-cert-engineer/core/do178c_core.py +411 -0
- package/roles/do178c-cert-engineer/templates/psac-template.md +74 -0
- package/roles/do178c-cert-engineer/tests/test_do178c_cert_engineer_core.py +91 -0
- package/roles/do178c-cert-engineer/tests/test_role_do178c.py +109 -0
- package/roles/do254-hardware-engineer/ROLE.md +127 -0
- package/roles/do254-hardware-engineer/SOURCES.md +19 -0
- package/roles/do254-hardware-engineer/cli.py +308 -0
- package/roles/do254-hardware-engineer/core/do254_hardware_core.py +761 -0
- package/roles/do254-hardware-engineer/templates/phac-template.md +87 -0
- package/roles/do254-hardware-engineer/tests/test_do254_bundle_profile.py +152 -0
- package/roles/do254-hardware-engineer/tests/test_do254_hardware_core.py +200 -0
- package/roles/do254-hardware-engineer/tests/test_role_do254_hardware.py +108 -0
- package/roles/engineering-analysis-engineer/ROLE.md +154 -0
- package/roles/engineering-analysis-engineer/SOURCES.md +15 -0
- package/roles/engineering-analysis-engineer/cli.py +151 -0
- package/roles/engineering-analysis-engineer/core/engineering_analysis_engineer_core.py +866 -0
- package/roles/engineering-analysis-engineer/templates/analysis-memo-template.md +73 -0
- package/roles/engineering-analysis-engineer/tests/test_engineering_analysis_engineer_core.py +367 -0
- package/roles/engineering-analysis-engineer/tests/test_role_engineering_analysis_engineer.py +113 -0
- package/roles/flight-management-engineer/ROLE.md +160 -0
- package/roles/flight-management-engineer/SOURCES.md +30 -0
- package/roles/flight-management-engineer/cli.py +258 -0
- package/roles/flight-management-engineer/core/flight_management_core.py +1473 -0
- package/roles/flight-management-engineer/templates/route-assessment-template.md +94 -0
- package/roles/flight-management-engineer/tests/test_flight_management_core.py +437 -0
- package/roles/flight-management-engineer/tests/test_role_flight_management_engineer.py +123 -0
- package/roles/flight-mechanics-engineer/ROLE.md +162 -0
- package/roles/flight-mechanics-engineer/SOURCES.md +51 -0
- package/roles/flight-mechanics-engineer/cli.py +149 -0
- package/roles/flight-mechanics-engineer/core/flight_mechanics_core.py +1507 -0
- package/roles/flight-mechanics-engineer/templates/perf-sc-report-template.md +82 -0
- package/roles/flight-mechanics-engineer/tests/test_flight_mechanics_core.py +277 -0
- package/roles/flight-mechanics-engineer/tests/test_role_flight_mechanics_engineer.py +141 -0
- package/roles/flight-test-engineer/ROLE.md +137 -0
- package/roles/flight-test-engineer/SOURCES.md +24 -0
- package/roles/flight-test-engineer/cli.py +135 -0
- package/roles/flight-test-engineer/core/flight_test_core.py +931 -0
- package/roles/flight-test-engineer/templates/flight-test-template.md +143 -0
- package/roles/flight-test-engineer/tests/test_flight_test_engineer_core.py +227 -0
- package/roles/flight-test-engineer/tests/test_role_flight_test_engineer.py +150 -0
- package/roles/flight-test-performance-engineer/ROLE.md +165 -0
- package/roles/flight-test-performance-engineer/SOURCES.md +20 -0
- package/roles/flight-test-performance-engineer/cli.py +319 -0
- package/roles/flight-test-performance-engineer/core/flight_test_performance_core.py +1398 -0
- package/roles/flight-test-performance-engineer/templates/performance-report-template.md +105 -0
- package/roles/flight-test-performance-engineer/tests/test_flight_test_performance_engineer_core.py +308 -0
- package/roles/flight-test-performance-engineer/tests/test_role_flight_test_performance_engineer.py +165 -0
- package/roles/gnc-engineer/ROLE.md +141 -0
- package/roles/gnc-engineer/SOURCES.md +35 -0
- package/roles/gnc-engineer/cli.py +141 -0
- package/roles/gnc-engineer/core/gnc_core.py +1074 -0
- package/roles/gnc-engineer/templates/gnc-report-template.md +105 -0
- package/roles/gnc-engineer/tests/test_gnc_engineer_core.py +238 -0
- package/roles/gnc-engineer/tests/test_role_gnc_engineer.py +142 -0
- package/roles/guidance-engineer/ROLE.md +156 -0
- package/roles/guidance-engineer/SOURCES.md +43 -0
- package/roles/guidance-engineer/cli.py +280 -0
- package/roles/guidance-engineer/core/guidance_core.py +820 -0
- package/roles/guidance-engineer/templates/guidance-report-template.md +70 -0
- package/roles/guidance-engineer/tests/test_guidance_engineer_core.py +269 -0
- package/roles/guidance-engineer/tests/test_role_guidance_engineer.py +146 -0
- package/roles/high-speed-aerodynamics-engineer/ROLE.md +161 -0
- package/roles/high-speed-aerodynamics-engineer/SOURCES.md +18 -0
- package/roles/high-speed-aerodynamics-engineer/cli.py +282 -0
- package/roles/high-speed-aerodynamics-engineer/core/high_speed_aero_core.py +1566 -0
- package/roles/high-speed-aerodynamics-engineer/templates/high-speed-memo-template.md +75 -0
- package/roles/high-speed-aerodynamics-engineer/tests/test_bundle_protocol.py +103 -0
- package/roles/high-speed-aerodynamics-engineer/tests/test_high_speed_aero_core.py +280 -0
- package/roles/high-speed-aerodynamics-engineer/tests/test_role_high_speed_aerodynamics.py +125 -0
- package/roles/ndt-engineer/ROLE.md +157 -0
- package/roles/ndt-engineer/SOURCES.md +18 -0
- package/roles/ndt-engineer/cli.py +316 -0
- package/roles/ndt-engineer/core/ndt_core.py +1590 -0
- package/roles/ndt-engineer/templates/ndt-plan-template.md +109 -0
- package/roles/ndt-engineer/tests/test_ndt_cli_bundle.py +183 -0
- package/roles/ndt-engineer/tests/test_ndt_core.py +437 -0
- package/roles/ndt-engineer/tests/test_role_ndt_engineer.py +148 -0
- package/roles/numerical-analysis-engineer/ROLE.md +158 -0
- package/roles/numerical-analysis-engineer/SOURCES.md +19 -0
- package/roles/numerical-analysis-engineer/cli.py +414 -0
- package/roles/numerical-analysis-engineer/core/numerical_analysis_core.py +1220 -0
- package/roles/numerical-analysis-engineer/templates/verification-memo-template.md +120 -0
- package/roles/numerical-analysis-engineer/tests/test_bundle_protocol.py +157 -0
- package/roles/numerical-analysis-engineer/tests/test_numerical_analysis_core.py +337 -0
- package/roles/numerical-analysis-engineer/tests/test_role_numerical_analysis_engineer.py +117 -0
- package/roles/propulsion-engineer/ROLE.md +163 -0
- package/roles/propulsion-engineer/SOURCES.md +15 -0
- package/roles/propulsion-engineer/cli.py +168 -0
- package/roles/propulsion-engineer/core/propulsion_core.py +1291 -0
- package/roles/propulsion-engineer/templates/propulsion-report-template.md +92 -0
- package/roles/propulsion-engineer/tests/test_propulsion_engineer_core.py +294 -0
- package/roles/propulsion-engineer/tests/test_role_propulsion_engineer.py +106 -0
- package/roles/space-systems-engineer/ROLE.md +161 -0
- package/roles/space-systems-engineer/SOURCES.md +49 -0
- package/roles/space-systems-engineer/cli.py +173 -0
- package/roles/space-systems-engineer/core/space_systems_core.py +980 -0
- package/roles/space-systems-engineer/templates/space-systems-template.md +88 -0
- package/roles/space-systems-engineer/tests/test_role_space_systems_engineer.py +117 -0
- package/roles/space-systems-engineer/tests/test_space_systems_engineer_core.py +247 -0
- package/roles/state-estimation-engineer/ROLE.md +154 -0
- package/roles/state-estimation-engineer/SOURCES.md +27 -0
- package/roles/state-estimation-engineer/cli.py +326 -0
- package/roles/state-estimation-engineer/core/state_estimation_core.py +958 -0
- package/roles/state-estimation-engineer/templates/nav-state-estimator-design-template.md +76 -0
- package/roles/state-estimation-engineer/tests/test_bundle_protocol.py +110 -0
- package/roles/state-estimation-engineer/tests/test_role_state_estimation_engineer.py +127 -0
- package/roles/state-estimation-engineer/tests/test_state_estimation_engineer_core.py +231 -0
- package/roles/structures-loads-engineer/ROLE.md +171 -0
- package/roles/structures-loads-engineer/SOURCES.md +44 -0
- package/roles/structures-loads-engineer/cli.py +219 -0
- package/roles/structures-loads-engineer/core/structures_loads_core.py +1112 -0
- package/roles/structures-loads-engineer/templates/loads-strength-report-template.md +96 -0
- package/roles/structures-loads-engineer/tests/test_bundle_protocol.py +101 -0
- package/roles/structures-loads-engineer/tests/test_role_structures_loads_engineer.py +147 -0
- 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()
|