aero-agent-roles 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/NOTICE +18 -0
  2. package/README.md +49 -0
  3. package/bin/aero-agent-roles.js +127 -0
  4. package/lib/catalog.js +97 -0
  5. package/lib/install.js +48 -0
  6. package/lib/mcp.js +199 -0
  7. package/manifest.json +516 -0
  8. package/package.json +44 -0
  9. package/roles/aerodynamics-engineer/ROLE.md +153 -0
  10. package/roles/aerodynamics-engineer/SOURCES.md +12 -0
  11. package/roles/aerodynamics-engineer/cli.py +143 -0
  12. package/roles/aerodynamics-engineer/core/aerodynamics_core.py +1218 -0
  13. package/roles/aerodynamics-engineer/templates/aero-design-report-template.md +72 -0
  14. package/roles/aerodynamics-engineer/tests/test_aerodynamics_core.py +227 -0
  15. package/roles/aerodynamics-engineer/tests/test_role_aerodynamics.py +94 -0
  16. package/roles/aircraft-design-engineer/ROLE.md +138 -0
  17. package/roles/aircraft-design-engineer/SOURCES.md +12 -0
  18. package/roles/aircraft-design-engineer/cli.py +152 -0
  19. package/roles/aircraft-design-engineer/core/aircraft_design_core.py +1278 -0
  20. package/roles/aircraft-design-engineer/templates/concept-design-template.md +99 -0
  21. package/roles/aircraft-design-engineer/tests/test_aircraft_design_core.py +269 -0
  22. package/roles/aircraft-design-engineer/tests/test_role_aircraft_design_engineer.py +106 -0
  23. package/roles/airworthiness-compliance-engineer/ROLE.md +122 -0
  24. package/roles/airworthiness-compliance-engineer/SOURCES.md +16 -0
  25. package/roles/airworthiness-compliance-engineer/cli.py +146 -0
  26. package/roles/airworthiness-compliance-engineer/core/airworthiness_core.py +894 -0
  27. package/roles/airworthiness-compliance-engineer/templates/compliance-matrix-template.md +46 -0
  28. package/roles/airworthiness-compliance-engineer/tests/test_airworthiness_core.py +224 -0
  29. package/roles/airworthiness-compliance-engineer/tests/test_role_airworthiness.py +85 -0
  30. package/roles/as9100-quality-auditor/ROLE.md +128 -0
  31. package/roles/as9100-quality-auditor/SOURCES.md +16 -0
  32. package/roles/as9100-quality-auditor/cli.py +136 -0
  33. package/roles/as9100-quality-auditor/core/as9100_core.py +857 -0
  34. package/roles/as9100-quality-auditor/templates/findings-report-template.md +119 -0
  35. package/roles/as9100-quality-auditor/tests/test_as9100_cli_profile.py +105 -0
  36. package/roles/as9100-quality-auditor/tests/test_as9100_core.py +204 -0
  37. package/roles/as9100-quality-auditor/tests/test_role_as9100.py +90 -0
  38. package/roles/data-bus-avionics-engineer/ROLE.md +146 -0
  39. package/roles/data-bus-avionics-engineer/SOURCES.md +23 -0
  40. package/roles/data-bus-avionics-engineer/cli.py +311 -0
  41. package/roles/data-bus-avionics-engineer/core/data_bus_avionics_core.py +1121 -0
  42. package/roles/data-bus-avionics-engineer/templates/bus-assessment-template.md +134 -0
  43. package/roles/data-bus-avionics-engineer/tests/test_bundle_protocol.py +137 -0
  44. package/roles/data-bus-avionics-engineer/tests/test_data_bus_avionics_core.py +261 -0
  45. package/roles/data-bus-avionics-engineer/tests/test_role_data_bus_avionics_engineer.py +121 -0
  46. package/roles/do160-environmental-engineer/ROLE.md +136 -0
  47. package/roles/do160-environmental-engineer/SOURCES.md +30 -0
  48. package/roles/do160-environmental-engineer/cli.py +147 -0
  49. package/roles/do160-environmental-engineer/core/do160_environmental_core.py +1246 -0
  50. package/roles/do160-environmental-engineer/templates/environmental-qualification-plan-template.md +114 -0
  51. package/roles/do160-environmental-engineer/tests/test_do160_environmental_core.py +312 -0
  52. package/roles/do160-environmental-engineer/tests/test_role_do160_environmental_engineer.py +281 -0
  53. package/roles/do178c-cert-engineer/ROLE.md +120 -0
  54. package/roles/do178c-cert-engineer/SOURCES.md +16 -0
  55. package/roles/do178c-cert-engineer/cli.py +129 -0
  56. package/roles/do178c-cert-engineer/core/do178c_core.py +411 -0
  57. package/roles/do178c-cert-engineer/templates/psac-template.md +74 -0
  58. package/roles/do178c-cert-engineer/tests/test_do178c_cert_engineer_core.py +91 -0
  59. package/roles/do178c-cert-engineer/tests/test_role_do178c.py +109 -0
  60. package/roles/do254-hardware-engineer/ROLE.md +127 -0
  61. package/roles/do254-hardware-engineer/SOURCES.md +19 -0
  62. package/roles/do254-hardware-engineer/cli.py +308 -0
  63. package/roles/do254-hardware-engineer/core/do254_hardware_core.py +761 -0
  64. package/roles/do254-hardware-engineer/templates/phac-template.md +87 -0
  65. package/roles/do254-hardware-engineer/tests/test_do254_bundle_profile.py +152 -0
  66. package/roles/do254-hardware-engineer/tests/test_do254_hardware_core.py +200 -0
  67. package/roles/do254-hardware-engineer/tests/test_role_do254_hardware.py +108 -0
  68. package/roles/engineering-analysis-engineer/ROLE.md +154 -0
  69. package/roles/engineering-analysis-engineer/SOURCES.md +15 -0
  70. package/roles/engineering-analysis-engineer/cli.py +151 -0
  71. package/roles/engineering-analysis-engineer/core/engineering_analysis_engineer_core.py +866 -0
  72. package/roles/engineering-analysis-engineer/templates/analysis-memo-template.md +73 -0
  73. package/roles/engineering-analysis-engineer/tests/test_engineering_analysis_engineer_core.py +367 -0
  74. package/roles/engineering-analysis-engineer/tests/test_role_engineering_analysis_engineer.py +113 -0
  75. package/roles/flight-management-engineer/ROLE.md +160 -0
  76. package/roles/flight-management-engineer/SOURCES.md +30 -0
  77. package/roles/flight-management-engineer/cli.py +258 -0
  78. package/roles/flight-management-engineer/core/flight_management_core.py +1473 -0
  79. package/roles/flight-management-engineer/templates/route-assessment-template.md +94 -0
  80. package/roles/flight-management-engineer/tests/test_flight_management_core.py +437 -0
  81. package/roles/flight-management-engineer/tests/test_role_flight_management_engineer.py +123 -0
  82. package/roles/flight-mechanics-engineer/ROLE.md +162 -0
  83. package/roles/flight-mechanics-engineer/SOURCES.md +51 -0
  84. package/roles/flight-mechanics-engineer/cli.py +149 -0
  85. package/roles/flight-mechanics-engineer/core/flight_mechanics_core.py +1507 -0
  86. package/roles/flight-mechanics-engineer/templates/perf-sc-report-template.md +82 -0
  87. package/roles/flight-mechanics-engineer/tests/test_flight_mechanics_core.py +277 -0
  88. package/roles/flight-mechanics-engineer/tests/test_role_flight_mechanics_engineer.py +141 -0
  89. package/roles/flight-test-engineer/ROLE.md +137 -0
  90. package/roles/flight-test-engineer/SOURCES.md +24 -0
  91. package/roles/flight-test-engineer/cli.py +135 -0
  92. package/roles/flight-test-engineer/core/flight_test_core.py +931 -0
  93. package/roles/flight-test-engineer/templates/flight-test-template.md +143 -0
  94. package/roles/flight-test-engineer/tests/test_flight_test_engineer_core.py +227 -0
  95. package/roles/flight-test-engineer/tests/test_role_flight_test_engineer.py +150 -0
  96. package/roles/flight-test-performance-engineer/ROLE.md +165 -0
  97. package/roles/flight-test-performance-engineer/SOURCES.md +20 -0
  98. package/roles/flight-test-performance-engineer/cli.py +319 -0
  99. package/roles/flight-test-performance-engineer/core/flight_test_performance_core.py +1398 -0
  100. package/roles/flight-test-performance-engineer/templates/performance-report-template.md +105 -0
  101. package/roles/flight-test-performance-engineer/tests/test_flight_test_performance_engineer_core.py +308 -0
  102. package/roles/flight-test-performance-engineer/tests/test_role_flight_test_performance_engineer.py +165 -0
  103. package/roles/gnc-engineer/ROLE.md +141 -0
  104. package/roles/gnc-engineer/SOURCES.md +35 -0
  105. package/roles/gnc-engineer/cli.py +141 -0
  106. package/roles/gnc-engineer/core/gnc_core.py +1074 -0
  107. package/roles/gnc-engineer/templates/gnc-report-template.md +105 -0
  108. package/roles/gnc-engineer/tests/test_gnc_engineer_core.py +238 -0
  109. package/roles/gnc-engineer/tests/test_role_gnc_engineer.py +142 -0
  110. package/roles/guidance-engineer/ROLE.md +156 -0
  111. package/roles/guidance-engineer/SOURCES.md +43 -0
  112. package/roles/guidance-engineer/cli.py +280 -0
  113. package/roles/guidance-engineer/core/guidance_core.py +820 -0
  114. package/roles/guidance-engineer/templates/guidance-report-template.md +70 -0
  115. package/roles/guidance-engineer/tests/test_guidance_engineer_core.py +269 -0
  116. package/roles/guidance-engineer/tests/test_role_guidance_engineer.py +146 -0
  117. package/roles/high-speed-aerodynamics-engineer/ROLE.md +161 -0
  118. package/roles/high-speed-aerodynamics-engineer/SOURCES.md +18 -0
  119. package/roles/high-speed-aerodynamics-engineer/cli.py +282 -0
  120. package/roles/high-speed-aerodynamics-engineer/core/high_speed_aero_core.py +1566 -0
  121. package/roles/high-speed-aerodynamics-engineer/templates/high-speed-memo-template.md +75 -0
  122. package/roles/high-speed-aerodynamics-engineer/tests/test_bundle_protocol.py +103 -0
  123. package/roles/high-speed-aerodynamics-engineer/tests/test_high_speed_aero_core.py +280 -0
  124. package/roles/high-speed-aerodynamics-engineer/tests/test_role_high_speed_aerodynamics.py +125 -0
  125. package/roles/ndt-engineer/ROLE.md +157 -0
  126. package/roles/ndt-engineer/SOURCES.md +18 -0
  127. package/roles/ndt-engineer/cli.py +316 -0
  128. package/roles/ndt-engineer/core/ndt_core.py +1590 -0
  129. package/roles/ndt-engineer/templates/ndt-plan-template.md +109 -0
  130. package/roles/ndt-engineer/tests/test_ndt_cli_bundle.py +183 -0
  131. package/roles/ndt-engineer/tests/test_ndt_core.py +437 -0
  132. package/roles/ndt-engineer/tests/test_role_ndt_engineer.py +148 -0
  133. package/roles/numerical-analysis-engineer/ROLE.md +158 -0
  134. package/roles/numerical-analysis-engineer/SOURCES.md +19 -0
  135. package/roles/numerical-analysis-engineer/cli.py +414 -0
  136. package/roles/numerical-analysis-engineer/core/numerical_analysis_core.py +1220 -0
  137. package/roles/numerical-analysis-engineer/templates/verification-memo-template.md +120 -0
  138. package/roles/numerical-analysis-engineer/tests/test_bundle_protocol.py +157 -0
  139. package/roles/numerical-analysis-engineer/tests/test_numerical_analysis_core.py +337 -0
  140. package/roles/numerical-analysis-engineer/tests/test_role_numerical_analysis_engineer.py +117 -0
  141. package/roles/propulsion-engineer/ROLE.md +163 -0
  142. package/roles/propulsion-engineer/SOURCES.md +15 -0
  143. package/roles/propulsion-engineer/cli.py +168 -0
  144. package/roles/propulsion-engineer/core/propulsion_core.py +1291 -0
  145. package/roles/propulsion-engineer/templates/propulsion-report-template.md +92 -0
  146. package/roles/propulsion-engineer/tests/test_propulsion_engineer_core.py +294 -0
  147. package/roles/propulsion-engineer/tests/test_role_propulsion_engineer.py +106 -0
  148. package/roles/space-systems-engineer/ROLE.md +161 -0
  149. package/roles/space-systems-engineer/SOURCES.md +49 -0
  150. package/roles/space-systems-engineer/cli.py +173 -0
  151. package/roles/space-systems-engineer/core/space_systems_core.py +980 -0
  152. package/roles/space-systems-engineer/templates/space-systems-template.md +88 -0
  153. package/roles/space-systems-engineer/tests/test_role_space_systems_engineer.py +117 -0
  154. package/roles/space-systems-engineer/tests/test_space_systems_engineer_core.py +247 -0
  155. package/roles/state-estimation-engineer/ROLE.md +154 -0
  156. package/roles/state-estimation-engineer/SOURCES.md +27 -0
  157. package/roles/state-estimation-engineer/cli.py +326 -0
  158. package/roles/state-estimation-engineer/core/state_estimation_core.py +958 -0
  159. package/roles/state-estimation-engineer/templates/nav-state-estimator-design-template.md +76 -0
  160. package/roles/state-estimation-engineer/tests/test_bundle_protocol.py +110 -0
  161. package/roles/state-estimation-engineer/tests/test_role_state_estimation_engineer.py +127 -0
  162. package/roles/state-estimation-engineer/tests/test_state_estimation_engineer_core.py +231 -0
  163. package/roles/structures-loads-engineer/ROLE.md +171 -0
  164. package/roles/structures-loads-engineer/SOURCES.md +44 -0
  165. package/roles/structures-loads-engineer/cli.py +219 -0
  166. package/roles/structures-loads-engineer/core/structures_loads_core.py +1112 -0
  167. package/roles/structures-loads-engineer/templates/loads-strength-report-template.md +96 -0
  168. package/roles/structures-loads-engineer/tests/test_bundle_protocol.py +101 -0
  169. package/roles/structures-loads-engineer/tests/test_role_structures_loads_engineer.py +147 -0
  170. package/roles/structures-loads-engineer/tests/test_structures_loads_core.py +261 -0
@@ -0,0 +1,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()