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,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: role
|
|
3
|
+
name: numerical-analysis-engineer
|
|
4
|
+
title: "Numerical Analysis Engineer"
|
|
5
|
+
status: draft
|
|
6
|
+
domain: cross-cutting
|
|
7
|
+
deliverable_type: "numerical methods verification memo"
|
|
8
|
+
standards_bound:
|
|
9
|
+
- id: asme-vv-20
|
|
10
|
+
tier: TIER-2
|
|
11
|
+
reference-only: true
|
|
12
|
+
skills_bound:
|
|
13
|
+
- cross-cutting/numerics/numerical-integration
|
|
14
|
+
- cross-cutting/numerics/root-finding
|
|
15
|
+
- cross-cutting/numerics/convergence-verification
|
|
16
|
+
- cross-cutting/numerics/finite-difference-derivatives
|
|
17
|
+
- cross-cutting/numerics/ode-solvers
|
|
18
|
+
- cross-cutting/numerics/interpolation
|
|
19
|
+
- cross-cutting/numerics/least-squares-regression
|
|
20
|
+
- cross-cutting/numerics/matrix-operations
|
|
21
|
+
- cross-cutting/numerics/singular-value-decomposition
|
|
22
|
+
- cross-cutting/numerics/uncertainty-propagation
|
|
23
|
+
tools_allowed: [stdlib, offline-file-processing]
|
|
24
|
+
forbidden:
|
|
25
|
+
- "issue engineering approval"
|
|
26
|
+
- "declare compliance"
|
|
27
|
+
- "sign off numerical results as released"
|
|
28
|
+
- "reproduce proprietary standard text"
|
|
29
|
+
sign_off_required: true
|
|
30
|
+
license: Apache-2.0
|
|
31
|
+
compatibility: "agentskills.io ROLE.md; any SKILL.md host"
|
|
32
|
+
metadata:
|
|
33
|
+
version: 0.1.0
|
|
34
|
+
author: ashfordeOU
|
|
35
|
+
skills_release: "v1.3.0+"
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
# Numerical Analysis Engineer
|
|
39
|
+
|
|
40
|
+
## Role identity
|
|
41
|
+
|
|
42
|
+
This role independently VERIFIES the numerical methods inside an
|
|
43
|
+
engineering code: the integrals, roots, solves, derivatives and
|
|
44
|
+
convergence behavior that the code's results quietly depend on. It
|
|
45
|
+
selects reference methods with real rationale, recomputes every
|
|
46
|
+
reported number with an independent implementation, quantifies the
|
|
47
|
+
discrepancy against the code's own claimed tolerances, and runs a
|
|
48
|
+
three-mesh convergence study plus a conditioning report to bound the
|
|
49
|
+
discretization and rounding error. Use when an engineering deliverable
|
|
50
|
+
rests on a numerical result that must be checked against reference
|
|
51
|
+
methods. Do NOT use for design decisions themselves (use the domain
|
|
52
|
+
roles), for statistical data analysis (see the analysis roles), or to
|
|
53
|
+
approve/release code.
|
|
54
|
+
|
|
55
|
+
## Deliverable contract
|
|
56
|
+
|
|
57
|
+
1. **Numerical Methods Verification Memo** — per numerical operation in
|
|
58
|
+
scope: the reference method selected and why, the independent
|
|
59
|
+
reference value, the code-reported value, the quantified discrepancy
|
|
60
|
+
vs the code's claimed tolerance, a PASS/FAIL verdict, and (for any
|
|
61
|
+
FAIL) an evidence-backed finding with a recommendation. Always
|
|
62
|
+
includes the convergence study (observed order, Richardson
|
|
63
|
+
extrapolation, GCI) and the conditioning assessment of any linear
|
|
64
|
+
solve.
|
|
65
|
+
2. **Evidence bundle** — `evidence/{model,gates,provenance}.json`
|
|
66
|
+
emitted with `--bundle` per PROTOCOL.md v1, carrying every number in
|
|
67
|
+
the memo plus the skill-dispatch cross-check rows.
|
|
68
|
+
|
|
69
|
+
## Workflow (stages -> bound skills)
|
|
70
|
+
|
|
71
|
+
| Stage | Loads skill | Produces |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| 1. Integration | numerics/numerical-integration | rule selection + reference integral + Richardson error estimate |
|
|
74
|
+
| 2. Root finding | numerics/root-finding | reference root (Newton + bisection bracket cross-check), simple-root check |
|
|
75
|
+
| 3. Derivatives | numerics/finite-difference-derivatives | stencil-selection input when code uses numerical differentiation |
|
|
76
|
+
| 4. ODE paths | numerics/ode-solvers | reference time-marching when the code integrates state equations |
|
|
77
|
+
| 5. Interpolation paths | numerics/interpolation | reference table interpolation checks |
|
|
78
|
+
| 6. Regression paths | numerics/least-squares-regression | reference fit checks |
|
|
79
|
+
| 7. Linear solve | numerics/matrix-operations + numerics/singular-value-decomposition | reference solve, residual, condition number s_max/s_min |
|
|
80
|
+
| 8. Convergence | numerics/convergence-verification | observed order, Richardson extrapolation, GCI (Fs=1.25), verdict |
|
|
81
|
+
| 9. Error budget | numerics/uncertainty-propagation | uncertainty framing for inputs when claimed |
|
|
82
|
+
| 10. Memo build | (report conventions) | the Numerical Methods Verification Memo + evidence bundle |
|
|
83
|
+
|
|
84
|
+
## Evidence gates
|
|
85
|
+
|
|
86
|
+
- Stage 1 done = every in-scope integral has a reference rule with
|
|
87
|
+
rationale and an error estimate; the reference value is a real number.
|
|
88
|
+
- Stage 2 done = every in-scope root has a reference root, a bracket or
|
|
89
|
+
guess statement, and a residual.
|
|
90
|
+
- Stage 7 done = the solve is checked against a pivoted reference solve
|
|
91
|
+
and the conditioning report is stated.
|
|
92
|
+
- Stage 8 done = a three-mesh study reports observed order and GCI (or
|
|
93
|
+
an explicit oscillatory/diverging verdict).
|
|
94
|
+
- FINAL = every check row quantifies discrepancy vs the code's claimed
|
|
95
|
+
tolerance and carries a PASS/FAIL verdict; findings cite their
|
|
96
|
+
evidence. Nothing is asserted without a checkable basis.
|
|
97
|
+
|
|
98
|
+
## Boundary / forbidden
|
|
99
|
+
|
|
100
|
+
- NEVER issue engineering approval, declare compliance, or sign off
|
|
101
|
+
numerical results as released — a human numerical-analysis reviewer
|
|
102
|
+
owns the disposition of findings.
|
|
103
|
+
- NEVER reproduce proprietary standard text (ASME V&V 20-2009 is
|
|
104
|
+
reference-only); the memo's method descriptions are original
|
|
105
|
+
paraphrases of classical numerical analysis.
|
|
106
|
+
- The code's claimed tolerances are inputs to the memo, not
|
|
107
|
+
endorsements.
|
|
108
|
+
- Output is a DRAFT for human review — mark it draft.
|
|
109
|
+
|
|
110
|
+
## Verification
|
|
111
|
+
|
|
112
|
+
The role runs STANDALONE: `core/numerical_analysis_core.py` is an
|
|
113
|
+
executable engine that reproduces the bound leaf methods (composite
|
|
114
|
+
trapezoid/Simpson, Richardson error estimate error(2n)=|I_2n-I_n|/3,
|
|
115
|
+
Newton-Raphson and bisection, Gaussian elimination with partial
|
|
116
|
+
pivoting, observed order/GCI with Fs=1.25, condition number s_max/s_min)
|
|
117
|
+
to compute reference values, quantify discrepancies, run the
|
|
118
|
+
convergence study, and gate-check deliverables. No AeroSkills checkout
|
|
119
|
+
required (`AEROSKILLS_DEV=/nonexistent` still builds correctly).
|
|
120
|
+
|
|
121
|
+
Run the role:
|
|
122
|
+
```bash
|
|
123
|
+
python3 cli.py build --out memo.md # example item
|
|
124
|
+
python3 cli.py build --out memo.md --bundle # + evidence bundle
|
|
125
|
+
python3 cli.py build --code-integral 50400.0 --code-integral-tol 1.0 \
|
|
126
|
+
--out memo.md # re-verify a code report
|
|
127
|
+
python3 cli.py build --profile ../../profiles/example-airframer.json \
|
|
128
|
+
--out memo.md # program tailoring
|
|
129
|
+
python3 cli.py check --file memo.md # gate-check a memo
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Tests:
|
|
133
|
+
- tests/test_numerical_analysis_core.py: quadrature rules + Richardson
|
|
134
|
+
error estimate, Newton/bisection root anchors (A/A* = 1.2 subsonic
|
|
135
|
+
M = 0.59024876099), reference solve, convergence study, conditioning,
|
|
136
|
+
memo builder, gates, standalone (no skills repo), and the filled
|
|
137
|
+
template byte-matches the core example.
|
|
138
|
+
- tests/test_role_numerical_analysis_engineer.py: bound-skill
|
|
139
|
+
resolution (skips if the skills repo is absent) + workflow +
|
|
140
|
+
template present + boundaries.
|
|
141
|
+
- tests/test_bundle_protocol.py: `build --bundle` emits the three
|
|
142
|
+
evidence files with all gates PASS; the ten dispatch rows agree with
|
|
143
|
+
the bound numerics leaves (delta <= 1e-6) when AeroSkills is present;
|
|
144
|
+
standalone runs honest (`cross_checked: false`); `--profile` and
|
|
145
|
+
`check` behave per protocol.
|
|
146
|
+
|
|
147
|
+
Bound skills in Aero Agent Skills deepen individual stages when the
|
|
148
|
+
library is present (integration, root-finding, convergence, matrix and
|
|
149
|
+
SVD leaves); the core engine does not depend on them.
|
|
150
|
+
|
|
151
|
+
## Compliance
|
|
152
|
+
|
|
153
|
+
- asme-vv-20 TIER-2 reference-only (discretization-error vocabulary).
|
|
154
|
+
- Classical numerical-analysis methodology (Richardson 1910/1927,
|
|
155
|
+
Euler-Maclaurin error analysis, Newton/Simpson/Gauss quadrature) is
|
|
156
|
+
public domain and paraphrased, never copied from any commercial
|
|
157
|
+
text.
|
|
158
|
+
- SOURCES.md records standards referenced.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SOURCES.md - Numerical Analysis 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
|
+
The numerical methods themselves (Newton, Simpson/Gauss quadrature,
|
|
6
|
+
Richardson extrapolation, Gaussian elimination, condition numbers) are
|
|
7
|
+
classical analysis and public-domain methodology; the bound AeroSkills
|
|
8
|
+
leaves paraphrase them and anchor their tables.
|
|
9
|
+
|
|
10
|
+
| Source | Role use | Gated |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| ASME V&V 20-2009, Standard for Verification and Validation in CFD and Heat Transfer | discretization-error vocabulary (observed order, Richardson extrapolation, grid convergence index, safety factor) used in the memo's convergence section | true |
|
|
13
|
+
| Classical numerical analysis (Newton 1669/1711; Simpson 1743; Gauss 1814; Richardson 1910/1927; Euler-Maclaurin error analysis) | reference methods: quadrature rules, root iterations, error estimates - public domain, paraphrased | false |
|
|
14
|
+
| NACA Report 824 (public-domain anchor of the cross-cutting/numerics leaves) | compressible-flow relation context for the area-Mach inversion anchor used by the root-finding leaf | false |
|
|
15
|
+
|
|
16
|
+
The verification-memo template in `templates/` is an original
|
|
17
|
+
structure produced by the role's own core engine; it contains no
|
|
18
|
+
reproduced text from any standard. ASME V&V 20-2009 is referenced for
|
|
19
|
+
its methodology vocabulary only (summary-not-copy, TIER-2).
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""cli.py - run the Numerical Analysis Engineer role.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python3 cli.py build [--out <file.md>] [--bundle] [--profile <file.json>]
|
|
6
|
+
[--no-dispatch]
|
|
7
|
+
[--code-integral <N>] [--code-mach <M>]
|
|
8
|
+
[--code-solve <c0,c1>]
|
|
9
|
+
# build the Numerical Methods Verification Memo for the example item
|
|
10
|
+
# (Loads Post-Processor v2.3.1) and gate-check it
|
|
11
|
+
# --bundle also emit evidence/{model,gates,provenance}.json (PROTOCOL.md)
|
|
12
|
+
# --profile program profile JSON for customer tailoring
|
|
13
|
+
# (docs/PROFILE-SCHEMA.md) -> prepended context header
|
|
14
|
+
# --no-dispatch skip dispatching bound AeroSkills numerics logic
|
|
15
|
+
# the --code-* flags re-verify a different code report of the same
|
|
16
|
+
# operations (integration value, Mach root, linear-solve result)
|
|
17
|
+
python3 cli.py check --file <file.md> # gate-check an existing memo
|
|
18
|
+
|
|
19
|
+
The role ENGINE (core/numerical_analysis_core.py) does the work standalone:
|
|
20
|
+
reference quadrature, Newton/bisection root finding, dense solve,
|
|
21
|
+
convergence study (observed order, Richardson, GCI), conditioning, and
|
|
22
|
+
the evidence gates. When AeroSkills is present (AEROSKILLS_DEV or
|
|
23
|
+
~/AeroSkills), the CLI dispatches the bound cross-cutting/numerics leaf
|
|
24
|
+
logic modules and cross-checks their numbers against the core's - two
|
|
25
|
+
independent implementations agreeing is recorded in provenance.json.
|
|
26
|
+
"""
|
|
27
|
+
import argparse
|
|
28
|
+
import importlib.util
|
|
29
|
+
import os
|
|
30
|
+
import sys
|
|
31
|
+
|
|
32
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
33
|
+
"core"))
|
|
34
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
35
|
+
"..", "..", "scripts"))
|
|
36
|
+
import numerical_analysis_core as core # noqa: E402
|
|
37
|
+
import evidence # noqa: E402
|
|
38
|
+
|
|
39
|
+
AEROSKILLS = os.environ.get("AEROSKILLS_DEV", os.path.expanduser("~/AeroSkills"))
|
|
40
|
+
NUMERICS_ROOT = os.path.join(AEROSKILLS, "skills", "cross-cutting", "numerics")
|
|
41
|
+
ROLE_SLUG = "numerical-analysis-engineer"
|
|
42
|
+
SKILLS_RELEASE = "v1.3.0+"
|
|
43
|
+
|
|
44
|
+
# Bound leaves and their dispatch points (leaf module names as on disk).
|
|
45
|
+
BOUND_LEAVES = [
|
|
46
|
+
("numerical-integration", "numerical_integration_logic.py"),
|
|
47
|
+
("root-finding", "root_finding_logic.py"),
|
|
48
|
+
("convergence-verification", "convergence_verification_logic.py"),
|
|
49
|
+
("singular-value-decomposition", "singular_value_decomposition_logic.py"),
|
|
50
|
+
("matrix-operations", "matrix_operations_logic.py"),
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _load_leaf(leaf, logic_file):
|
|
55
|
+
"""Import a bound leaf's *_logic.py module, or None when unavailable."""
|
|
56
|
+
path = os.path.join(NUMERICS_ROOT, leaf, "scripts", logic_file)
|
|
57
|
+
if not os.path.exists(path):
|
|
58
|
+
return None
|
|
59
|
+
spec = importlib.util.spec_from_file_location(
|
|
60
|
+
"numerics_leaf_" + leaf.replace("-", "_"), path)
|
|
61
|
+
mod = importlib.util.module_from_spec(spec)
|
|
62
|
+
try:
|
|
63
|
+
spec.loader.exec_module(mod)
|
|
64
|
+
return mod
|
|
65
|
+
except Exception:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _row(leaf, logic_file, fn, core_val, skill_val, point, tol=1e-6):
|
|
70
|
+
delta = abs(float(core_val) - float(skill_val))
|
|
71
|
+
return {
|
|
72
|
+
"leaf": "cross-cutting/numerics/" + leaf,
|
|
73
|
+
"skill_md": "SKILL.md",
|
|
74
|
+
"logic_file": "scripts/" + logic_file,
|
|
75
|
+
"function": fn,
|
|
76
|
+
"dispatched": True,
|
|
77
|
+
"cross_check_point": point,
|
|
78
|
+
"core_value": round(float(core_val), 9),
|
|
79
|
+
"skill_value": round(float(skill_val), 9),
|
|
80
|
+
"delta": round(delta, 12),
|
|
81
|
+
"agrees": delta <= tol,
|
|
82
|
+
"tolerance": tol,
|
|
83
|
+
"skills_release": SKILLS_RELEASE,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _row_err(leaf, logic_file, fn, exc):
|
|
88
|
+
return {"leaf": "cross-cutting/numerics/" + leaf,
|
|
89
|
+
"logic_file": "scripts/" + logic_file,
|
|
90
|
+
"function": fn, "dispatched": True,
|
|
91
|
+
"error": str(exc), "agrees": False}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _run_crosschecks(item, model):
|
|
95
|
+
"""Cross-check core numbers against the five bound numerics leaves.
|
|
96
|
+
|
|
97
|
+
Each row compares the same quantity computed two independent ways:
|
|
98
|
+
the role core implementation and the AeroSkills leaf logic. Rows
|
|
99
|
+
are empty when the skills library is absent.
|
|
100
|
+
"""
|
|
101
|
+
rows = []
|
|
102
|
+
a, b = float(item.interval[0]), float(item.interval[1])
|
|
103
|
+
f = lambda y: core.lift_intensity(y, item.integrand_w0,
|
|
104
|
+
item.integrand_span)
|
|
105
|
+
ar, gam = item.area_ratio, item.gamma
|
|
106
|
+
resid = lambda M: core.area_mach_residual(M, ar, gam)
|
|
107
|
+
deriv = lambda M: core.area_mach_derivative(M, gam)
|
|
108
|
+
|
|
109
|
+
# 1. numerical-integration: trapezoid at the code's panel count
|
|
110
|
+
mod = _load_leaf("numerical-integration",
|
|
111
|
+
"numerical_integration_logic.py")
|
|
112
|
+
if mod is not None and hasattr(mod, "trapezoid"):
|
|
113
|
+
try:
|
|
114
|
+
core_val = core.trapezoid(f, a, b, item.code_integral_n)
|
|
115
|
+
skill_val = mod.trapezoid(f, a, b, item.code_integral_n)
|
|
116
|
+
rows.append(_row("numerical-integration",
|
|
117
|
+
"numerical_integration_logic.py", "trapezoid",
|
|
118
|
+
core_val, skill_val,
|
|
119
|
+
"code-panel trapezoid of the spanwise load"))
|
|
120
|
+
except Exception as e: # pragma: no cover
|
|
121
|
+
rows.append(_row_err("numerical-integration",
|
|
122
|
+
"numerical_integration_logic.py",
|
|
123
|
+
"trapezoid", e))
|
|
124
|
+
|
|
125
|
+
# 2. numerical-integration: reference Simpson value
|
|
126
|
+
if mod is not None and hasattr(mod, "simpson"):
|
|
127
|
+
try:
|
|
128
|
+
n_ref = max(2 * item.code_integral_n, 64)
|
|
129
|
+
core_val = core.simpson(f, a, b, n_ref)
|
|
130
|
+
skill_val = mod.simpson(f, a, b, n_ref)
|
|
131
|
+
rows.append(_row("numerical-integration",
|
|
132
|
+
"numerical_integration_logic.py", "simpson",
|
|
133
|
+
core_val, skill_val,
|
|
134
|
+
"reference Simpson integral of the spanwise "
|
|
135
|
+
"load"))
|
|
136
|
+
except Exception as e: # pragma: no cover
|
|
137
|
+
rows.append(_row_err("numerical-integration",
|
|
138
|
+
"numerical_integration_logic.py",
|
|
139
|
+
"simpson", e))
|
|
140
|
+
|
|
141
|
+
# 3. numerical-integration: Richardson error estimate error(2n)
|
|
142
|
+
if mod is not None and hasattr(mod, "error_estimate_trapezoid"):
|
|
143
|
+
try:
|
|
144
|
+
core_val = core.richardson_error_trapezoid(
|
|
145
|
+
f, a, b, item.code_integral_n)
|
|
146
|
+
skill_val = mod.error_estimate_trapezoid(
|
|
147
|
+
f, a, b, item.code_integral_n)
|
|
148
|
+
rows.append(_row("numerical-integration",
|
|
149
|
+
"numerical_integration_logic.py",
|
|
150
|
+
"error_estimate_trapezoid", core_val, skill_val,
|
|
151
|
+
"Richardson error estimate of the trapezoid "
|
|
152
|
+
"result"))
|
|
153
|
+
except Exception as e: # pragma: no cover
|
|
154
|
+
rows.append(_row_err("numerical-integration",
|
|
155
|
+
"numerical_integration_logic.py",
|
|
156
|
+
"error_estimate_trapezoid", e))
|
|
157
|
+
|
|
158
|
+
# 4. root-finding: Newton-Raphson subsonic area-Mach root
|
|
159
|
+
mod = _load_leaf("root-finding", "root_finding_logic.py")
|
|
160
|
+
if mod is not None and hasattr(mod, "newton_raphson"):
|
|
161
|
+
try:
|
|
162
|
+
core_val = core.newton_raphson(resid, deriv, item.newton_guess)
|
|
163
|
+
skill_val = mod.newton_raphson(resid, deriv, item.newton_guess)
|
|
164
|
+
rows.append(_row("root-finding", "root_finding_logic.py",
|
|
165
|
+
"newton_raphson", core_val, skill_val,
|
|
166
|
+
"subsonic root of A/A* = %g, gamma = %g"
|
|
167
|
+
% (ar, gam)))
|
|
168
|
+
except Exception as e: # pragma: no cover
|
|
169
|
+
rows.append(_row_err("root-finding", "root_finding_logic.py",
|
|
170
|
+
"newton_raphson", e))
|
|
171
|
+
|
|
172
|
+
# 5. root-finding: bisection bracket cross-check
|
|
173
|
+
if mod is not None and hasattr(mod, "bisection"):
|
|
174
|
+
try:
|
|
175
|
+
core_val = core.bisection(resid, item.bracket[0], item.bracket[1])
|
|
176
|
+
skill_val = mod.bisection(resid, item.bracket[0], item.bracket[1])
|
|
177
|
+
rows.append(_row("root-finding", "root_finding_logic.py",
|
|
178
|
+
"bisection", core_val, skill_val,
|
|
179
|
+
"bisection cross-check on [%g, %g]"
|
|
180
|
+
% (item.bracket[0], item.bracket[1])))
|
|
181
|
+
except Exception as e: # pragma: no cover
|
|
182
|
+
rows.append(_row_err("root-finding", "root_finding_logic.py",
|
|
183
|
+
"bisection", e))
|
|
184
|
+
|
|
185
|
+
# 6. convergence-verification: grid-study order + GCI
|
|
186
|
+
mod = _load_leaf("convergence-verification",
|
|
187
|
+
"convergence_verification_logic.py")
|
|
188
|
+
if mod is not None and hasattr(mod, "convergence_verdict"):
|
|
189
|
+
try:
|
|
190
|
+
meshes = model["convergence"]["meshes"]
|
|
191
|
+
f1, f2, f3 = (m["f"] for m in meshes)
|
|
192
|
+
r = model["convergence"]["refinement_ratio"]
|
|
193
|
+
core_cv = core.convergence_verdict(f1, f2, f3, r)
|
|
194
|
+
skill_cv = mod.convergence_verdict(f1, f2, f3, r)
|
|
195
|
+
if core_cv["order"] is not None and skill_cv["order"] is not None:
|
|
196
|
+
rows.append(_row("convergence-verification",
|
|
197
|
+
"convergence_verification_logic.py",
|
|
198
|
+
"convergence_verdict.order",
|
|
199
|
+
core_cv["order"], skill_cv["order"],
|
|
200
|
+
"observed order of the three-mesh study"))
|
|
201
|
+
rows.append(_row("convergence-verification",
|
|
202
|
+
"convergence_verification_logic.py",
|
|
203
|
+
"convergence_verdict.gci",
|
|
204
|
+
core_cv["gci"], skill_cv["gci"],
|
|
205
|
+
"grid convergence index of the study"))
|
|
206
|
+
rows.append(_row("convergence-verification",
|
|
207
|
+
"convergence_verification_logic.py",
|
|
208
|
+
"convergence_verdict.verdict",
|
|
209
|
+
1.0 if core_cv["verdict"] == skill_cv["verdict"]
|
|
210
|
+
else 0.0,
|
|
211
|
+
1.0,
|
|
212
|
+
"convergence verdict classification"))
|
|
213
|
+
except Exception as e: # pragma: no cover
|
|
214
|
+
rows.append(_row_err("convergence-verification",
|
|
215
|
+
"convergence_verification_logic.py",
|
|
216
|
+
"convergence_verdict", e))
|
|
217
|
+
|
|
218
|
+
# 7. singular-value-decomposition: condition number of the solve
|
|
219
|
+
mod = _load_leaf("singular-value-decomposition",
|
|
220
|
+
"singular_value_decomposition_logic.py")
|
|
221
|
+
if mod is not None and hasattr(mod, "condition_number"):
|
|
222
|
+
try:
|
|
223
|
+
sv = model["linear_solve"]["conditioning"]["singular_values"]
|
|
224
|
+
core_val = core.condition_number(sv)
|
|
225
|
+
skill_val = mod.condition_number(sv)
|
|
226
|
+
rows.append(_row("singular-value-decomposition",
|
|
227
|
+
"singular_value_decomposition_logic.py",
|
|
228
|
+
"condition_number", core_val, skill_val,
|
|
229
|
+
"2-norm condition number s_max/s_min of A"))
|
|
230
|
+
except Exception as e: # pragma: no cover
|
|
231
|
+
rows.append(_row_err("singular-value-decomposition",
|
|
232
|
+
"singular_value_decomposition_logic.py",
|
|
233
|
+
"condition_number", e))
|
|
234
|
+
|
|
235
|
+
# 8. matrix-operations: reference dense solve of A c = b
|
|
236
|
+
mod = _load_leaf("matrix-operations", "matrix_operations_logic.py")
|
|
237
|
+
if mod is not None and hasattr(mod, "solve"):
|
|
238
|
+
try:
|
|
239
|
+
core_val = core.solve(item.system_A, item.system_b)[0]
|
|
240
|
+
skill_val = mod.solve(item.system_A, item.system_b)[0]
|
|
241
|
+
rows.append(_row("matrix-operations", "matrix_operations_logic.py",
|
|
242
|
+
"solve", core_val, skill_val,
|
|
243
|
+
"first component of c = A^-1 b"))
|
|
244
|
+
except Exception as e: # pragma: no cover
|
|
245
|
+
rows.append(_row_err("matrix-operations",
|
|
246
|
+
"matrix_operations_logic.py", "solve", e))
|
|
247
|
+
return rows
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _provenance(rows):
|
|
251
|
+
ok_rows = [r for r in rows if r.get("dispatched") and not r.get("error")]
|
|
252
|
+
return {
|
|
253
|
+
"role": ROLE_SLUG,
|
|
254
|
+
"core": {
|
|
255
|
+
"file": "core/numerical_analysis_core.py",
|
|
256
|
+
"functions": ["trapezoid", "simpson",
|
|
257
|
+
"richardson_error_trapezoid", "newton_raphson",
|
|
258
|
+
"bisection", "convergence_verdict", "solve",
|
|
259
|
+
"condition_number", "build_report",
|
|
260
|
+
"check_report"],
|
|
261
|
+
"version": "0.1.0",
|
|
262
|
+
},
|
|
263
|
+
"skills": rows,
|
|
264
|
+
"cross_checked": bool(ok_rows) and all(r.get("agrees")
|
|
265
|
+
for r in ok_rows),
|
|
266
|
+
"disclaimer": "DRAFT for human review. Not an approval document.",
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _parse_csv_floats(text):
|
|
271
|
+
return [float(t) for t in str(text).split(",") if t.strip()]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def cmd_build(args):
|
|
275
|
+
item = core.example_item()
|
|
276
|
+
# allow re-verifying different code reports from the CLI
|
|
277
|
+
if args.code_integral is not None:
|
|
278
|
+
item.code_integral = args.code_integral
|
|
279
|
+
if args.code_integral_tol is not None:
|
|
280
|
+
item.code_integral_tol = args.code_integral_tol
|
|
281
|
+
if args.code_mach is not None:
|
|
282
|
+
item.code_mach = args.code_mach
|
|
283
|
+
if args.code_mach_tol is not None:
|
|
284
|
+
item.code_mach_tol = args.code_mach_tol
|
|
285
|
+
if args.code_solve:
|
|
286
|
+
vals = _parse_csv_floats(args.code_solve)
|
|
287
|
+
if len(vals) != len(item.system_b):
|
|
288
|
+
print("error: --code-solve needs %d comma-separated values"
|
|
289
|
+
% len(item.system_b))
|
|
290
|
+
return 1
|
|
291
|
+
item.code_solution = vals
|
|
292
|
+
if args.code_solve_tol is not None:
|
|
293
|
+
item.code_solve_tol = args.code_solve_tol
|
|
294
|
+
|
|
295
|
+
model = core.build_report(item)
|
|
296
|
+
md = core.render_report_markdown(model)
|
|
297
|
+
|
|
298
|
+
# program profile (customer tailoring): load + apply context header
|
|
299
|
+
profile = None
|
|
300
|
+
try:
|
|
301
|
+
profile = evidence.load_profile(args.profile)
|
|
302
|
+
except ValueError as e:
|
|
303
|
+
print(f"error: bad profile: {e}")
|
|
304
|
+
return 1
|
|
305
|
+
if profile:
|
|
306
|
+
model["profile"] = {
|
|
307
|
+
"customer": profile.get("customer"),
|
|
308
|
+
"program": profile.get("program"),
|
|
309
|
+
"basis": profile.get("basis"),
|
|
310
|
+
"authority": profile.get("authority"),
|
|
311
|
+
"der": profile.get("der"),
|
|
312
|
+
"document_prefix": profile.get("document_prefix"),
|
|
313
|
+
"revision": profile.get("revision"),
|
|
314
|
+
}
|
|
315
|
+
md = evidence.profile_header_block(profile) + md
|
|
316
|
+
|
|
317
|
+
gates = core.check_report(model)
|
|
318
|
+
|
|
319
|
+
rows = []
|
|
320
|
+
if not args.no_dispatch:
|
|
321
|
+
rows = _run_crosschecks(item, model)
|
|
322
|
+
|
|
323
|
+
if args.out:
|
|
324
|
+
with open(args.out, "w") as f:
|
|
325
|
+
f.write(md if md.endswith("\n") else md + "\n")
|
|
326
|
+
print("built Numerical Methods Verification Memo -> %s" % args.out)
|
|
327
|
+
for c in model["checks"]:
|
|
328
|
+
print(" %-12s verdict=%-4s discrepancy=%.6g (tol %g)"
|
|
329
|
+
% (c["operation"][:12], c["verdict"], c["discrepancy"],
|
|
330
|
+
c["code_tolerance"]))
|
|
331
|
+
conv = model["convergence"]
|
|
332
|
+
print(" grid study: p=%s gci=%s verdict=%s"
|
|
333
|
+
% (conv["observed_order"], conv["gci_fraction"],
|
|
334
|
+
conv["verdict"]))
|
|
335
|
+
print("gates: all_pass=%s %s" % (gates["all_pass"], gates))
|
|
336
|
+
if profile:
|
|
337
|
+
print("profile: %s / %s" % (profile.get("customer"),
|
|
338
|
+
profile.get("program")))
|
|
339
|
+
if args.bundle:
|
|
340
|
+
prov = _provenance(rows)
|
|
341
|
+
paths = evidence.write_bundle(
|
|
342
|
+
args.out, ROLE_SLUG,
|
|
343
|
+
"Numerical Methods Verification Memo", model, gates, prov)
|
|
344
|
+
print("bundle: model=%s" % paths["model"])
|
|
345
|
+
print(" gates=%s" % paths["gates"])
|
|
346
|
+
print(" provenance=%s" % paths["provenance"])
|
|
347
|
+
if rows:
|
|
348
|
+
for r in rows:
|
|
349
|
+
if r.get("dispatched") and not r.get("error"):
|
|
350
|
+
print("cross-check: %-32s core=%-12s skill=%-12s "
|
|
351
|
+
"delta=%s agrees=%s"
|
|
352
|
+
% (r["function"], r["core_value"],
|
|
353
|
+
r["skill_value"], r["delta"], r["agrees"]))
|
|
354
|
+
else:
|
|
355
|
+
print("cross-check: not dispatched (no AeroSkills logic)")
|
|
356
|
+
else:
|
|
357
|
+
print(md)
|
|
358
|
+
return 0 if gates["all_pass"] else 1
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def cmd_check(args):
|
|
362
|
+
if not os.path.exists(args.file):
|
|
363
|
+
print(f"file not found: {args.file}")
|
|
364
|
+
return 1
|
|
365
|
+
md = open(args.file).read()
|
|
366
|
+
gates = core.check_report_markdown(md)
|
|
367
|
+
for name, ok in gates.items():
|
|
368
|
+
if name != "all_pass":
|
|
369
|
+
print(f"{'PASS' if ok else 'FAIL'} {name}")
|
|
370
|
+
print(f"RESULT: {'PASS' if gates['all_pass'] else 'FAIL'}")
|
|
371
|
+
return 0 if gates["all_pass"] else 1
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def main():
|
|
375
|
+
p = argparse.ArgumentParser(
|
|
376
|
+
description="Numerical Analysis Engineer role: numerical methods "
|
|
377
|
+
"verification memo")
|
|
378
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
379
|
+
|
|
380
|
+
b = sub.add_parser("build")
|
|
381
|
+
b.add_argument("--out", default="",
|
|
382
|
+
help="output file (default: stdout)")
|
|
383
|
+
b.add_argument("--bundle", action="store_true",
|
|
384
|
+
help="emit evidence/{model,gates,provenance}.json")
|
|
385
|
+
b.add_argument("--profile", default="",
|
|
386
|
+
help="program profile JSON (customer tailoring, "
|
|
387
|
+
"docs/PROFILE-SCHEMA.md)")
|
|
388
|
+
b.add_argument("--no-dispatch", action="store_true",
|
|
389
|
+
help="skip dispatching bound AeroSkills logic")
|
|
390
|
+
b.add_argument("--code-integral", type=float, default=None,
|
|
391
|
+
help="code-reported integral (N) to re-verify")
|
|
392
|
+
b.add_argument("--code-integral-tol", type=float, default=None,
|
|
393
|
+
help="code-claimed integral tolerance (N)")
|
|
394
|
+
b.add_argument("--code-mach", type=float, default=None,
|
|
395
|
+
help="code-reported subsonic Mach root to re-verify")
|
|
396
|
+
b.add_argument("--code-mach-tol", type=float, default=None,
|
|
397
|
+
help="code-claimed root residual tolerance")
|
|
398
|
+
b.add_argument("--code-solve", default="",
|
|
399
|
+
help="code-reported solution as c0,c1 to re-verify")
|
|
400
|
+
b.add_argument("--code-solve-tol", type=float, default=None,
|
|
401
|
+
help="code-claimed solve component tolerance")
|
|
402
|
+
b.set_defaults(fn=cmd_build)
|
|
403
|
+
|
|
404
|
+
c = sub.add_parser("check")
|
|
405
|
+
c.add_argument("--file", required=True,
|
|
406
|
+
help="verification memo markdown to gate-check")
|
|
407
|
+
c.set_defaults(fn=cmd_check)
|
|
408
|
+
|
|
409
|
+
args = p.parse_args()
|
|
410
|
+
sys.exit(args.fn(args))
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
if __name__ == "__main__":
|
|
414
|
+
main()
|