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,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: role
|
|
3
|
+
name: do254-hardware-engineer
|
|
4
|
+
title: "DO-254 Airborne Electronic Hardware Engineer"
|
|
5
|
+
status: draft
|
|
6
|
+
domain: avionics
|
|
7
|
+
deliverable_type: "Plan for Hardware Aspects of Certification (PHAC) + design assurance evidence set"
|
|
8
|
+
standards_bound:
|
|
9
|
+
- id: do-254
|
|
10
|
+
tier: TIER-2
|
|
11
|
+
reference-only: true
|
|
12
|
+
- id: arp4754a
|
|
13
|
+
reference-only: true
|
|
14
|
+
skills_bound:
|
|
15
|
+
- avionics/do254/hardware-planning
|
|
16
|
+
- avionics/do254/requirements-capture
|
|
17
|
+
- avionics/do254/verification
|
|
18
|
+
- avionics/do254/configuration-management
|
|
19
|
+
tools_allowed: [stdlib, offline-file-processing]
|
|
20
|
+
forbidden:
|
|
21
|
+
- "issue certification approval"
|
|
22
|
+
- "claim regulatory sign-off"
|
|
23
|
+
- "reproduce proprietary RTCA/EUROCAE text"
|
|
24
|
+
- "assert DAL without evidence"
|
|
25
|
+
sign_off_required: true
|
|
26
|
+
license: Apache-2.0
|
|
27
|
+
compatibility: "agentskills.io ROLE.md; any SKILL.md host"
|
|
28
|
+
metadata:
|
|
29
|
+
version: 0.1.0
|
|
30
|
+
author: ashfordeOU
|
|
31
|
+
skills_release: "v1.3.0+"
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# DO-254 Airborne Electronic Hardware Engineer
|
|
35
|
+
|
|
36
|
+
## Role identity
|
|
37
|
+
|
|
38
|
+
This role drives the DO-254 design assurance workflow for an airborne
|
|
39
|
+
electronic hardware (AEH) item: from classification (simple vs complex
|
|
40
|
+
AEH) and planning through requirements capture, verification,
|
|
41
|
+
configuration management, and the Plan for Hardware Aspects of
|
|
42
|
+
Certification (PHAC). Use when a project must produce DO-254-compliant
|
|
43
|
+
hardware evidence for CPLD/FPGA/ASIC-based items or other AEH. Do NOT
|
|
44
|
+
use for software-only items (see DO-178C role) or when no cert basis
|
|
45
|
+
exists.
|
|
46
|
+
|
|
47
|
+
## Deliverable contract
|
|
48
|
+
|
|
49
|
+
The role produces:
|
|
50
|
+
|
|
51
|
+
1. **PHAC (Plan for Hardware Aspects of Certification)** — original
|
|
52
|
+
skeleton per templates/phac-template.md: hardware design assurance
|
|
53
|
+
level (DAL A-E per function failure), AEH class, life cycle data,
|
|
54
|
+
verification strategy with coverage ratios and independence, CM
|
|
55
|
+
approach, liaison with airworthiness.
|
|
56
|
+
2. **Design assurance evidence set** — requirement traceability health
|
|
57
|
+
(allocated vs derived), verification coverage vs the level's ratio,
|
|
58
|
+
configuration index input.
|
|
59
|
+
3. **Gap report** — what is missing before the human hardware cert
|
|
60
|
+
engineer signs.
|
|
61
|
+
|
|
62
|
+
## Workflow (stages → bound skills)
|
|
63
|
+
|
|
64
|
+
| Stage | Loads skill | Produces |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| 1. Hardware planning | do254/hardware-planning | AEH class (simple/complex), PHAC scope, artifact set |
|
|
67
|
+
| 2. Requirements capture | do254/requirements-capture | requirement issue list, derived-vs-allocated classification, readiness verdict |
|
|
68
|
+
| 3. Verification strategy | do254/verification | verification methods, coverage ratio (0.98 A/B, 0.95 C/D), independence |
|
|
69
|
+
| 4. Configuration management | do254/configuration-management | change class, ECR/ECO path, HCI entries, baseline control |
|
|
70
|
+
| 5. Process assurance | core engine | process assurance records plan |
|
|
71
|
+
| 6. Certification liaison | core engine | PHAC input, open items for the cert authority |
|
|
72
|
+
|
|
73
|
+
## Evidence gates
|
|
74
|
+
|
|
75
|
+
- Stage 1 done = item classified with evidence, DAL identified WITH the
|
|
76
|
+
system-safety output (FHA/PSSA), PHAC skeleton filled.
|
|
77
|
+
- Stage 2 done = every allocated requirement traced upward, every
|
|
78
|
+
derived requirement identified AND justified, readiness score >= 0.7.
|
|
79
|
+
- Stage 3 done = verification methods + coverage ratio + independence
|
|
80
|
+
stated for the item's class and level.
|
|
81
|
+
- Stage 4 done = change-class rule and HCI format applied.
|
|
82
|
+
- FINAL = every section of the deliverable has a source (skill +
|
|
83
|
+
standard reference); nothing asserted without a checkable basis.
|
|
84
|
+
|
|
85
|
+
## Boundary / forbidden
|
|
86
|
+
|
|
87
|
+
- NEVER issue certification approval — the DER/regulator signs.
|
|
88
|
+
- NEVER reproduce DO-254 text (proprietary, RTCA/EUROCAE). Summaries and
|
|
89
|
+
original structure only.
|
|
90
|
+
- NEVER assert a DAL without the system-safety evidence trail.
|
|
91
|
+
- Output is a DRAFT for human review — mark it draft.
|
|
92
|
+
|
|
93
|
+
## Verification
|
|
94
|
+
|
|
95
|
+
The role runs STANDALONE: `core/do254_hardware_core.py` is an executable
|
|
96
|
+
engine that determines DAL from failure severity, classifies AEH,
|
|
97
|
+
computes verification expectations, CM depth, requirement traceability,
|
|
98
|
+
BUILDS the PHAC, and gate-checks deliverables. No AeroSkills checkout
|
|
99
|
+
required. When the AeroSkills library is present, the CLI dispatches the
|
|
100
|
+
four bound do254 leaves' logic files and cross-checks 8 computations
|
|
101
|
+
(classification, coverage, methods, independence, change class, HCI
|
|
102
|
+
entry, readiness, derived classification).
|
|
103
|
+
|
|
104
|
+
Run the role:
|
|
105
|
+
```bash
|
|
106
|
+
python3 cli.py build --out phac.md # example item (DAL B, complex AEH)
|
|
107
|
+
python3 cli.py build --failure-condition catastrophic # DAL A variant
|
|
108
|
+
python3 cli.py build --out phac.md --bundle # + evidence/{model,gates,provenance}.json
|
|
109
|
+
python3 cli.py check --file phac.md --dal B # gate-check a PHAC
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Tests:
|
|
113
|
+
- tests/test_do254_hardware_core.py: domain rules + PHAC builder +
|
|
114
|
+
gates + standalone (no skills repo)
|
|
115
|
+
- tests/test_role_do254_hardware.py: bound-skill resolution (skips if
|
|
116
|
+
the skills repo is absent) + workflow + template present + boundaries
|
|
117
|
+
- tests/test_do254_bundle_profile.py: --bundle evidence protocol +
|
|
118
|
+
--profile + dispatch cross-checks + standalone honesty
|
|
119
|
+
|
|
120
|
+
Bound skills in Aero Skills deepen individual stages when the library
|
|
121
|
+
is present (verification logic, CM, requirements capture); the core
|
|
122
|
+
engine does not depend on them.
|
|
123
|
+
|
|
124
|
+
## Compliance
|
|
125
|
+
|
|
126
|
+
- do-254 TIER-2 reference-only per standards-map; no verbatim.
|
|
127
|
+
- SOURCES.md records acquisition/extraction/verification status.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SOURCES.md - DO-254 Airborne Electronic Hardware Engineer
|
|
2
|
+
|
|
3
|
+
Standards and documents this role references. Summary-not-copy: see
|
|
4
|
+
[STANDARDS.md](../../STANDARDS.md) for the full rule and purchase links.
|
|
5
|
+
|
|
6
|
+
| Source | Role use | Gated |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| RTCA DO-254 / EUROCAE ED-80 | design assurance of airborne electronic hardware: DAL, AEH classes, life cycle data, verification objectives | true |
|
|
9
|
+
| SAE ARP4754A | development assurance level derivation from failure conditions (shared with systems safety) | true |
|
|
10
|
+
| RTCA DO-178C | hardware/software integration boundary with hosted software | true |
|
|
11
|
+
| FAA AC 20-152A | FAA acceptance of DO-254 for AEH; simple vs complex guidance | false |
|
|
12
|
+
|
|
13
|
+
Bound AeroSkills leaves under `avionics/do254/` (hardware-planning,
|
|
14
|
+
requirements-capture, verification, configuration-management) encode
|
|
15
|
+
paraphrased common-knowledge summaries of DO-254 practice and are
|
|
16
|
+
dispatched for cross-check by `cli.py` when present. The PHAC template
|
|
17
|
+
in `templates/` is an original structure informed by public-domain
|
|
18
|
+
guidance (AC 20-152A) and summary process knowledge. No proprietary
|
|
19
|
+
text is reproduced.
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""cli.py - run the DO-254 Airborne Electronic Hardware Engineer role.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python3 cli.py build --out <file.md> # build PHAC for the example item
|
|
6
|
+
python3 cli.py build --out <file.md> --bundle # + evidence/{model,gates,provenance}.json
|
|
7
|
+
python3 cli.py build --out <file.md> --bundle --profile <profile.json>
|
|
8
|
+
python3 cli.py check --file <file.md> # gate-check an existing PHAC
|
|
9
|
+
|
|
10
|
+
The role ENGINE (core/do254_hardware_core.py) does the work standalone;
|
|
11
|
+
bound avionics/do254 skills in Aero Skills deepen individual stages
|
|
12
|
+
when present and are dispatched for cross-check.
|
|
13
|
+
"""
|
|
14
|
+
import argparse
|
|
15
|
+
import importlib.util
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
21
|
+
"core"))
|
|
22
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
23
|
+
"..", "..", "scripts"))
|
|
24
|
+
import do254_hardware_core as core # noqa: E402
|
|
25
|
+
import evidence # noqa: E402
|
|
26
|
+
|
|
27
|
+
ROLE_SLUG = "do254-hardware-engineer"
|
|
28
|
+
AEROSKILLS = os.environ.get("AEROSKILLS_DEV", os.path.expanduser("~/AeroSkills"))
|
|
29
|
+
HAS_SKILLS = os.path.isdir(os.path.join(AEROSKILLS, "skills"))
|
|
30
|
+
|
|
31
|
+
# Bound avionics/do254 leaves and their logic files.
|
|
32
|
+
DO254_LEAVES = {
|
|
33
|
+
"hardware-planning": "avionics/do254/hardware-planning",
|
|
34
|
+
"verification": "avionics/do254/verification",
|
|
35
|
+
"configuration-management": "avionics/do254/configuration-management",
|
|
36
|
+
"requirements-capture": "avionics/do254/requirements-capture",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _load_leaf(leaf: str):
|
|
41
|
+
"""Import a bound leaf's *logic.py module (or None when unavailable)."""
|
|
42
|
+
if not HAS_SKILLS:
|
|
43
|
+
return None
|
|
44
|
+
logic_dir = os.path.join(AEROSKILLS, "skills", DO254_LEAVES[leaf], "scripts")
|
|
45
|
+
if not os.path.isdir(logic_dir):
|
|
46
|
+
return None
|
|
47
|
+
logic_files = sorted(f for f in os.listdir(logic_dir)
|
|
48
|
+
if f.endswith("_logic.py"))
|
|
49
|
+
if not logic_files:
|
|
50
|
+
return None
|
|
51
|
+
for lf in logic_files:
|
|
52
|
+
path = os.path.join(logic_dir, lf)
|
|
53
|
+
spec = importlib.util.spec_from_file_location(
|
|
54
|
+
"do254_skill_" + leaf, path)
|
|
55
|
+
mod = importlib.util.module_from_spec(spec)
|
|
56
|
+
try:
|
|
57
|
+
spec.loader.exec_module(mod)
|
|
58
|
+
return mod
|
|
59
|
+
except Exception:
|
|
60
|
+
continue
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _dispatch_rows(item) -> list:
|
|
65
|
+
"""Dispatch the bound do254 skill logics and compare with the core.
|
|
66
|
+
|
|
67
|
+
Cross-check points (each leaf that ships a logic file):
|
|
68
|
+
1. hardware-planning: classify_aeh -> 'complex' for a programmable
|
|
69
|
+
logic item (AEH classification).
|
|
70
|
+
2. verification: coverage ratio adequate at the item's DAL (0.98 at B)
|
|
71
|
+
and methods required for complex AEH at level B.
|
|
72
|
+
3. configuration-management: change class for a class-1 change
|
|
73
|
+
(functional change on complex hardware) + HCI entry format.
|
|
74
|
+
4. requirements-capture: capture readiness score for the example
|
|
75
|
+
requirements set.
|
|
76
|
+
"""
|
|
77
|
+
rows = []
|
|
78
|
+
item = item or core.example_item()
|
|
79
|
+
dal = item.assurance_level()
|
|
80
|
+
|
|
81
|
+
def add(leaf, function, core_value, skill_value, extra=None):
|
|
82
|
+
if not isinstance(core_value, (int, float)) or \
|
|
83
|
+
not isinstance(skill_value, (int, float)):
|
|
84
|
+
agrees = str(core_value) == str(skill_value)
|
|
85
|
+
delta = None
|
|
86
|
+
else:
|
|
87
|
+
delta = abs(float(core_value) - float(skill_value))
|
|
88
|
+
agrees = delta <= 1e-6
|
|
89
|
+
row = {
|
|
90
|
+
"leaf": DO254_LEAVES[leaf],
|
|
91
|
+
"skill_md": "SKILL.md",
|
|
92
|
+
"logic_file": "scripts/" + os.path.basename(
|
|
93
|
+
_leaf_logic_file(leaf) or ""),
|
|
94
|
+
"function": function,
|
|
95
|
+
"dispatched": True,
|
|
96
|
+
"core_value": core_value if isinstance(core_value, (int, float))
|
|
97
|
+
else str(core_value),
|
|
98
|
+
"skill_value": skill_value if isinstance(skill_value, (int, float))
|
|
99
|
+
else str(skill_value),
|
|
100
|
+
"agrees": agrees,
|
|
101
|
+
"skills_release": "v1.3.0+",
|
|
102
|
+
}
|
|
103
|
+
if delta is not None:
|
|
104
|
+
row["delta"] = round(delta, 9)
|
|
105
|
+
row["tolerance"] = 1e-6
|
|
106
|
+
if extra:
|
|
107
|
+
row["cross_check_point"] = extra
|
|
108
|
+
rows.append(row)
|
|
109
|
+
return row
|
|
110
|
+
|
|
111
|
+
hp = _load_leaf("hardware-planning")
|
|
112
|
+
if hp is not None and hasattr(hp, "classify_aeh"):
|
|
113
|
+
add("hardware-planning", "classify_aeh",
|
|
114
|
+
core.classify_aeh(item.has_programmable_logic,
|
|
115
|
+
item.has_internal_state,
|
|
116
|
+
item.fully_verifiable_from_top_data,
|
|
117
|
+
item.safety_significant),
|
|
118
|
+
hp.classify_aeh(item.has_programmable_logic,
|
|
119
|
+
item.has_internal_state,
|
|
120
|
+
item.fully_verifiable_from_top_data,
|
|
121
|
+
item.safety_significant),
|
|
122
|
+
"complex AEH classification for programmable-logic item")
|
|
123
|
+
|
|
124
|
+
ver = _load_leaf("verification")
|
|
125
|
+
if ver is not None and hasattr(ver, "requirements_based_coverage_ok"):
|
|
126
|
+
# 196 of 200 requirements tested at DAL B -> 0.98 ratio met
|
|
127
|
+
tested, total = 196, 200
|
|
128
|
+
add("verification", "requirements_based_coverage_ok",
|
|
129
|
+
int(core.coverage_adequate(dal, tested / total)),
|
|
130
|
+
int(ver.requirements_based_coverage_ok(tested, total, dal,
|
|
131
|
+
min_ratio=0.98)),
|
|
132
|
+
"requirements-based coverage 196/200 at DAL %s" % dal)
|
|
133
|
+
if ver is not None and hasattr(ver, "verification_methods_for"):
|
|
134
|
+
core_methods = sorted(core.verification_methods_for("complex", dal))
|
|
135
|
+
skill_methods = sorted(ver.verification_methods_for("complex", dal))
|
|
136
|
+
add("verification", "verification_methods_for",
|
|
137
|
+
",".join(core_methods), ",".join(skill_methods),
|
|
138
|
+
"method set for complex AEH at DAL %s" % dal)
|
|
139
|
+
if ver is not None and hasattr(ver, "independence_required"):
|
|
140
|
+
add("verification", "independence_required",
|
|
141
|
+
int(core.independence_required(dal)),
|
|
142
|
+
int(ver.independence_required(dal)),
|
|
143
|
+
"independence expectation at DAL %s" % dal)
|
|
144
|
+
|
|
145
|
+
cm = _load_leaf("configuration-management")
|
|
146
|
+
if cm is not None and hasattr(cm, "change_class"):
|
|
147
|
+
change = {"hardware_class": "complex", "safety_effect": "major",
|
|
148
|
+
"functional_change": True}
|
|
149
|
+
add("configuration-management", "change_class",
|
|
150
|
+
core.hw_change_class(change)["class"],
|
|
151
|
+
cm.change_class(change)["class"],
|
|
152
|
+
"class-1 change on complex hardware")
|
|
153
|
+
if cm is not None and hasattr(cm, "hci_entry"):
|
|
154
|
+
add("configuration-management", "hci_entry",
|
|
155
|
+
core.hci_entry("HW-ITEM-001", "Rev C", "BL-2.0"),
|
|
156
|
+
cm.hci_entry("HW-ITEM-001", "Rev C", "BL-2.0"),
|
|
157
|
+
"HCI entry format")
|
|
158
|
+
|
|
159
|
+
rc = _load_leaf("requirements-capture")
|
|
160
|
+
if rc is not None and hasattr(rc, "capture_readiness"):
|
|
161
|
+
reqs = item.requirements or core.example_requirements()
|
|
162
|
+
core_ready, core_score = core.capture_readiness(reqs)
|
|
163
|
+
skill_ready, skill_score = rc.capture_readiness(reqs)
|
|
164
|
+
add("requirements-capture", "capture_readiness",
|
|
165
|
+
round(core_score, 6), round(skill_score, 6),
|
|
166
|
+
"capture readiness score on example requirements")
|
|
167
|
+
add("requirements-capture", "classify_derived",
|
|
168
|
+
core.classify_derived(True), rc.classify_derived(True),
|
|
169
|
+
"allocated-vs-derived classification")
|
|
170
|
+
|
|
171
|
+
return rows
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _leaf_logic_file(leaf: str) -> str:
|
|
175
|
+
"""Return the basename of a leaf's logic file (best effort)."""
|
|
176
|
+
if not HAS_SKILLS:
|
|
177
|
+
return ""
|
|
178
|
+
logic_dir = os.path.join(AEROSKILLS, "skills", DO254_LEAVES[leaf], "scripts")
|
|
179
|
+
if os.path.isdir(logic_dir):
|
|
180
|
+
files = sorted(f for f in os.listdir(logic_dir)
|
|
181
|
+
if f.endswith("_logic.py"))
|
|
182
|
+
if files:
|
|
183
|
+
return files[0]
|
|
184
|
+
return ""
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _provenance(item, rows):
|
|
188
|
+
dispatched_rows = [r for r in rows if r.get("dispatched")]
|
|
189
|
+
all_agree = bool(dispatched_rows) and all(
|
|
190
|
+
r.get("agrees") for r in dispatched_rows)
|
|
191
|
+
return {
|
|
192
|
+
"role": ROLE_SLUG,
|
|
193
|
+
"core": {
|
|
194
|
+
"file": "core/do254_hardware_core.py",
|
|
195
|
+
"functions": ["classify_aeh", "coverage_adequate",
|
|
196
|
+
"verification_methods_for", "independence_required",
|
|
197
|
+
"hw_change_class", "hci_entry",
|
|
198
|
+
"capture_readiness", "build_phac", "check_phac"],
|
|
199
|
+
"version": "0.1.0",
|
|
200
|
+
},
|
|
201
|
+
"skills": rows,
|
|
202
|
+
"cross_checked": all_agree,
|
|
203
|
+
"disclaimer": "DRAFT for human review. Not an approval document.",
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def cmd_build(args):
|
|
208
|
+
item = core.example_item()
|
|
209
|
+
# allow overriding the failure condition from CLI for different DALs
|
|
210
|
+
if args.failure_condition:
|
|
211
|
+
item.failure_condition = args.failure_condition
|
|
212
|
+
item.system_safety_ref = args.safety_ref or item.system_safety_ref
|
|
213
|
+
model = core.build_phac(item)
|
|
214
|
+
md = core.render_phac_markdown(model)
|
|
215
|
+
|
|
216
|
+
# program profile (customer tailoring): load + apply context header
|
|
217
|
+
profile = None
|
|
218
|
+
try:
|
|
219
|
+
profile = evidence.load_profile(args.profile)
|
|
220
|
+
except ValueError as e:
|
|
221
|
+
print(f"error: bad profile: {e}")
|
|
222
|
+
return 1
|
|
223
|
+
if profile:
|
|
224
|
+
model["profile"] = {
|
|
225
|
+
"customer": profile.get("customer"),
|
|
226
|
+
"program": profile.get("program"),
|
|
227
|
+
"basis": profile.get("basis"),
|
|
228
|
+
"authority": profile.get("authority"),
|
|
229
|
+
"der": profile.get("der"),
|
|
230
|
+
"document_prefix": profile.get("document_prefix"),
|
|
231
|
+
"revision": profile.get("revision"),
|
|
232
|
+
}
|
|
233
|
+
md = evidence.profile_header_block(profile) + md
|
|
234
|
+
|
|
235
|
+
gates = core.check_phac(model)
|
|
236
|
+
rows = _dispatch_rows(item)
|
|
237
|
+
|
|
238
|
+
if args.out:
|
|
239
|
+
with open(args.out, "w") as f:
|
|
240
|
+
f.write(md)
|
|
241
|
+
print(f"built PHAC (level {model['assurance_level']}, "
|
|
242
|
+
f"{model['aeh_class']} AEH) -> {args.out}")
|
|
243
|
+
if profile:
|
|
244
|
+
print(f"profile: {profile.get('customer')} / "
|
|
245
|
+
f"{profile.get('program')}")
|
|
246
|
+
print(f"gates: all_pass={gates['all_pass']} {gates}")
|
|
247
|
+
if rows:
|
|
248
|
+
n_agree = sum(1 for r in rows if r.get("agrees"))
|
|
249
|
+
print(f"skill dispatch: {n_agree}/{len(rows)} cross-checks agree")
|
|
250
|
+
else:
|
|
251
|
+
print("skill dispatch: no AeroSkills logic available "
|
|
252
|
+
"(standalone)")
|
|
253
|
+
if args.bundle:
|
|
254
|
+
prov = _provenance(item, rows)
|
|
255
|
+
paths = evidence.write_bundle(
|
|
256
|
+
args.out, ROLE_SLUG,
|
|
257
|
+
"Plan for Hardware Aspects of Certification",
|
|
258
|
+
model, gates, prov)
|
|
259
|
+
print(f"bundle: model={paths['model']}")
|
|
260
|
+
print(f" gates={paths['gates']}")
|
|
261
|
+
print(f" provenance={paths['provenance']}")
|
|
262
|
+
else:
|
|
263
|
+
print(md)
|
|
264
|
+
return 0 if gates["all_pass"] else 1
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def cmd_check(args):
|
|
268
|
+
if not os.path.exists(args.file):
|
|
269
|
+
print(f"file not found: {args.file}")
|
|
270
|
+
return 1
|
|
271
|
+
md = open(args.file).read()
|
|
272
|
+
dal = (args.dal or "B").upper()
|
|
273
|
+
gates = core.check_phac_markdown(md, dal)
|
|
274
|
+
for name, ok in gates.items():
|
|
275
|
+
if name != "all_pass":
|
|
276
|
+
print(f"{'PASS' if ok else 'FAIL'} {name}")
|
|
277
|
+
print(f"RESULT: {'PASS' if gates['all_pass'] else 'FAIL'}")
|
|
278
|
+
return 0 if gates["all_pass"] else 1
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def main():
|
|
282
|
+
p = argparse.ArgumentParser(description="DO-254 Hardware Engineer role")
|
|
283
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
284
|
+
|
|
285
|
+
b = sub.add_parser("build")
|
|
286
|
+
b.add_argument("--out", default="", help="output file (default: stdout)")
|
|
287
|
+
b.add_argument("--failure-condition", default="",
|
|
288
|
+
help="hazardous/major/minor/...")
|
|
289
|
+
b.add_argument("--safety-ref", default="", help="system safety reference")
|
|
290
|
+
b.add_argument("--bundle", action="store_true",
|
|
291
|
+
help="emit evidence/{model,gates,provenance}.json")
|
|
292
|
+
b.add_argument("--profile", default="",
|
|
293
|
+
help="program profile JSON (customer tailoring, "
|
|
294
|
+
"docs/PROFILE-SCHEMA.md)")
|
|
295
|
+
b.set_defaults(fn=cmd_build)
|
|
296
|
+
|
|
297
|
+
c = sub.add_parser("check")
|
|
298
|
+
c.add_argument("--file", required=True,
|
|
299
|
+
help="PHAC markdown file to gate-check")
|
|
300
|
+
c.add_argument("--dal", default="", help="expected design assurance level")
|
|
301
|
+
c.set_defaults(fn=cmd_check)
|
|
302
|
+
|
|
303
|
+
args = p.parse_args()
|
|
304
|
+
sys.exit(args.fn(args))
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
if __name__ == "__main__":
|
|
308
|
+
main()
|