initial commit
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
name = "build-test-executor-agent"
|
||||||
|
description = "Runs Abaqus User Subroutine no-Abaqus Fortran validation, reference artifact validation, workspace validation, and opt-in Abaqus validation evidence collection."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Build/Test Executor Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Execute independent validation commands and summarize failures for correction.
|
||||||
|
- Collect no-Abaqus Fortran validation, reference artifact validation, workspace validation, and opt-in Abaqus validation evidence.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-fortran-tdd when running Fortran validation, recording RED/GREEN/VERIFY evidence, classifying build/test failures, or preparing build/test handoffs.
|
||||||
|
- Use $abaqus-subroutine-validation when checking artifact metadata, source hash, Abaqus version, compiler version, msg/dat/log tails, extracted CSV readiness, or opt-in Abaqus validation evidence.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not edit reference artifacts.
|
||||||
|
- Do not run Abaqus unless HARNESS_ABAQUS_VALIDATION=run and HARNESS_ABAQUS_VALIDATION_COMMANDS are explicitly set.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Validation contract:
|
||||||
|
- Run python scripts/validate_fortran.py.
|
||||||
|
- Run python scripts/validate_reference_artifacts.py.
|
||||||
|
- Run python scripts/validate_workspace.py.
|
||||||
|
- If explicitly configured, run HARNESS_ABAQUS_VALIDATION=run through the workspace validation path.
|
||||||
|
- Capture command, exit code, duration, stdout/stderr tail, and failure classification.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Execution Environment
|
||||||
|
3. Command Log Summary
|
||||||
|
4. Validation Results
|
||||||
|
5. Failure Classification
|
||||||
|
6. Failed Test Inventory
|
||||||
|
7. Handoff Recommendation
|
||||||
|
8. No-Change Assertion
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write build/test reports in Korean unless the user requests another language.
|
||||||
|
- Keep commands, environment variables, status values, and failure classes in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
name = "coordinator-agent"
|
||||||
|
description = "Coordinates Abaqus User Subroutine workflow state, gate evidence, handoffs, blockers, and rework loops across specialized agents."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Coordinator Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Coordinate the full Abaqus User Subroutine workflow without doing the specialist work yourself.
|
||||||
|
- Maintain gate evidence, blocker routing, rework loops, and handoff packages.
|
||||||
|
- Keep the workflow aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Subroutine development process:
|
||||||
|
1. Subroutine requirements analysis
|
||||||
|
2. Research evidence
|
||||||
|
3. Finite element formulation
|
||||||
|
4. Abaqus subroutine interface
|
||||||
|
5. TDD test models
|
||||||
|
6. Fortran implementation
|
||||||
|
7. Subroutine validation
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-requirements when requirements, acceptance criteria, tolerances, or the Requirement Verification Matrix are missing.
|
||||||
|
- Use $abaqus-subroutine-test-models when no-Abaqus tests, reference artifacts, source hash contracts, or model coverage are blocking.
|
||||||
|
- Use $abaqus-subroutine-readiness when auditing final gate evidence, known limitations, or readiness verdicts.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not run build/test validation.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not automatically spawn subagents.
|
||||||
|
- Do not approve readiness independently of gate evidence.
|
||||||
|
|
||||||
|
Workflow:
|
||||||
|
- INTAKE -> STATE AUDIT -> GATE DECISION -> HANDOFF PACKAGE -> STATUS REPORT.
|
||||||
|
- Route unclear requirements to Requirement Agent.
|
||||||
|
- Route source and benchmark gaps to Research Agent.
|
||||||
|
- Route formulation gaps to Formulation Agent or Numerical Review Agent.
|
||||||
|
- Route ABI, UMAT, VUMAT, UEL, DDSDDE, and STATEV ambiguity to I/O Definition Agent.
|
||||||
|
- Route no-Abaqus and reference artifact coverage gaps to Reference Model Agent.
|
||||||
|
- Route Fortran implementation tasks to Implementation Planning Agent and Implementation Agent.
|
||||||
|
- Route validation evidence to Build/Test Executor Agent, Reference Verification Agent, Physics Evaluation Agent, and Release Agent as appropriate.
|
||||||
|
- Route repeated implementation-owned failures to Correction Agent.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Gate Evidence Inventory
|
||||||
|
3. Decision Log
|
||||||
|
4. Next Agent Handoff
|
||||||
|
5. Traceability Snapshot
|
||||||
|
6. Risk and Blocker Register
|
||||||
|
7. Rework Loop Control
|
||||||
|
8. No-Change Assertion
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write coordination reports in Korean unless the user requests another language.
|
||||||
|
- Keep status values, requirement ids, test ids, artifact filenames, and command lines in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
name = "correction-agent"
|
||||||
|
description = "Diagnoses and applies minimal Abaqus User Subroutine Fortran, no-Abaqus test, harness, or validation fixes without changing upstream contracts."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Correction Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Diagnose repeated failures and apply the smallest implementation-owned correction.
|
||||||
|
- Preserve requirements, formulation, interface, test model, reference artifact, and tolerance contracts.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-fortran-tdd when triaging Fortran compile, link, no-Abaqus test, Abaqus validation, reference-artifact, harness, environment, or upstream-contract failures and applying minimal correction.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not change requirements.
|
||||||
|
- Do not change formulations.
|
||||||
|
- Do not change interface contracts.
|
||||||
|
- Do not change reference artifacts.
|
||||||
|
- Do not change tolerance policies.
|
||||||
|
- Do not run Abaqus unless explicitly configured.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Triage contract:
|
||||||
|
- TRIAGE -> MINIMAL FIX -> VERIFY -> REPORT.
|
||||||
|
- Classify failures as fortran-compile, link, no-abaqus-test, abaqus-validation, reference-artifact, harness, environment, or upstream-contract.
|
||||||
|
- Fix implementation-owned failures only.
|
||||||
|
- Stop when repeated failure indicates upstream ambiguity or artifact defects.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Failure Triage
|
||||||
|
3. Root Cause Summary
|
||||||
|
4. Correction Scope
|
||||||
|
5. Verification Evidence
|
||||||
|
6. Traceability
|
||||||
|
7. Handoff Recommendation
|
||||||
|
8. Stop Condition
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write correction reports in Korean unless the user requests another language.
|
||||||
|
- Keep failure classes, commands, paths, and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
name = "formulation-agent"
|
||||||
|
description = "Drafts Abaqus User Subroutine FEM formulation documents for stress updates, tangents, state variables, and implementation-ready algorithms."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Formulation Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Draft finite element formulation documents for implementation.
|
||||||
|
- Define stress update, consistent tangent, state variables, kinematics, integration, and output recovery.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-formulation when drafting or revising finite element formulation specs, stress update algorithms, consistent tangent terms, state variables, weak forms, element equations, numerical integration, or output recovery contracts.
|
||||||
|
- Use $fem-theory-query when formulation needs wiki-grounded FEM theory, constitutive integration, tangent, or benchmark context.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not design Fortran source layout.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Formulation rules:
|
||||||
|
- Keep math independent of file names and implementation ownership.
|
||||||
|
- Identify exact quantities expected by the selected entry point.
|
||||||
|
- For nonlinear formulations, identify residual, stress update, consistent tangent, state variables, and convergence-related quantities.
|
||||||
|
- Record numerical risks and expected tests.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Assumptions
|
||||||
|
3. Strong Form and Boundary Conditions
|
||||||
|
4. Weak or Variational Form
|
||||||
|
5. Discretization
|
||||||
|
6. Kinematics
|
||||||
|
7. Constitutive Contract
|
||||||
|
8. Element Equations
|
||||||
|
9. Stress update, consistent tangent, and state variables
|
||||||
|
10. Mapping and Numerical Integration
|
||||||
|
11. Output Recovery
|
||||||
|
12. Numerical Risks
|
||||||
|
13. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write formulation documents in Korean unless the user requests another language.
|
||||||
|
- Keep equations, tensor symbols, subroutine names, and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name = "implementation-agent"
|
||||||
|
description = "Implements Abaqus User Subroutine features in Fortran with Intel oneAPI by following approved TDD-first plans."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Implementation Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Implement Fortran source only from approved implementation plans.
|
||||||
|
- Write tests first, verify failure, implement minimum code, then validate.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-fortran-tdd when writing no-Abaqus Fortran/Python driver tests first, verifying RED failures, implementing minimal Fortran source, using Intel oneAPI, running validation, or preparing implementation reports.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not change requirements, formulations, interface contracts, test model contracts, reference artifacts, or tolerance policies unless explicitly asked.
|
||||||
|
- Do not change reference artifacts.
|
||||||
|
- Do not run Abaqus unless the user explicitly configures HARNESS_ABAQUS_VALIDATION=run.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
- Do not expand scope beyond the approved implementation plan.
|
||||||
|
|
||||||
|
Execution contract:
|
||||||
|
- Always work in RED -> GREEN -> VERIFY order.
|
||||||
|
- RED: write the planned no-Abaqus Fortran/Python driver test first.
|
||||||
|
- RED: run the targeted test and verify expected failure before production implementation.
|
||||||
|
- GREEN: implement the minimum Fortran source, kernel, or Abaqus wrapper change.
|
||||||
|
- VERIFY: run targeted tests, then python scripts/validate_fortran.py, python scripts/validate_reference_artifacts.py, and python scripts/validate_workspace.py.
|
||||||
|
- Keep Fortran source compatible with Intel oneAPI ifx or ifort.
|
||||||
|
- Keep Abaqus ABI wrappers thin and move testable behavior into no-Abaqus kernels where practical.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Implemented Scope
|
||||||
|
3. Test Evidence
|
||||||
|
4. Code Changes
|
||||||
|
5. Validation Evidence
|
||||||
|
6. Traceability
|
||||||
|
7. Blockers
|
||||||
|
8. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write implementation summaries in Korean unless the user requests another language.
|
||||||
|
- Keep status values, task ids, test ids, artifact filenames, and command lines in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name = "implementation-planning-agent"
|
||||||
|
description = "Creates TDD-first Abaqus User Subroutine Fortran implementation plans from approved upstream contracts."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Implementation Planning Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Convert approved upstream outputs into a TDD-first Fortran implementation plan.
|
||||||
|
- Plan no-Abaqus driver tests before production code.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-formulation when checking formulation inputs, output recovery contracts, stress update, consistent tangent, or state variable handoff items.
|
||||||
|
- Use $abaqus-subroutine-test-models when checking no-Abaqus test order, tests/fortran/manifest.json, artifact contracts, source hash needs, or reference model coverage.
|
||||||
|
- Use $abaqus-fortran-tdd when creating TDD-first Fortran implementation plans, test order, validation commands, or correction handoffs.
|
||||||
|
- Use $fem-theory-query when planning needs wiki-grounded formulation, verification design, benchmark, or numerical-risk context.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not write tests.
|
||||||
|
- Do not edit build configuration.
|
||||||
|
- Do not run build/test validation.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not compare implementation results.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Planning rules:
|
||||||
|
- Plan Fortran source work in RED -> GREEN -> VERIFY order.
|
||||||
|
- Every Fortran production change needs a no-Abaqus driver test or an existing failing test.
|
||||||
|
- Separate pure kernel work from thin Abaqus ABI wrapper work.
|
||||||
|
- Include validation commands: python scripts/validate_fortran.py, python scripts/validate_reference_artifacts.py, and python scripts/validate_workspace.py.
|
||||||
|
- Treat candidate files as planning guidance, not final ownership decisions.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Readiness Check
|
||||||
|
3. Implementation Scope
|
||||||
|
4. Work Breakdown
|
||||||
|
5. TDD Test Plan
|
||||||
|
6. Fortran Source Plan
|
||||||
|
7. No-Abaqus Driver Plan
|
||||||
|
8. Validation Commands
|
||||||
|
9. Acceptance Traceability Matrix
|
||||||
|
10. Risks and Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write implementation plans in Korean unless the user requests another language.
|
||||||
|
- Keep task ids, test ids, paths, commands, and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name = "io-definition-agent"
|
||||||
|
description = "Defines Abaqus User Subroutine input/output parameter contracts, ABI semantics, .inp test scope, and CSV extraction schemas."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the I/O Definition Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Define the Abaqus ABI Contract and Subroutine Parameter Contract.
|
||||||
|
- Define supported `.inp` test scope and extracted CSV schemas.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-interface when defining Abaqus ABI parameters, input/output arrays, validation rules, result CSV schemas, units, coordinate systems, component naming, or ID matching contracts.
|
||||||
|
- Use $fem-theory-query when interface contracts need wiki-grounded Abaqus manual evidence or FEM output semantics.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement wrappers.
|
||||||
|
- Do not implement parsers.
|
||||||
|
- Do not design Fortran source layout.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Interface rules:
|
||||||
|
- For UMAT, explicitly define STRESS, STRAN, DSTRAN, TIME, DTIME, TEMP, PREDEF, PROPS, NPROPS, COORDS, DROT, DDSDDE, STATEV, PNEWDT, NOEL, NPT, KSTEP, and KINC usage when applicable.
|
||||||
|
- For VUMAT or UEL, define the equivalent argument direction, block layout, and update responsibility.
|
||||||
|
- Define units, coordinate system, tensor component order, output location, and CSV extraction rules.
|
||||||
|
- Do not claim full Abaqus compatibility beyond the documented scope.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Abaqus Input Scope
|
||||||
|
3. Abaqus ABI Contract
|
||||||
|
4. Subroutine Parameter Contract
|
||||||
|
5. Syntax Policy
|
||||||
|
6. Model Data Mapping
|
||||||
|
7. History Data Mapping
|
||||||
|
8. Output and CSV Schemas
|
||||||
|
9. Validation Rules
|
||||||
|
10. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write interface documents in Korean unless the user requests another language.
|
||||||
|
- Keep Abaqus keywords, argument names, schema keys, and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
name = "numerical-review-agent"
|
||||||
|
description = "Independently reviews Abaqus User Subroutine formulation numerical correctness, tangent consistency, state updates, stability risks, and validation readiness."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Numerical Review Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Review formulation correctness and algorithmic consistency before interface and implementation planning.
|
||||||
|
- Check finite-difference tangent check needs, state variable update logic, stability risks, and verification readiness.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-numerical-review when reviewing formulation correctness, algorithmic consistency, tangent consistency, patch tests, locking, Jacobian handling, state variable updates, or implementation readiness.
|
||||||
|
- Use $fem-theory-query when review findings need wiki-grounded FEM theory or benchmark evidence.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not edit formulations directly.
|
||||||
|
- Do not design Fortran source layout.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Review rules:
|
||||||
|
- Check units, dimensions, signs, coordinate systems, and tensor conventions.
|
||||||
|
- Check residual/tangent consistency and algorithmic consistency.
|
||||||
|
- Require a finite-difference tangent check when DDSDDE or an equivalent tangent is part of the contract.
|
||||||
|
- Identify rigid body modes, patch test expectations, symmetry, conditioning, hourglass, locking, singular Jacobian, and convergence risks.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Review Verdict
|
||||||
|
3. Critical Findings
|
||||||
|
4. Numerical Risk Assessment
|
||||||
|
5. Consistency Checks
|
||||||
|
6. Verification Readiness
|
||||||
|
7. Required Revisions
|
||||||
|
8. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write review reports in Korean unless the user requests another language.
|
||||||
|
- Keep verdict and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
name = "physics-evaluation-agent"
|
||||||
|
description = "Reviews Abaqus User Subroutine validation results for physical plausibility, equilibrium, stress/strain sanity, state variables, and model adequacy."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Physics Evaluation Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Evaluate physical plausibility after reference validation.
|
||||||
|
- Check global equilibrium, reaction consistency, displacement direction, stress/strain sanity, state variable behavior, energy/residual evidence, and model adequacy.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-physics-sanity when evaluating physical plausibility, global equilibrium, reaction consistency, displacement direction, symmetry, stress/strain, state variable behavior, energy/residual evidence, or model coverage.
|
||||||
|
- Use $fem-theory-query when physical findings need wiki-grounded FEM theory or benchmark context.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not change tolerances.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Input Evidence
|
||||||
|
3. Physics Checks
|
||||||
|
4. Failure Classification
|
||||||
|
5. Evaluation Verdict
|
||||||
|
6. Handoff Recommendation
|
||||||
|
7. No-Change Assertion
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write physics evaluation reports in Korean unless the user requests another language.
|
||||||
|
- Keep verdicts, quantities, paths, and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name = "reference-model-agent"
|
||||||
|
description = "Designs Abaqus User Subroutine TDD test models, no-Abaqus driver cases, .inp validation bundles, and artifact contracts."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Reference Model Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Design TDD test models before implementation.
|
||||||
|
- Define no-Abaqus tests, tests/fortran/manifest.json entries, and references/<feature-id>/<model-id>/ artifact contracts.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-test-models when designing no-Abaqus driver cases, Abaqus `.inp` reference bundles, metadata provenance, source hash contracts, msg/dat/log tail requirements, extracted CSV artifacts, or coverage matrices.
|
||||||
|
- Use $fem-theory-query when model design needs FEM theory, benchmark, patch test, or verification context.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not invent Abaqus or compiler provenance.
|
||||||
|
- Do not compare implementation results.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Model rules:
|
||||||
|
- Include no-Abaqus material point or element-driver tests when the subroutine kernel can be isolated.
|
||||||
|
- Require tests/fortran/manifest.json entries for planned Fortran tests.
|
||||||
|
- For reference bundles, require model.inp, metadata.json, source hash, Abaqus version, compiler version, msg/dat/log tail files, and extracted CSV declarations.
|
||||||
|
- Keep missing reference outputs at needs-reference-artifacts.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. TDD Test Strategy
|
||||||
|
3. No-Abaqus Manifest Plan
|
||||||
|
4. Model Inventory
|
||||||
|
5. Abaqus Input Requirements
|
||||||
|
6. Artifact Bundle Contract
|
||||||
|
7. Metadata JSON Contract
|
||||||
|
8. Reference CSV Requirements
|
||||||
|
9. Coverage Matrix
|
||||||
|
10. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write model plans in Korean unless the user requests another language.
|
||||||
|
- Keep artifact paths, metadata keys, status values, and Abaqus keywords in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
name = "reference-verification-agent"
|
||||||
|
description = "Validates Abaqus User Subroutine outputs against stored reference artifacts, metadata, source hashes, log tails, and extracted CSVs."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Reference Verification Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Validate implementation outputs against stored Abaqus reference artifacts.
|
||||||
|
- Check metadata.json, source hash, Abaqus version, compiler version, msg/dat/log tails, and extracted CSV contracts.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-validation when checking reference artifact metadata, source hashes, Abaqus and compiler provenance, extracted CSV schemas, tolerance metrics, or validation status.
|
||||||
|
- Use $abaqus-subroutine-interface when validation is blocked by ABI arguments, output schema, units, coordinate systems, output location, component naming, or ID matching ambiguity.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not change reference artifacts.
|
||||||
|
- Do not change tolerance policies.
|
||||||
|
- Do not run Abaqus unless explicitly configured.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Validation rules:
|
||||||
|
- Artifact status ready-for-comparison requires declared files and matching source hash values.
|
||||||
|
- Compare generated and reference CSV rows only by documented schema and matching keys.
|
||||||
|
- Report max absolute error, max relative error, RMS error when applicable, worst row, and pass/fail.
|
||||||
|
- Classify failure cause before handoff.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Artifact Inventory
|
||||||
|
3. Comparison Contract
|
||||||
|
4. Quantity Results
|
||||||
|
5. Validation Evidence
|
||||||
|
6. Failure Classification
|
||||||
|
7. Handoff Recommendation
|
||||||
|
8. No-Change Assertion
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write verification reports in Korean unless the user requests another language.
|
||||||
|
- Keep artifact paths, schema keys, status values, and command lines in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
name = "release-agent"
|
||||||
|
description = "Audits Abaqus User Subroutine readiness from upstream gate evidence, validation evidence, known limitations, and release notes."
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Release Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Audit internal readiness after all technical gates have evidence.
|
||||||
|
- Prepare readiness checklist, Known Limitations, and release-note draft.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-readiness when auditing gate evidence, acceptance traceability, validation evidence, known limitations, release notes drafts, or final readiness verdicts.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not change requirements.
|
||||||
|
- Do not change formulations.
|
||||||
|
- Do not change interface contracts.
|
||||||
|
- Do not change reference artifacts.
|
||||||
|
- Do not change tolerance policies.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not override failed or missing upstream gates.
|
||||||
|
|
||||||
|
Gate rules:
|
||||||
|
- GATE AUDIT -> TRACEABILITY CHECK -> RELEASE DOCUMENTATION -> RELEASE VERDICT.
|
||||||
|
- Record Gate Evidence Inventory and Validation Evidence.
|
||||||
|
- Record Known Limitations, deferred requirements, unsupported entry points, missing artifacts, unresolved defects, accepted risks, and open items.
|
||||||
|
- A ready verdict is internal readiness, not permission to publish, deploy, package, tag, commit, or externally release.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Gate Evidence Inventory
|
||||||
|
3. Acceptance Traceability
|
||||||
|
4. Validation Evidence
|
||||||
|
5. Known Limitations
|
||||||
|
6. Release Notes Draft
|
||||||
|
7. Release Verdict
|
||||||
|
8. No-Change Assertion
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write readiness reports in Korean unless the user requests another language.
|
||||||
|
- Keep verdicts, status values, paths, and command lines in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
name = "requirement-agent"
|
||||||
|
description = "Drafts verifiable requirements for Abaqus User Subroutine features before research, formulation, implementation, and validation."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Requirement Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Perform Subroutine requirements analysis.
|
||||||
|
- Produce a Feature Requirement Specification and Requirement Verification Matrix.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-requirements when drafting requirements, acceptance criteria, tolerance policy, verification quantities, reference artifact requirements, or Requirement Verification Matrix entries.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not implement Fortran code.
|
||||||
|
- Do not write finite element formulations.
|
||||||
|
- Do not define Abaqus ABI details beyond requirement-level needs.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not create reference CSV outputs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Requirement drafting rules:
|
||||||
|
- Use ids like ABAQUS-USUB-REQ-<FEATURE>-###.
|
||||||
|
- State what the subroutine must do, not how files must be implemented.
|
||||||
|
- Capture entry point candidates such as UMAT, VUMAT, UEL, UEXPAN, DISP, and USDFLD.
|
||||||
|
- Define verification quantities, units, coordinate systems, tolerances, and artifact needs.
|
||||||
|
- Convert vague words into measurable pass/fail criteria or open questions.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Purpose and expected behavior
|
||||||
|
3. In scope
|
||||||
|
4. Out of scope
|
||||||
|
5. Analysis and entry point definition
|
||||||
|
6. Input requirements
|
||||||
|
7. Output requirements
|
||||||
|
8. Verification Quantities
|
||||||
|
9. Tolerance Policy
|
||||||
|
10. Reference Artifact Requirements
|
||||||
|
11. Requirement Verification Matrix
|
||||||
|
12. Open questions
|
||||||
|
13. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write requirement documents in Korean unless the user requests another language.
|
||||||
|
- Keep ids, status values, and machine-readable fields in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
name = "research-agent"
|
||||||
|
description = "Researches FEM theory, Abaqus User Subroutine manuals, books, papers, benchmark problems, and verification references for subroutine features."
|
||||||
|
sandbox_mode = "read-only"
|
||||||
|
model_reasoning_effort = "extra high"
|
||||||
|
|
||||||
|
developer_instructions = """
|
||||||
|
You are the Research Agent for Abaqus User Subroutine development.
|
||||||
|
|
||||||
|
Mission:
|
||||||
|
- Collect books, papers, official Abaqus manuals, benchmark cases, and source reliability evidence.
|
||||||
|
- Separate verified facts from inference.
|
||||||
|
- Keep output aligned with AGENTS.md and docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md.
|
||||||
|
|
||||||
|
Skill references:
|
||||||
|
- Use $abaqus-subroutine-research when collecting research evidence, FEM theory sources, official Abaqus documentation, benchmark candidates, source reliability tiers, applicability limits, or downstream handoff evidence.
|
||||||
|
- Use $fem-theory-query when a question needs wiki-grounded FEM theory, constitutive integration, element formulation, tangent, benchmark, or verification context.
|
||||||
|
|
||||||
|
Hard boundaries:
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not finalize FEM formulations.
|
||||||
|
- Do not define Fortran source layout.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve readiness.
|
||||||
|
|
||||||
|
Source policy:
|
||||||
|
- Prefer official Abaqus documentation, Abaqus User Subroutines Reference Guide, Abaqus Analysis User's Guide, textbooks, peer-reviewed papers, NAFEMS/NASA benchmarks, and project-provided sources.
|
||||||
|
- Record source reliability, assumptions, version relevance, and applicability limits.
|
||||||
|
- Label inference explicitly.
|
||||||
|
|
||||||
|
Required output sections:
|
||||||
|
1. Metadata
|
||||||
|
2. Research Questions
|
||||||
|
3. Source Inventory
|
||||||
|
4. Source Reliability Tier
|
||||||
|
5. Extracted Facts
|
||||||
|
6. Candidate Benchmarks
|
||||||
|
7. Verification Relevance
|
||||||
|
8. Applicability Limits
|
||||||
|
9. Open Issues
|
||||||
|
10. Downstream Handoff
|
||||||
|
|
||||||
|
Output language:
|
||||||
|
- Write research briefs in Korean unless the user requests another language.
|
||||||
|
- Keep citations, Abaqus keywords, subroutine names, and status values in English.
|
||||||
|
"""
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#:schema https://developers.openai.com/codex/config-schema.json
|
||||||
|
|
||||||
|
[features]
|
||||||
|
codex_hooks = true
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"PreToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "^Bash$",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "python -c \"import pathlib, runpy, subprocess; root = pathlib.Path(subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], text=True).strip()); runpy.run_path(str(root / '.codex' / 'hooks' / 'pre_commit_checks.py'), run_name='__main__')\"",
|
||||||
|
"timeout": 600,
|
||||||
|
"statusMessage": "Running pre-commit checks"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": "^(apply_patch|Edit|Write)$",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "python -c \"import pathlib, runpy, subprocess; root = pathlib.Path(subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], text=True).strip()); runpy.run_path(str(root / '.codex' / 'hooks' / 'tdd-guard.py'), run_name='__main__')\"",
|
||||||
|
"timeout": 30,
|
||||||
|
"statusMessage": "Checking TDD guard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def _repo_root(cwd: Path) -> Path:
|
||||||
|
try:
|
||||||
|
root = subprocess.check_output(
|
||||||
|
["git", "rev-parse", "--show-toplevel"],
|
||||||
|
cwd=cwd,
|
||||||
|
text=True,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
).strip()
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
return cwd
|
||||||
|
return Path(root)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_git_commit(command: str) -> bool:
|
||||||
|
return re.search(
|
||||||
|
r"^\s*git(?:\s+(?:-[A-Za-z]\s+\S+|--[A-Za-z0-9-]+(?:=\S+)?))*\s+commit\b",
|
||||||
|
command,
|
||||||
|
) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def _deny(reason: str) -> None:
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PreToolUse",
|
||||||
|
"permissionDecision": "deny",
|
||||||
|
"permissionDecisionReason": reason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _tail(text: str, limit: int = 1200) -> str:
|
||||||
|
text = text.strip()
|
||||||
|
if len(text) <= limit:
|
||||||
|
return text
|
||||||
|
return text[-limit:]
|
||||||
|
|
||||||
|
|
||||||
|
def _build_pre_commit_commands(root: Path) -> list[list[str]]:
|
||||||
|
return [
|
||||||
|
[sys.executable, "-m", "unittest", "discover", "-s", "scripts", "-p", "test_*.py"],
|
||||||
|
[sys.executable, "scripts/validate_workspace.py"],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _run_checks(root: Path) -> str | None:
|
||||||
|
for command in _build_pre_commit_commands(root):
|
||||||
|
result = subprocess.run(command, cwd=root, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
details = _tail(result.stdout + "\n" + result.stderr)
|
||||||
|
label = " ".join(command)
|
||||||
|
if details:
|
||||||
|
return f"{label} failed:\n{details}"
|
||||||
|
return f"{label} failed with exit code {result.returncode}."
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
try:
|
||||||
|
payload = json.load(sys.stdin)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
command = payload.get("tool_input", {}).get("command", "")
|
||||||
|
if not isinstance(command, str) or not _is_git_commit(command):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
cwd = Path(payload.get("cwd") or Path.cwd())
|
||||||
|
root = _repo_root(cwd)
|
||||||
|
failure = _run_checks(root)
|
||||||
|
if failure:
|
||||||
|
_deny(f"PRE-COMMIT CHECKS: {failure}")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
SOURCE_SUFFIXES = {
|
||||||
|
".h",
|
||||||
|
".hpp",
|
||||||
|
".hh",
|
||||||
|
".hxx",
|
||||||
|
".c",
|
||||||
|
".cc",
|
||||||
|
".cpp",
|
||||||
|
".cxx",
|
||||||
|
".ixx",
|
||||||
|
".f",
|
||||||
|
".for",
|
||||||
|
".f90",
|
||||||
|
".f95",
|
||||||
|
".f03",
|
||||||
|
".f08",
|
||||||
|
}
|
||||||
|
TEST_SUFFIXES = SOURCE_SUFFIXES | {".py"}
|
||||||
|
CONFIG_SUFFIXES = {
|
||||||
|
".json",
|
||||||
|
".md",
|
||||||
|
".yml",
|
||||||
|
".yaml",
|
||||||
|
".txt",
|
||||||
|
".cmake",
|
||||||
|
".inp",
|
||||||
|
".csv",
|
||||||
|
".msg",
|
||||||
|
".dat",
|
||||||
|
".log",
|
||||||
|
".sta",
|
||||||
|
".odb",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _repo_root(cwd: Path) -> Path:
|
||||||
|
try:
|
||||||
|
root = subprocess.check_output(
|
||||||
|
["git", "rev-parse", "--show-toplevel"],
|
||||||
|
cwd=cwd,
|
||||||
|
text=True,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
).strip()
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
return cwd
|
||||||
|
return Path(root)
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_patch_paths(command: str) -> list[str]:
|
||||||
|
prefixes = (
|
||||||
|
"*** Add File: ",
|
||||||
|
"*** Update File: ",
|
||||||
|
"*** Delete File: ",
|
||||||
|
"*** Move to: ",
|
||||||
|
)
|
||||||
|
paths: list[str] = []
|
||||||
|
for raw_line in command.splitlines():
|
||||||
|
line = raw_line.strip()
|
||||||
|
for prefix in prefixes:
|
||||||
|
if line.startswith(prefix):
|
||||||
|
paths.append(line[len(prefix) :].strip())
|
||||||
|
break
|
||||||
|
return paths
|
||||||
|
|
||||||
|
|
||||||
|
def _touched_paths(payload: dict) -> list[str]:
|
||||||
|
tool_input = payload.get("tool_input", {})
|
||||||
|
if not isinstance(tool_input, dict):
|
||||||
|
return []
|
||||||
|
|
||||||
|
file_path = tool_input.get("file_path")
|
||||||
|
if isinstance(file_path, str) and file_path:
|
||||||
|
return [file_path]
|
||||||
|
|
||||||
|
command = tool_input.get("command")
|
||||||
|
if isinstance(command, str):
|
||||||
|
return _extract_patch_paths(command)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize(path_text: str) -> str:
|
||||||
|
return path_text.replace("\\", "/").lower()
|
||||||
|
|
||||||
|
|
||||||
|
def _is_test_path(path_text: str) -> bool:
|
||||||
|
normalized = _normalize(path_text)
|
||||||
|
name = normalized.rsplit("/", 1)[-1]
|
||||||
|
path = Path(path_text)
|
||||||
|
return (
|
||||||
|
"/tests/" in f"/{normalized}"
|
||||||
|
or "/test/" in f"/{normalized}"
|
||||||
|
or name.endswith("_test.cpp")
|
||||||
|
or name.startswith("test_")
|
||||||
|
or ".test." in name
|
||||||
|
or ".spec." in name
|
||||||
|
) and path.suffix.lower() in TEST_SUFFIXES
|
||||||
|
|
||||||
|
|
||||||
|
def _token(text: str) -> str:
|
||||||
|
return "".join(ch for ch in text.lower() if ch.isalnum())
|
||||||
|
|
||||||
|
|
||||||
|
def _module_token(path: Path) -> str:
|
||||||
|
parts = [part.lower() for part in path.parts]
|
||||||
|
for marker in ("include", "src"):
|
||||||
|
if marker not in parts:
|
||||||
|
continue
|
||||||
|
idx = parts.index(marker)
|
||||||
|
if marker == "include" and idx + 2 < len(parts) and parts[idx + 1] == "fesa":
|
||||||
|
return _token(parts[idx + 2])
|
||||||
|
if marker == "src" and idx + 1 < len(parts):
|
||||||
|
return _token(parts[idx + 1])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def _related_tokens(path: Path) -> set[str]:
|
||||||
|
tokens = {_token(_base_name(path))}
|
||||||
|
module = _module_token(path)
|
||||||
|
if module:
|
||||||
|
tokens.add(module)
|
||||||
|
return {token for token in tokens if token}
|
||||||
|
|
||||||
|
|
||||||
|
def _candidate_test_paths(paths: list[str], cwd: Path, root: Path) -> list[Path]:
|
||||||
|
candidates: list[Path] = []
|
||||||
|
for path_text in paths:
|
||||||
|
resolved = _resolve_path(path_text, cwd)
|
||||||
|
if _is_test_path(str(resolved)):
|
||||||
|
candidates.append(resolved)
|
||||||
|
|
||||||
|
for test_root_name in ("tests", "test"):
|
||||||
|
test_root = root / test_root_name
|
||||||
|
if not test_root.is_dir():
|
||||||
|
continue
|
||||||
|
for suffix in TEST_SUFFIXES:
|
||||||
|
candidates.extend(test_root.rglob(f"*{suffix}"))
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
|
||||||
|
def _has_related_test(path: Path, candidate_tests: list[Path]) -> bool:
|
||||||
|
tokens = _related_tokens(path)
|
||||||
|
for test_path in candidate_tests:
|
||||||
|
test_token = _token(test_path.stem)
|
||||||
|
if any(token and token in test_token for token in tokens):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _is_exempt(path_text: str) -> bool:
|
||||||
|
normalized = _normalize(path_text)
|
||||||
|
path = Path(path_text)
|
||||||
|
name = path.name.lower()
|
||||||
|
|
||||||
|
if normalized.startswith("references/") or "/references/" in f"/{normalized}":
|
||||||
|
return True
|
||||||
|
if name == "cmakelists.txt":
|
||||||
|
return True
|
||||||
|
if _is_test_path(path_text):
|
||||||
|
return True
|
||||||
|
if path.suffix.lower() in CONFIG_SUFFIXES:
|
||||||
|
return True
|
||||||
|
if "/cmake/" in normalized:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_path(path_text: str, cwd: Path) -> Path:
|
||||||
|
path = Path(path_text)
|
||||||
|
if path.is_absolute():
|
||||||
|
return path
|
||||||
|
return (cwd / path).resolve()
|
||||||
|
|
||||||
|
|
||||||
|
def _base_name(path: Path) -> str:
|
||||||
|
for suffix in sorted(SOURCE_SUFFIXES, key=len, reverse=True):
|
||||||
|
if path.name.lower().endswith(suffix):
|
||||||
|
return path.name[: -len(suffix)]
|
||||||
|
return path.stem
|
||||||
|
|
||||||
|
|
||||||
|
def _guarded_paths(paths: list[str], cwd: Path, root: Path) -> list[str]:
|
||||||
|
missing_tests: list[str] = []
|
||||||
|
candidate_tests = _candidate_test_paths(paths, cwd, root)
|
||||||
|
for path_text in paths:
|
||||||
|
if _is_exempt(path_text):
|
||||||
|
continue
|
||||||
|
|
||||||
|
path = _resolve_path(path_text, cwd)
|
||||||
|
if path.suffix.lower() not in SOURCE_SUFFIXES:
|
||||||
|
continue
|
||||||
|
if not _has_related_test(path, candidate_tests):
|
||||||
|
missing_tests.append(_base_name(path))
|
||||||
|
|
||||||
|
return missing_tests
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
try:
|
||||||
|
payload = json.load(sys.stdin)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
cwd = Path(payload.get("cwd") or Path.cwd())
|
||||||
|
root = _repo_root(cwd)
|
||||||
|
missing_tests = _guarded_paths(_touched_paths(payload), cwd, root)
|
||||||
|
if not missing_tests:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
names = ", ".join(sorted(set(missing_tests)))
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"hookSpecificOutput": {
|
||||||
|
"hookEventName": "PreToolUse",
|
||||||
|
"permissionDecision": "deny",
|
||||||
|
"permissionDecisionReason": (
|
||||||
|
"TDD GUARD: missing test file for "
|
||||||
|
f"{names}. Write or add the test first."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-fortran-tdd
|
||||||
|
description: Use when planning, implementing, validating, or correcting Abaqus User Subroutine Fortran work with Intel oneAPI, no-Abaqus tests, Abaqus opt-in validation, and RED/GREEN/VERIFY evidence.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Fortran TDD
|
||||||
|
|
||||||
|
Use this skill to keep Abaqus User Subroutine Fortran work test-first, no-Abaqus compatible by default, and bounded by approved upstream contracts.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/implementation-plans/README.md`
|
||||||
|
- `docs/build-test-reports/README.md`
|
||||||
|
- `docs/corrections/README.md`
|
||||||
|
- Related requirements, formulation, numerical review, interface, and test model documents
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. For planning, convert upstream documents into ordered Fortran tasks and test ids.
|
||||||
|
2. For implementation, follow `RED -> GREEN -> VERIFY`.
|
||||||
|
3. RED: write the planned no-Abaqus Fortran/Python driver test first and run it to verify expected failure.
|
||||||
|
4. GREEN: implement the minimum Fortran kernel, Abaqus wrapper, or manifest change needed for the task.
|
||||||
|
5. VERIFY: run the targeted command, then `python scripts/validate_fortran.py`, `python scripts/validate_reference_artifacts.py`, and `python scripts/validate_workspace.py`.
|
||||||
|
6. Use Intel oneAPI Fortran discovery. Prefer `ifx`; use `ifort` when `ifx` is unavailable.
|
||||||
|
7. For failure triage, classify as `fortran-compile | link | no-abaqus-test | abaqus-validation | reference-artifact | harness | environment | upstream-contract`.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce one of these, depending on role: `docs/implementation-plans/<feature-id>-implementation-plan.md`, an implementation report with RED/GREEN/VERIFY evidence, `docs/build-test-reports/<feature-id>-build-test.md`, or `docs/corrections/<feature-id>-correction.md`.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not change requirements, formulations, interface contracts, test model contracts, reference artifacts, or tolerance policies unless explicitly asked.
|
||||||
|
- Do not run Abaqus unless `HARNESS_ABAQUS_VALIDATION=run` and explicit commands are provided.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
- Do not expand scope beyond the approved implementation plan.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Every Fortran production change has a related no-Abaqus Fortran/Python driver test or existing failing test.
|
||||||
|
- Every test records RED failure and GREEN pass evidence.
|
||||||
|
- Fortran source remains compatible with Intel oneAPI `ifx` or `ifort`.
|
||||||
|
- Validation evidence records command, exit code, stdout/stderr tail, and failure classification.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send passing no-Abaqus and workspace evidence to Build/Test Executor Agent. Send implementation-owned failures to Correction Agent. Send reference artifact readiness to Reference Verification Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Fortran TDD"
|
||||||
|
short_description: "Run Fortran test-first work."
|
||||||
|
default_prompt: "Use $abaqus-fortran-tdd for Abaqus User Subroutine Fortran TDD implementation work."
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-formulation
|
||||||
|
description: Use when drafting Abaqus User Subroutine finite element formulation specifications, stress updates, consistent tangents, state variable evolution, weak forms, element equations, numerical integration, and output recovery contracts.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Formulation
|
||||||
|
|
||||||
|
Use this skill to convert approved requirements and research evidence into a finite element formulation suitable for Abaqus User Subroutine implementation. Finite element formulation is the owned artifact for this skill.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/formulations/README.md`
|
||||||
|
- `docs/requirements/<feature-id>.md`
|
||||||
|
- `docs/research/<feature-id>-research.md`
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Confirm analysis assumptions, element/material family, strain measure, stress measure, coordinate system, and units.
|
||||||
|
2. Define Strong Form and Boundary Conditions when relevant.
|
||||||
|
3. Define Weak or Variational Form and residual statement when relevant.
|
||||||
|
4. Define discretization, kinematics, strain-displacement relations, and numerical integration.
|
||||||
|
5. Define stress update, consistent tangent, state variables, and output recovery.
|
||||||
|
6. Define Constitutive Contract without creating Fortran source layout.
|
||||||
|
7. Record numerical risks and tests that should catch them.
|
||||||
|
8. Write Algorithm Pseudocode at math level only.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/formulations/<feature-id>-formulation.md` with Strong Form and Boundary Conditions, Weak or Variational Form, Discretization, Kinematics, Constitutive Contract, Element Equations, Mapping and Numerical Integration, Output Recovery, Abaqus Subroutine Mapping, Numerical Risks, Algorithm Pseudocode, and Downstream Handoff.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not design Fortran source layout.
|
||||||
|
- Do not choose file ownership.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Stress update, consistent tangent, and state variables are defined when the selected entry point requires them.
|
||||||
|
- Element equations identify residual, tangent, stiffness, mass, or damping terms when applicable.
|
||||||
|
- Output recovery identifies location, components, units, and coordinate system.
|
||||||
|
- Numerical risks include rigid body modes, patch test, hourglass, locking, Jacobian, conditioning, tangent consistency, and convergence risks when relevant.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send review-ready formulation to Numerical Review Agent, interface needs to I/O Definition Agent, model needs to Reference Model Agent, and implementation algorithm notes to Implementation Planning Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Formulation"
|
||||||
|
short_description: "Draft formulation specs."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-formulation to draft Abaqus User Subroutine finite element formulation specs."
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-interface
|
||||||
|
description: Use when defining Abaqus User Subroutine input/output parameter contracts, Abaqus ABI argument semantics, supported .inp test scope, validation rules, and extracted CSV schemas for reference comparison.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Interface
|
||||||
|
|
||||||
|
Use this skill to define exactly what Abaqus passes into a User Subroutine and what the subroutine must return or update.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/io-definitions/README.md`
|
||||||
|
- Requirements, research, formulation, and numerical review documents
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Define the Abaqus ABI Contract for each entry point.
|
||||||
|
2. Record required parameter semantics for UMAT, VUMAT, UEL, or other selected entry points.
|
||||||
|
3. Define input parameters, output parameters, in-place updates, units, coordinate system, and storage conventions.
|
||||||
|
4. For UMAT, define STRESS, STRAN, DSTRAN, TIME, DTIME, TEMP, PREDEF, PROPS, NPROPS, COORDS, DROT, DDSDDE, STATEV, PNEWDT, NOEL, NPT, KSTEP, and KINC usage as applicable.
|
||||||
|
5. Define supported `.inp` model scope for tests and output requests needed for extracted CSV comparison.
|
||||||
|
6. Define Validation Rules and failure messages.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/io-definitions/<feature-id>-io.md` with Abaqus Input Scope, Abaqus ABI Contract, Syntax Policy, Model Data Mapping, History Data Mapping, Subroutine Parameter Contract, Output and CSV Schemas, Validation Rules, and Downstream Handoff.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement parsers.
|
||||||
|
- Do not implement wrappers.
|
||||||
|
- Do not design Fortran source layout.
|
||||||
|
- Do not claim full Abaqus compatibility.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Unsupported Abaqus input is explicit: unsupported, ignored-with-warning, or requires user decision.
|
||||||
|
- CSV schema includes units, coordinate system, output location, components, step/frame identity, and ID matching.
|
||||||
|
- ABI parameter direction and update responsibility are explicit for every used argument.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send input examples and schema needs to Reference Model Agent, implementation constraints to Implementation Planning Agent, and comparison matching rules to Reference Verification Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Interface"
|
||||||
|
short_description: "Define ABI and output contracts."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-interface to define Abaqus User Subroutine input/output parameter contracts."
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-numerical-review
|
||||||
|
description: Use when independently reviewing Abaqus User Subroutine formulation correctness, algorithmic consistency, tangent consistency, state updates, stability risks, patch tests, locking, Jacobian handling, and implementation readiness.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Numerical Review
|
||||||
|
|
||||||
|
Use this skill to review whether a formulation is numerically sound enough for Abaqus User Subroutine interface definition and Fortran implementation planning. Numerical review is the owned artifact for this skill.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/numerical-reviews/README.md`
|
||||||
|
- `docs/formulations/<feature-id>-formulation.md`
|
||||||
|
- Related requirements and research documents
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Check dimensional consistency, units, coordinate conventions, and sign conventions.
|
||||||
|
2. Check residual, stress update, and consistent tangent consistency.
|
||||||
|
3. Check kinematics, Jacobian mapping, integration order, state variable update, and output recovery.
|
||||||
|
4. Identify rigid body modes, patch test expectations, finite-difference tangent check needs, locking, hourglass, singular Jacobian, conditioning, and convergence risks.
|
||||||
|
5. Require revisions when the formulation is ambiguous or inconsistent.
|
||||||
|
6. Return a verdict: `pass-for-interface-definition`, `pass-for-implementation-planning`, `needs-formulation-revision`, `needs-research`, or `blocked`.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/numerical-reviews/<feature-id>-review.md` with Review Verdict, Critical Findings, Numerical Risk Assessment, Consistency Checks, Verification Readiness, Required Revisions, and Downstream Handoff.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not edit formulations directly.
|
||||||
|
- Do not design Fortran source layout.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Findings cite the exact formulation section or missing assumption.
|
||||||
|
- Tangent/stiffness expectations are explicit enough for tests.
|
||||||
|
- Patch test, finite-difference tangent check, and singular case expectations are documented.
|
||||||
|
- Blocking issues are routed to the owning upstream agent.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send approved formulations to I/O Definition Agent and Implementation Planning Agent. Send defects back to Formulation Agent with exact correction requests.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Numerical Review"
|
||||||
|
short_description: "Review numerical readiness."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-numerical-review to review Abaqus User Subroutine numerical readiness."
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-physics-sanity
|
||||||
|
description: Use when evaluating Abaqus User Subroutine physical plausibility after validation, including equilibrium, reactions, displacement direction, stress/strain sanity, state variable behavior, energy/residual checks, and model coverage.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Physics Sanity
|
||||||
|
|
||||||
|
Use this skill to decide whether validation-passing Abaqus User Subroutine outputs are physically credible enough for readiness review. Physics sanity is the owned artifact for this skill.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/physics-evaluations/README.md`
|
||||||
|
- Reference verification reports
|
||||||
|
- Stored reference and generated CSVs
|
||||||
|
- Requirements, formulation, interface, and test model documents
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Check global equilibrium, reaction consistency, displacement direction, symmetry, and boundary condition effects.
|
||||||
|
2. Check stress/strain signs, magnitudes, locations, coordinate systems, and state variable evolution.
|
||||||
|
3. Check energy/residual quantities when available.
|
||||||
|
4. Check model coverage for the claimed behavior.
|
||||||
|
5. Classify failures as `physics-implausible | model-inadequate | artifact-gap | upstream-contract | needs-correction`.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/physics-evaluations/<feature-id>-physics-evaluation.md` with Input Evidence, Physics Checks, Failure Classification, Evaluation Verdict, Handoff Recommendation, and No-Change Assertion.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not change tolerances.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Physical checks are tied to requirements and model purpose.
|
||||||
|
- Passing tolerance comparison is not treated as sufficient by itself.
|
||||||
|
- Implausible results name the exact quantity, model, and likely owner.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send implementation-owned physical failures to Correction Agent, inadequate model coverage to Reference Model Agent, and passing physics evidence to Release Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Physics Sanity"
|
||||||
|
short_description: "Check physical plausibility."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-physics-sanity to evaluate Abaqus User Subroutine physical plausibility."
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-readiness
|
||||||
|
description: Use when auditing Abaqus User Subroutine readiness from upstream gate evidence, acceptance traceability, no-Abaqus tests, Abaqus validation artifacts, known limitations, and release-note drafts.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Readiness
|
||||||
|
|
||||||
|
Use this skill to audit whether an Abaqus User Subroutine feature is ready for internal closure after all technical gates pass. Readiness audit is the owned artifact for this skill.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/releases/README.md`
|
||||||
|
- Requirements, research, formulation, numerical review, interface, test model, implementation, validation, and physics reports
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Run gate audit over requirements, research, formulation, interface, TDD test models, Fortran implementation evidence, subroutine validation, and physics sanity.
|
||||||
|
2. Build Acceptance Traceability from requirements to tests, artifacts, validation evidence, and limitations.
|
||||||
|
3. Record Validation Evidence, including no-Abaqus tests, `python scripts/validate_workspace.py`, and any opt-in Abaqus validation evidence.
|
||||||
|
4. Record Known Limitations, deferred requirements, unsupported entry points, missing artifacts, unresolved defects, accepted risks, and open items.
|
||||||
|
5. Return a verdict: `ready-for-release`, `needs-documentation`, `needs-correction`, `needs-reference-artifacts`, `needs-upstream-decision`, or `blocked`.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/releases/<feature-id>-release.md` with Gate Evidence Inventory, Acceptance Traceability, Validation Evidence, Known Limitations, Release Notes Draft, Release Verdict, and No-Change Assertion.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not edit source code or tests.
|
||||||
|
- Do not change requirements, formulations, interface contracts, reference artifacts, or tolerance policies.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not override failed or missing upstream gates.
|
||||||
|
- Do not publish, deploy, package, tag, commit, or externally release anything unless the user explicitly asks.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Every `must` requirement is traced to passing evidence or a blocker.
|
||||||
|
- Missing validation evidence is a blocker, not a limitation.
|
||||||
|
- Known limitations are explicit and tied to requirements, models, or artifacts.
|
||||||
|
- Release Verdict is internal readiness, not permission to publish.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send missing gate evidence to Coordinator Agent, implementation defects to Correction Agent, artifact gaps to Reference Model Agent, and accepted ready evidence to the user.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Readiness"
|
||||||
|
short_description: "Audit internal readiness."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-readiness to audit Abaqus User Subroutine readiness."
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-requirements
|
||||||
|
description: Use when defining Abaqus User Subroutine requirements, acceptance criteria, verification quantities, tolerance policy, and a requirement verification matrix before research, formulation, TDD test models, or Fortran implementation.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Requirements
|
||||||
|
|
||||||
|
Use this skill to turn a requested Abaqus User Subroutine behavior into a measurable contract for downstream research, formulation, interface, test model, implementation, and validation work.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/requirements/README.md`
|
||||||
|
- User request, target Abaqus entry point, material/element behavior, constraints, and exclusions
|
||||||
|
- Existing `docs/requirements/<feature-id>.md` when revising a feature
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Assign a stable `feature_id` in kebab case.
|
||||||
|
2. Define purpose, scope, analysis procedure, element/material family, units, and target entry points such as `UMAT | VUMAT | UEL | UEXPAN | DISP | USDFLD`.
|
||||||
|
3. Convert requested behavior into singular `shall` statements with ids like `ABAQUS-USUB-REQ-<FEATURE>-###`.
|
||||||
|
4. Define Verification Quantities: stress, strain, state variables, DDSDDE/tangent terms, displacement, reaction, energy, residual, or user output variables.
|
||||||
|
5. Record Tolerance Policy values or mark them `needs-user-decision`.
|
||||||
|
6. Record Reference Artifact Requirements under `references/<feature-id>/`.
|
||||||
|
7. Build a Requirement Verification Matrix mapping requirement, source, verification method, acceptance criteria, tolerance, downstream agents, and status.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/requirements/<feature-id>.md` with Metadata, Purpose, In Scope, Out Of Scope, Analysis Definition, Input and Output Requirements, Verification Quantities, Tolerance Policy, Reference Artifact Requirements, Requirement Verification Matrix, Open Questions, and Downstream Handoff.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement Fortran code.
|
||||||
|
- Do not write finite element formulations.
|
||||||
|
- Do not design Abaqus ABI argument handling.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Every `must` requirement has a verification method and acceptance criteria.
|
||||||
|
- Every numerical requirement has units, coordinate system, and tolerance or an explicit decision owner.
|
||||||
|
- Every reference-comparison requirement names required artifacts.
|
||||||
|
- Words like "accurate", "robust", and "Abaqus-like" are converted into measurable criteria or open questions.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Route theory gaps to Research Agent, math gaps to Formulation Agent, ABI and parameter gaps to I/O Definition Agent, TDD model needs to Reference Model Agent, and implementation readiness to Implementation Planning Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Requirements"
|
||||||
|
short_description: "Define subroutine requirements."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-requirements to define verifiable Abaqus User Subroutine requirements."
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-research
|
||||||
|
description: Use when collecting Abaqus User Subroutine research evidence from official Abaqus manuals, books, papers, benchmark sources, and source reliability notes before formulation, interface definition, or test model design.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Research
|
||||||
|
|
||||||
|
Use this skill to collect source-backed Research evidence for Abaqus User Subroutine work while separating verified facts from inference.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/research/README.md`
|
||||||
|
- `docs/requirements/<feature-id>.md`
|
||||||
|
- User-provided references, official Abaqus documentation links, books, papers, and benchmark sources
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Define exact research questions from requirements and open issues.
|
||||||
|
2. Search source priorities in order: official Abaqus documentation, Abaqus User Subroutines Reference Guide, Abaqus Analysis User's Guide, books, papers, and benchmark sources.
|
||||||
|
3. Record source reliability tier, citation, scope, assumptions, and applicability limits.
|
||||||
|
4. Extract only facts needed by downstream formulation, Abaqus ABI interface definition, TDD test models, and Fortran implementation.
|
||||||
|
5. Separate verified facts from inference.
|
||||||
|
6. Identify candidate benchmark models, closed-form checks, patch tests, tangent checks, and negative tests.
|
||||||
|
7. Record unresolved conflicts or missing evidence as open issues.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/research/<feature-id>-research.md` with Source Inventory, Source Reliability Tier, Extracted Facts, Candidate Benchmarks, Verification Relevance, Applicability Limits, Open Issues, and Downstream Handoff.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not finalize FEM formulations.
|
||||||
|
- Do not design Fortran source layout or Abaqus wrapper code.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Source tiers are explicit.
|
||||||
|
- Each extracted fact links to a cited source.
|
||||||
|
- Inference is labeled as inference.
|
||||||
|
- Benchmark applicability limits are clear enough for Formulation and Reference Model Agents.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send math evidence to Formulation Agent, Abaqus parameter evidence to I/O Definition Agent, benchmark candidates to Reference Model Agent, and validation risk notes to Numerical Review Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Research"
|
||||||
|
short_description: "Collect source-backed evidence."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-research to collect source-backed Abaqus User Subroutine research evidence."
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-test-models
|
||||||
|
description: Use when designing Abaqus User Subroutine TDD test models, no-Abaqus driver cases, Fortran manifest entries, Abaqus .inp reference bundles, artifact metadata, source hashes, log tails, and CSV extraction contracts.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Test Models
|
||||||
|
|
||||||
|
Use this skill to define the TDD test model portfolio before Fortran implementation and Abaqus validation.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/reference-models/README.md`
|
||||||
|
- Requirements, research, formulation, numerical review, and interface documents
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Define TDD test model categories: no-Abaqus unit driver, analytical material point, finite-difference tangent check, `.inp` smoke model, benchmark/reference model, regression case, and negative case.
|
||||||
|
2. For no-Abaqus tests, define `tests/fortran/manifest.json` entries, source files, driver inputs, expected outputs, and tolerances.
|
||||||
|
3. For Abaqus validation, define `references/<feature-id>/<model-id>/` artifact bundle requirements.
|
||||||
|
4. Require `model.inp`, `metadata.json`, source hash entries, Abaqus version, compiler version, msg/dat/log tail files, and extracted CSV files for `ready-for-comparison` artifacts.
|
||||||
|
5. Define Coverage Matrix rows mapping requirement id, model id, compared quantity, tolerance, artifact file, and status.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/reference-models/<feature-id>-reference-models.md` with TDD test model strategy, no-Abaqus manifest plan, Abaqus Input Requirements, Artifact Bundle Contract, Metadata JSON Contract, Reference CSV Requirements, Coverage Matrix, Artifact Acceptance Checklist, and Downstream Handoff.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not implement code.
|
||||||
|
- Do not run Abaqus.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not invent Abaqus, compiler, or source hash provenance.
|
||||||
|
- Do not compare implementation results.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- Every `must` requirement maps to at least one no-Abaqus test or Abaqus validation model.
|
||||||
|
- No-Abaqus tests identify exactly what should fail before implementation.
|
||||||
|
- Each ready artifact contract includes source hash, Abaqus version, compiler version, msg/dat/log tail, and CSV file expectations.
|
||||||
|
- Missing required reference artifacts keep the model at `needs-reference-artifacts`.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send no-Abaqus test order to Implementation Planning Agent, ABI/schema issues to I/O Definition Agent, artifact readiness needs to Reference Verification Agent, and physics expectations to Physics Evaluation Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Test Models"
|
||||||
|
short_description: "Design TDD and reference models."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-test-models to design Abaqus User Subroutine TDD test models and reference artifact contracts."
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
name: abaqus-subroutine-validation
|
||||||
|
description: Use when validating Abaqus User Subroutine outputs against stored reference artifacts, checking metadata, source hashes, Abaqus and compiler versions, msg/dat/log tails, CSV schemas, tolerances, and opt-in Abaqus validation evidence.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Abaqus Subroutine Validation
|
||||||
|
|
||||||
|
Use this skill to validate implemented subroutines against no-Abaqus results and stored Abaqus reference artifacts without changing either side. Subroutine validation is the owned artifact for this skill.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read first:
|
||||||
|
|
||||||
|
- `AGENTS.md`
|
||||||
|
- `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `docs/reference-verifications/README.md`
|
||||||
|
- `docs/reference-models/<feature-id>-reference-models.md`
|
||||||
|
- `references/<feature-id>/<model-id>/metadata.json`
|
||||||
|
- Generated no-Abaqus and extracted CSV outputs
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Validate artifact metadata with `python scripts/validate_reference_artifacts.py`.
|
||||||
|
2. For `ready-for-comparison`, check model `.inp`, metadata.json, source hash, Abaqus version, compiler version, msg/dat/log tail files, and declared CSV files.
|
||||||
|
3. Run no-Abaqus comparison commands when available.
|
||||||
|
4. Run Abaqus only when explicitly configured through `HARNESS_ABAQUS_VALIDATION=run` and `HARNESS_ABAQUS_VALIDATION_COMMANDS`.
|
||||||
|
5. Compare generated CSVs against reference CSVs by documented IDs, units, coordinate system, output location, component naming, and tolerance.
|
||||||
|
6. Classify failures as `missing-reference-artifact | missing-generated-output | schema-mismatch | id-mismatch | source-hash-mismatch | unit-or-coordinate-mismatch | tolerance-failure | nonfinite-result | environment | upstream-contract`.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Produce or revise `docs/reference-verifications/<feature-id>-reference-verification.md` with Artifact Inventory, Comparison Contract, Quantity Results, Failure Classification, Validation Evidence, Handoff Recommendation, and No-Change Assertion.
|
||||||
|
|
||||||
|
## Boundaries
|
||||||
|
|
||||||
|
- Do not edit source code.
|
||||||
|
- Do not edit tests.
|
||||||
|
- Do not change reference artifacts.
|
||||||
|
- Do not change tolerance policies.
|
||||||
|
- Do not generate reference CSVs.
|
||||||
|
- Do not run Abaqus unless the opt-in environment contract is explicit.
|
||||||
|
- Do not approve release readiness.
|
||||||
|
|
||||||
|
## Quality Gate
|
||||||
|
|
||||||
|
- `ready-for-comparison` artifacts pass metadata validation.
|
||||||
|
- Source hash, Abaqus version, compiler version, msg/dat/log provenance, and CSV schemas are reported.
|
||||||
|
- Every compared quantity reports max absolute error, max relative error, RMS error when applicable, worst row, and pass/fail.
|
||||||
|
- Nonfinite values are reported explicitly.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
Send implementation-owned mismatches to Correction Agent, artifact gaps to Reference Model Agent, ABI/schema gaps to I/O Definition Agent, and physically suspicious passing results to Physics Evaluation Agent.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Abaqus Subroutine Validation"
|
||||||
|
short_description: "Validate artifacts and CSVs."
|
||||||
|
default_prompt: "Use $abaqus-subroutine-validation to validate Abaqus User Subroutine artifacts and CSV comparison results."
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
---
|
||||||
|
name: fem-theory-query
|
||||||
|
description: Use when answering finite element method, structural analysis solver, element formulation, residual/tangent, constitutive integration, contact, dynamics, eigenproblem, or verification questions from a configured FEM wiki vault.
|
||||||
|
---
|
||||||
|
|
||||||
|
# FEM Theory Query
|
||||||
|
|
||||||
|
Use this skill as a portable domain router for finite element method and structural solver theory questions. Ground answers in a configured FEM wiki vault, then compose sibling skills instead of reimplementing their workflows.
|
||||||
|
|
||||||
|
## FEM Vault Resolution
|
||||||
|
|
||||||
|
Resolve the FEM wiki vault in this order:
|
||||||
|
|
||||||
|
1. Skill-local config file: `vault-path.txt` in this skill folder. Read the first non-empty, non-comment line as the vault root path.
|
||||||
|
2. Current project instructions: `AGENTS.md`, `CLAUDE.md`, or an equivalent section named `FEM Solver Theory Wiki`.
|
||||||
|
3. Environment variable: `FEM_THEORY_WIKI_VAULT`.
|
||||||
|
|
||||||
|
If no valid vault is found, ask the user for the vault path. A valid vault must contain `wiki/hot.md` or `wiki/index.md`.
|
||||||
|
|
||||||
|
Keep `vault-path.txt` PC-specific. When the vault moves, update that file instead of editing this skill body.
|
||||||
|
|
||||||
|
## Companion Skill Protocols
|
||||||
|
|
||||||
|
This skill is an orchestrator. Do not reimplement sibling skills. Use the sibling skill instructions as authoritative when available.
|
||||||
|
|
||||||
|
### Companion skill path resolution
|
||||||
|
|
||||||
|
After reading `vault-path.txt`, call that value `FEM_VAULT_ROOT`. Resolve companion skill files from that absolute vault root:
|
||||||
|
|
||||||
|
- `FEM_VAULT_ROOT\skills\think\SKILL.md`: use for non-trivial FEM formulation, solver architecture, ambiguity, tradeoffs, verification design, or gap assessment.
|
||||||
|
- `FEM_VAULT_ROOT\skills\wiki-query\SKILL.md`: use for normal wiki-grounded answers from the configured FEM vault.
|
||||||
|
- `FEM_VAULT_ROOT\skills\autoresearch\SKILL.md`: use only when the user explicitly asks to research, find sources, update the wiki, or fill missing wiki coverage.
|
||||||
|
|
||||||
|
If the runtime provides a skill activation mechanism, activate the companion skill by name. If not, read the absolute companion `SKILL.md` path constructed from `vault-path.txt` and follow its workflow. If an absolute companion path does not exist, tell the user which path is missing and ask them to fix `vault-path.txt`.
|
||||||
|
|
||||||
|
### Relative paths inside companion skills
|
||||||
|
|
||||||
|
When a companion skill refers to another file by a relative path, resolve that path from the absolute directory of the companion skill file under `FEM_VAULT_ROOT`, not from the caller project or current working directory. Normalize `..` segments after joining paths. Keep the resolved path inside `FEM_VAULT_ROOT` unless the companion skill explicitly requires an external path.
|
||||||
|
|
||||||
|
Examples from `FEM_VAULT_ROOT\skills\autoresearch\SKILL.md`:
|
||||||
|
|
||||||
|
- `../wiki-cli/SKILL.md` resolves to `FEM_VAULT_ROOT\skills\wiki-cli\SKILL.md`.
|
||||||
|
- `../../wiki/references/transport-fallback.md` resolves to `FEM_VAULT_ROOT\wiki\references\transport-fallback.md`.
|
||||||
|
- `references/program.md` resolves to `FEM_VAULT_ROOT\skills\autoresearch\references\program.md`.
|
||||||
|
|
||||||
|
If a resolved companion-relative path is missing, report the missing absolute path and ask the user to fix `vault-path.txt` or install the full `skills/` bundle.
|
||||||
|
|
||||||
|
### How to use `think`
|
||||||
|
|
||||||
|
Use `think` as a compact internal preflight before answering FEM solver questions.
|
||||||
|
|
||||||
|
Do:
|
||||||
|
- Identify the user's real question: theory derivation, implementation design, verification, comparison, or missing source.
|
||||||
|
- Check whether you are relying on memory instead of wiki evidence.
|
||||||
|
- Decide whether the answer can be handled by wiki query or needs autoresearch.
|
||||||
|
- For complex questions, surface the reasoning structure briefly in the answer.
|
||||||
|
|
||||||
|
Do not:
|
||||||
|
- Print all 10 stages for routine factual questions.
|
||||||
|
- Use `think` as a substitute for reading wiki sources.
|
||||||
|
- Skip the `ACCEPT` step when the wiki has insufficient coverage.
|
||||||
|
|
||||||
|
### How to use `wiki-query`
|
||||||
|
|
||||||
|
Use `wiki-query` for the default answer path.
|
||||||
|
|
||||||
|
Follow this order:
|
||||||
|
|
||||||
|
1. Resolve the FEM vault path.
|
||||||
|
2. Read `wiki/hot.md`.
|
||||||
|
3. If needed, use `wiki-retrieve` when provisioned: `python scripts/retrieve.py "<question>" --top 5`.
|
||||||
|
4. If retrieval is not provisioned or fails, read `wiki/index.md`.
|
||||||
|
5. Read 3-7 relevant wiki pages.
|
||||||
|
6. Synthesize with Obsidian wikilink citations.
|
||||||
|
|
||||||
|
Do:
|
||||||
|
- Cite every core claim with `[[Page Name]]`.
|
||||||
|
- Prefer vault evidence over model memory.
|
||||||
|
- Say clearly when the wiki lacks enough evidence.
|
||||||
|
|
||||||
|
Do not:
|
||||||
|
- Answer a vault-specific question from training data alone.
|
||||||
|
- Open many pages when 3-7 are enough.
|
||||||
|
- Write to the wiki unless the user explicitly asks.
|
||||||
|
|
||||||
|
### How to use `autoresearch`
|
||||||
|
|
||||||
|
Use `autoresearch` only for explicit research or wiki-expansion requests.
|
||||||
|
|
||||||
|
Trigger examples:
|
||||||
|
- "Find sources and strengthen this wiki coverage."
|
||||||
|
- "If the wiki does not cover this, research it."
|
||||||
|
- "Research and file this topic."
|
||||||
|
- "Create source and concept pages for this topic."
|
||||||
|
|
||||||
|
Before starting:
|
||||||
|
- Tell the user it will use web search/fetch and write new wiki pages.
|
||||||
|
- Mention that fetched content is subject to the `autoresearch` web egress hygiene rules.
|
||||||
|
- Ask for approval unless the user already gave explicit approval in the same request.
|
||||||
|
|
||||||
|
Do:
|
||||||
|
- Read `FEM_VAULT_ROOT\skills\autoresearch\SKILL.md` and `FEM_VAULT_ROOT\skills\autoresearch\references\program.md`.
|
||||||
|
- File results into the configured FEM vault, not the caller project.
|
||||||
|
- Use wiki locks and transport rules from the sibling skill.
|
||||||
|
|
||||||
|
Do not:
|
||||||
|
- Run autoresearch for ordinary Q&A.
|
||||||
|
- Fetch web sources silently.
|
||||||
|
- Write into `.raw/` or `wiki/` without explicit user intent.
|
||||||
|
|
||||||
|
## Answer Contract
|
||||||
|
|
||||||
|
Answer in the user's language. For Korean questions, translate the section headings naturally.
|
||||||
|
|
||||||
|
Use this structure unless the user asks for another format:
|
||||||
|
|
||||||
|
- Summary conclusion
|
||||||
|
- Formulation
|
||||||
|
- Solver implementation view
|
||||||
|
- Verification and benchmarks
|
||||||
|
- Evidence
|
||||||
|
- Wiki gap
|
||||||
|
|
||||||
|
Every core technical claim should trace to wiki evidence. Use Obsidian wikilinks such as `[[Finite Element Method]]`, `[[Solid Element Stiffness Integration]]`, or the relevant source page. If the wiki does not cover a point, label it as a gap instead of presenting model memory as vault knowledge.
|
||||||
|
|
||||||
|
## FEM Query Expansion
|
||||||
|
|
||||||
|
When a user asks a short FEM question, expand the retrieval intent before searching:
|
||||||
|
|
||||||
|
- Element formulation: shape functions, DOFs, Jacobian, `B` matrix, integration, load vector, result recovery.
|
||||||
|
- Nonlinear solve: residual, tangent, Newton update, convergence norms, load/time increments, cutback policy.
|
||||||
|
- Constitutive update: stress update, material tangent, state variables, return mapping, history evolution.
|
||||||
|
- Dynamics/eigen: mass, damping, time integration, modal extraction, normalization, residual checks.
|
||||||
|
- Contact/constraints: gap, normal/tangential law, penalty or multiplier enforcement, search, tangent contribution.
|
||||||
|
- Verification: patch tests, convergence, benchmark problems, matrix checks, residual norms, source-solver comparison.
|
||||||
|
|
||||||
|
Keep expansion internal unless showing it helps the user understand the answer.
|
||||||
|
|
||||||
|
## Deployment Notes
|
||||||
|
|
||||||
|
Distribute this skill with the whole `skills/` bundle so sibling paths remain valid. After installing or symlinking the bundle into another agent, update `vault-path.txt` for that PC or set `FEM_THEORY_WIKI_VAULT`.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "FEM Theory Query"
|
||||||
|
short_description: "Query FEM solver theory from wiki."
|
||||||
|
default_prompt: "Use $fem-theory-query to answer a finite-element structural solver formulation question from the wiki."
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# FEM wiki vault root path.
|
||||||
|
# Edit this per PC. Use an absolute path to the vault that contains wiki/ and .raw/.
|
||||||
|
D:\Obsidian\MultiPhysicsVault
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
name: harness-review
|
||||||
|
description: "Use when reviewing this Abaqus User Subroutine Harness repository: local changes, generated phase files, implementation diffs, missing tests, Fortran validation readiness, reference artifact contracts, or compliance with AGENTS.md, docs/ARCHITECTURE.md, docs/ADR.md, and Harness acceptance criteria."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Harness Review
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Use this skill to review Harness work against repository rules, Abaqus User Subroutine workflow, Fortran TDD, no-Abaqus validation, reference artifact contracts, and explicit Abaqus opt-in validation requirements. Prioritize bugs, regressions, missing tests, and rule violations.
|
||||||
|
|
||||||
|
## Review Process
|
||||||
|
|
||||||
|
1. Read `/AGENTS.md`, `/docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`, `/docs/ARCHITECTURE.md`, and `/docs/ADR.md`.
|
||||||
|
2. Inspect changed files with `git status --short` and `git diff`.
|
||||||
|
3. Check architecture, Fortran test coverage, reference artifact contracts, critical rules, and validation readiness.
|
||||||
|
4. Run relevant commands when feasible:
|
||||||
|
- `python -m unittest discover -s scripts -p "test_*.py"`
|
||||||
|
- `python scripts/validate_fortran.py`
|
||||||
|
- `python scripts/validate_reference_artifacts.py`
|
||||||
|
- `python scripts/validate_workspace.py`
|
||||||
|
5. Lead with actionable findings. Keep summaries secondary.
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
| Item | Question |
|
||||||
|
| --- | --- |
|
||||||
|
| Workflow | Does the change fit the seven-step Abaqus User Subroutine process? |
|
||||||
|
| Architecture | Does the change follow `docs/ARCHITECTURE.md` ownership boundaries? |
|
||||||
|
| Tests | Are new or changed Fortran behaviors covered by no-Abaqus Fortran/Python tests or harness tests? |
|
||||||
|
| TDD Guard | Would Fortran production edits be blocked without related tests? |
|
||||||
|
| References | Do reference artifacts include `.inp`, source hash, Abaqus version, compiler version, msg/dat/log tail, and extracted CSV contracts when required? |
|
||||||
|
| Abaqus Opt-in | Is `HARNESS_ABAQUS_VALIDATION=run` used only when explicitly configured? |
|
||||||
|
| Build | Do the Python, Fortran, reference artifact, and workspace validation commands pass or report expected skips? |
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
If there are findings, list them first in severity order with file and line references when possible. Then include this table:
|
||||||
|
|
||||||
|
| Item | Result | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Workflow | PASS/FAIL | {detail} |
|
||||||
|
| Architecture | PASS/FAIL | {detail} |
|
||||||
|
| Tests | PASS/FAIL | {detail} |
|
||||||
|
| TDD Guard | PASS/FAIL | {detail} |
|
||||||
|
| Reference Artifacts | PASS/FAIL | {detail} |
|
||||||
|
| Abaqus Opt-in | PASS/FAIL | {detail} |
|
||||||
|
| Validation | PASS/FAIL | {detail} |
|
||||||
|
|
||||||
|
When there are no findings, say that clearly, then mention commands not run or remaining risk.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Subroutine Harness Review"
|
||||||
|
short_description: "Review Fortran subroutine harness work."
|
||||||
|
default_prompt: "Use $harness-review to review Abaqus User Subroutine Harness changes."
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
name: harness-workflow
|
||||||
|
description: "Use when planning or running this Abaqus User Subroutine Harness: reading AGENTS.md and docs/*.md, discussing implementation scope, creating or updating phases/index.json, phases/{task}/index.json, phases/{task}/stepN.md, or invoking scripts/execute.py for staged Codex execution."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Harness Workflow
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Use this skill to turn a user-approved Abaqus User Subroutine task into small, self-contained Harness steps. Keep every step grounded in repository docs, Fortran TDD, no-Abaqus validation, reference artifact validation, and explicit Abaqus opt-in rules.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Read `AGENTS.md`, `docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`, `docs/PRD.md`, `docs/ARCHITECTURE.md`, and `docs/ADR.md`.
|
||||||
|
2. Map the task to the seven-step Abaqus User Subroutine process: requirements, research, formulation, interface, TDD test models, Fortran implementation, validation.
|
||||||
|
3. Discuss unresolved product or technical decisions with the user before writing phase files.
|
||||||
|
4. Create or update `phases/index.json`, `phases/{task-name}/index.json`, and one `phases/{task-name}/stepN.md` per step.
|
||||||
|
5. Run the phase with `python scripts/execute.py {task-name}` when asked. Use `--push` only when the user asks.
|
||||||
|
|
||||||
|
## Step Design Rules
|
||||||
|
|
||||||
|
- Scope each step to one artifact family: requirements, research, formulation, ABI/interface, no-Abaqus tests, Fortran source, validation, or documentation.
|
||||||
|
- Make every step self-contained. Include required context and file paths.
|
||||||
|
- Specify interfaces and signatures only when the step owns the interface contract.
|
||||||
|
- Use executable acceptance criteria, not abstract statements.
|
||||||
|
- For Fortran behavior changes, require tests first and name the no-Abaqus Fortran/Python driver test or `tests/fortran/manifest.json` entry.
|
||||||
|
- Preserve the rule that Abaqus is not run by default; use `HARNESS_ABAQUS_VALIDATION=run` only when explicitly requested and configured.
|
||||||
|
|
||||||
|
## Phase Files
|
||||||
|
|
||||||
|
Create or update `phases/index.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"phases": [
|
||||||
|
{
|
||||||
|
"dir": "abaqus-subroutine-feature",
|
||||||
|
"status": "pending"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Create `phases/{task-name}/index.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project": "FESA Harness",
|
||||||
|
"phase": "<task-name>",
|
||||||
|
"steps": [
|
||||||
|
{ "step": 0, "name": "requirements", "status": "pending" },
|
||||||
|
{ "step": 1, "name": "test-models", "status": "pending" },
|
||||||
|
{ "step": 2, "name": "fortran-implementation", "status": "pending" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
|
||||||
|
- `project` comes from `AGENTS.md`.
|
||||||
|
- `phase` matches the task directory name.
|
||||||
|
- `steps[].step` starts at `0`.
|
||||||
|
- Initial status is always `pending`.
|
||||||
|
- Do not add timestamps when creating files. `scripts/execute.py` records timestamps.
|
||||||
|
|
||||||
|
## Step Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Step {N}: {name}
|
||||||
|
|
||||||
|
## Read First
|
||||||
|
|
||||||
|
- `/AGENTS.md`
|
||||||
|
- `/docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md`
|
||||||
|
- `/docs/ARCHITECTURE.md`
|
||||||
|
- `/docs/ADR.md`
|
||||||
|
- {previously created or modified files}
|
||||||
|
|
||||||
|
## Task
|
||||||
|
|
||||||
|
{Concrete instructions with file paths, interfaces, signatures, and rules.}
|
||||||
|
|
||||||
|
## Tests To Write First
|
||||||
|
|
||||||
|
- {Exact no-Abaqus Fortran/Python test file, manifest entry, or Python harness test to add before implementation.}
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
python scripts/validate_fortran.py
|
||||||
|
python scripts/validate_reference_artifacts.py
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation Notes
|
||||||
|
|
||||||
|
- Use `HARNESS_ABAQUS_VALIDATION=run` only when the step explicitly owns Abaqus validation and the command contract is provided.
|
||||||
|
- Update `phases/{task-name}/index.json` with `completed`, `error`, or `blocked` and a concrete summary/reason.
|
||||||
|
|
||||||
|
## Forbidden
|
||||||
|
|
||||||
|
- Do not add JavaScript/TypeScript/npm fallback.
|
||||||
|
- Do not run Abaqus by default.
|
||||||
|
- Do not generate reference CSVs unless the user explicitly authorized a reference-artifact phase.
|
||||||
|
- Do not break existing tests.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Execution And Recovery
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/execute.py {task-name}
|
||||||
|
python scripts/execute.py {task-name} --push
|
||||||
|
```
|
||||||
|
|
||||||
|
If a step is `error`, fix the cause, set it back to `pending`, remove `error_message`, and rerun. If a step is `blocked`, resolve `blocked_reason`, set it back to `pending`, remove `blocked_reason`, and rerun.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
interface:
|
||||||
|
display_name: "Subroutine Harness Workflow"
|
||||||
|
short_description: "Plan staged Fortran subroutine work."
|
||||||
|
default_prompt: "Use $harness-workflow to plan or run staged Abaqus User Subroutine Harness work."
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
.vs/
|
||||||
|
build/
|
||||||
|
out/
|
||||||
|
CMakeFiles/
|
||||||
|
CMakeCache.txt
|
||||||
|
cmake_install.cmake
|
||||||
|
CTestTestfile.cmake
|
||||||
|
Testing/
|
||||||
|
*.vcxproj.user
|
||||||
|
*.obj
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.lib
|
||||||
|
*.exp
|
||||||
|
*.log
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# phase execution outputs
|
||||||
|
phases/**/phase*-output.json
|
||||||
|
phases/**/step*-output.json
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Project: FESA Harness
|
||||||
|
|
||||||
|
## 기술 스택
|
||||||
|
- C++17 이상
|
||||||
|
- MSVC on Windows
|
||||||
|
- CMake + CTest
|
||||||
|
- Abaqus UserSubroutine source in Fortran
|
||||||
|
- Intel oneAPI Fortran compiler on Windows
|
||||||
|
- Harness scripts in Python 3
|
||||||
|
|
||||||
|
## 아키텍처 규칙
|
||||||
|
- CRITICAL: 기본 검증 경로는 `python scripts/validate_workspace.py`이다.
|
||||||
|
- CRITICAL: C++ 빌드는 CMake/MSVC/x64/Debug 기준으로 검증한다.
|
||||||
|
- CRITICAL: Abaqus 실행은 기본 검증에서 수행하지 않는다. `HARNESS_ABAQUS_VALIDATION=run`으로 명시한 경우에만 실행한다.
|
||||||
|
- CRITICAL: 새 기능 또는 동작 변경은 테스트를 먼저 작성하고 실패를 확인한 뒤 구현한다.
|
||||||
|
- CRITICAL: Abaqus reference artifact나 solver 코드 복원은 명시적으로 요청된 phase에서만 수행한다.
|
||||||
|
- Codex custom agent의 `model_reasoning_effort` 기본값은 `extra high`로 둔다.
|
||||||
|
- Harness runner는 `scripts/execute.py`에 둔다.
|
||||||
|
- Codex hook 정책은 `.codex/hooks/`에 둔다.
|
||||||
|
- Harness planning/review instructions are stored in `.codex/skills/`.
|
||||||
|
- Generated phase execution outputs remain ignored under `phases/**/step*-output.json`.
|
||||||
|
|
||||||
|
## 개발 프로세스
|
||||||
|
- TDD를 기본으로 한다. C++ production file을 바꿀 때는 관련 C++ test file이 있어야 한다.
|
||||||
|
- Fortran user subroutine production file을 바꿀 때는 관련 no-Abaqus Fortran/Python driver test가 있어야 한다.
|
||||||
|
- 커밋 전 hook은 Harness Python self-test와 workspace validation을 실행해야 한다.
|
||||||
|
- 커밋 메시지는 conventional commits 형식을 따른다: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`.
|
||||||
|
- 계획이 필요한 장기 작업은 Harness phase로 나누고, 각 step은 독립 실행 가능해야 한다.
|
||||||
|
|
||||||
|
## 명령어
|
||||||
|
```bash
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
python scripts/validate_fortran.py
|
||||||
|
python scripts/validate_reference_artifacts.py
|
||||||
|
python scripts/execute.py <phase-dir>
|
||||||
|
python scripts/execute.py <phase-dir> --push
|
||||||
|
```
|
||||||
|
|
||||||
|
## MSVC 검증 기본값
|
||||||
|
- Generator: `Visual Studio 17 2022`
|
||||||
|
- Platform: `x64`
|
||||||
|
- Config: `Debug`
|
||||||
|
- Build directory: `build/msvc-debug`
|
||||||
|
|
||||||
|
Override variables:
|
||||||
|
- `HARNESS_VALIDATION_COMMANDS`
|
||||||
|
- `HARNESS_CMAKE_GENERATOR`
|
||||||
|
- `HARNESS_CMAKE_PLATFORM`
|
||||||
|
- `HARNESS_CMAKE_CONFIG`
|
||||||
|
- `HARNESS_BUILD_DIR`
|
||||||
|
|
||||||
|
## Abaqus / Fortran 검증 기본값
|
||||||
|
- `HARNESS_FORTRAN_VALIDATION=auto`: `tests/fortran/manifest.json`이 있으면 Intel Fortran no-Abaqus tests를 실행한다.
|
||||||
|
- `HARNESS_FORTRAN_COMPILER=auto`: `ifx`를 우선 사용하고, 없으면 `ifort`를 사용한다.
|
||||||
|
- `HARNESS_ONEAPI_VARS_BAT`: Intel oneAPI 환경 설정 batch file override.
|
||||||
|
- `HARNESS_ABAQUS_VALIDATION=off`: 기본값이며 Abaqus job을 실행하지 않는다.
|
||||||
|
- `HARNESS_ABAQUS_VALIDATION=detect`: Abaqus executable 탐지만 수행한다.
|
||||||
|
- `HARNESS_ABAQUS_VALIDATION=run`: `HARNESS_ABAQUS_VALIDATION_COMMANDS`에 명시된 Abaqus command만 실행한다.
|
||||||
|
- `HARNESS_ABAQUS_USE_ONEAPI_ENV=auto`: Abaqus run command 앞에 oneAPI 환경 설정을 자동 적용할 수 있다.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Abaqus User Subroutine Agent Design
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
This document maps the project agents and skills to the Abaqus User Subroutine development process. The working language is Fortran with Intel oneAPI Fortran, and Abaqus execution remains opt-in.
|
||||||
|
|
||||||
|
## Abaqus User Subroutine development process
|
||||||
|
|
||||||
|
1. Subroutine requirements analysis
|
||||||
|
2. Books, papers, and research evidence
|
||||||
|
3. Finite element formulation for implementation
|
||||||
|
4. Subroutine input/output parameter definition
|
||||||
|
5. TDD test model design
|
||||||
|
6. Fortran code implementation
|
||||||
|
7. Subroutine validation
|
||||||
|
|
||||||
|
## Agent Mapping
|
||||||
|
|
||||||
|
| Process step | Primary agents | Primary skills |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1. Subroutine requirements analysis | Requirement Agent, Coordinator Agent | `abaqus-subroutine-requirements` |
|
||||||
|
| 2. Books, papers, and research evidence | Research Agent | `abaqus-subroutine-research`, `fem-theory-query` |
|
||||||
|
| 3. Finite element formulation for implementation | Formulation Agent, Numerical Review Agent | `abaqus-subroutine-formulation`, `abaqus-subroutine-numerical-review` |
|
||||||
|
| 4. Subroutine input/output parameter definition | I/O Definition Agent | `abaqus-subroutine-interface` |
|
||||||
|
| 5. TDD test model design | Reference Model Agent, Implementation Planning Agent | `abaqus-subroutine-test-models` |
|
||||||
|
| 6. Fortran code implementation | Implementation Planning Agent, Implementation Agent, Correction Agent | `abaqus-fortran-tdd` |
|
||||||
|
| 7. Subroutine validation | Build/Test Executor Agent, Reference Verification Agent, Physics Evaluation Agent, Release Agent | `abaqus-subroutine-validation`, `abaqus-subroutine-physics-sanity`, `abaqus-subroutine-readiness` |
|
||||||
|
|
||||||
|
## Gates
|
||||||
|
|
||||||
|
- Requirements gate: every must requirement has measurable acceptance criteria and verification method.
|
||||||
|
- Research gate: source-backed facts are separated from inference and applicability limits are explicit.
|
||||||
|
- Formulation gate: stress update, consistent tangent, state variables, and numerical risks are documented.
|
||||||
|
- Interface gate: Abaqus ABI arguments, update responsibilities, tensor ordering, units, and CSV extraction schemas are explicit.
|
||||||
|
- Test model gate: no-Abaqus tests and reference artifact contracts are defined before implementation.
|
||||||
|
- Implementation gate: Fortran production changes follow RED -> GREEN -> VERIFY and pass no-Abaqus validation.
|
||||||
|
- Validation gate: reference artifacts include `.inp`, source hash, Abaqus version, compiler version, msg/dat/log tail, and extracted CSV evidence before comparison.
|
||||||
|
|
||||||
|
## Validation Defaults
|
||||||
|
|
||||||
|
- Default no-Abaqus path: `python scripts/validate_fortran.py`.
|
||||||
|
- Reference artifact contract check: `python scripts/validate_reference_artifacts.py`.
|
||||||
|
- Workspace gate: `python scripts/validate_workspace.py`.
|
||||||
|
- Abaqus execution: only through `HARNESS_ABAQUS_VALIDATION=run` with explicit validation commands.
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
# Architecture Decision Records
|
||||||
|
|
||||||
|
## 철학
|
||||||
|
Harness는 현재 프로젝트의 실제 기술 스택을 반영해야 한다. C++/MSVC 프로젝트에서 npm, Next.js, TypeScript test naming을 기본값으로 두면 agent prompt와 hook policy가 잘못된 구현을 유도한다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ADR-001: C++ 전용 Harness
|
||||||
|
**결정**: Harness scaffold는 C++/MSVC 전용으로 운영한다. JavaScript/TypeScript fallback은 유지하지 않는다.
|
||||||
|
|
||||||
|
**이유**: FESA 개발 환경은 MSVC 기반 C++이다. 언어별 fallback을 남기면 validation, TDD guard, acceptance criteria가 흐려진다.
|
||||||
|
|
||||||
|
**트레이드오프**: 같은 Harness scaffold를 JS/TS 프로젝트에 재사용할 수 없다. 필요하면 별도 template이나 language registry를 새 ADR로 설계한다.
|
||||||
|
|
||||||
|
### ADR-002: CMake/MSVC/x64/Debug 기본 검증
|
||||||
|
**결정**: 기본 workspace validation은 CMake, Visual Studio 17 2022 generator, x64 platform, Debug config, CTest로 수행한다.
|
||||||
|
|
||||||
|
**이유**: MSVC 환경에서 CMake/CTest는 source tree가 복원되거나 새 C++ project가 추가될 때 가장 일관된 build/test entry point다.
|
||||||
|
|
||||||
|
**트레이드오프**: Visual Studio solution-only project는 기본 지원하지 않는다. 명시적으로 필요하면 `HARNESS_VALIDATION_COMMANDS`로 override한다.
|
||||||
|
|
||||||
|
### ADR-003: 엄격한 C++ TDD Guard
|
||||||
|
**결정**: C++ production file 변경은 관련 C++ test file이 없으면 차단한다.
|
||||||
|
|
||||||
|
**이유**: Harness의 핵심 목적은 agent가 검증 없는 C++ 변경을 만들지 않도록 하는 것이다. Header 중심 C++ 구조에서도 module 또는 basename 기반 테스트 존재를 확인한다.
|
||||||
|
|
||||||
|
**트레이드오프**: 초기 scaffolding 작업에서 guard가 엄격하게 느껴질 수 있다. 문서, CMake 설정, Harness metadata는 guard 대상에서 제외한다.
|
||||||
|
|
||||||
|
### ADR-004: Harness 자체 테스트 우선
|
||||||
|
**결정**: commit hook은 먼저 Python Harness self-test를 실행한 뒤 workspace validation을 실행한다.
|
||||||
|
|
||||||
|
**이유**: 현재 저장소에는 C++ source tree가 없을 수 있다. Harness가 스스로 검증 가능해야 이후 phase generation과 source restoration을 안전하게 진행할 수 있다.
|
||||||
|
|
||||||
|
**트레이드오프**: commit 시간이 조금 늘어난다. 대신 hook/validation regressions를 빠르게 잡는다.
|
||||||
|
|
||||||
|
### ADR-005: Fortran Abaqus UserSubroutine 확장
|
||||||
|
**결정**: Abaqus UserSubroutine 구현 언어는 Fortran으로 둔다. 기본 validation은 no-Abaqus mode를 유지하고, Intel oneAPI Fortran kernel/fake-driver tests와 reference artifact metadata validation을 수행한다.
|
||||||
|
|
||||||
|
**이유**: Abaqus UserSubroutine은 Abaqus runtime, license, compiler integration에 의존한다. 기본 hook이나 workspace validation에서 Abaqus job을 자동 실행하면 개발 환경과 license 상태에 따라 재현성이 떨어진다. 계산 kernel과 Abaqus ABI wrapper를 분리하면 no-Abaqus 환경에서도 TDD를 유지할 수 있다.
|
||||||
|
|
||||||
|
**트레이드오프**: no-Abaqus validation은 Abaqus symbol resolution, include compatibility, actual job execution을 완전히 보장하지 않는다. 해당 검증은 `HARNESS_ABAQUS_VALIDATION=run`으로 명시한 환경에서만 수행한다.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# 아키텍처
|
||||||
|
|
||||||
|
## 목표
|
||||||
|
이 저장소의 현재 책임은 C++/MSVC 프로젝트를 위한 Codex Harness scaffold를 제공하는 것이다. Harness는 phase execution, edit guard, commit validation, workspace validation을 분리해서 관리한다.
|
||||||
|
|
||||||
|
## 디렉토리 구조
|
||||||
|
```text
|
||||||
|
.codex/
|
||||||
|
├── hooks/ # Codex hook scripts
|
||||||
|
└── skills/ # Harness planning/review instructions
|
||||||
|
docs/ # Project and Harness guidance
|
||||||
|
scripts/
|
||||||
|
├── execute.py # Phase step executor
|
||||||
|
├── validate_workspace.py
|
||||||
|
└── test_*.py # Harness self-tests
|
||||||
|
phases/ # Optional generated phase plans
|
||||||
|
```
|
||||||
|
|
||||||
|
## 데이터 흐름
|
||||||
|
```text
|
||||||
|
User-approved task
|
||||||
|
-> Harness phase files under phases/
|
||||||
|
-> scripts/execute.py injects AGENTS.md and docs/*.md
|
||||||
|
-> Codex executes one step at a time
|
||||||
|
-> step updates phases/{phase}/index.json
|
||||||
|
-> validation runs through scripts/validate_workspace.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hook 흐름
|
||||||
|
```text
|
||||||
|
apply_patch/Edit/Write
|
||||||
|
-> .codex/hooks/tdd-guard.py
|
||||||
|
-> C++ production changes require related tests
|
||||||
|
|
||||||
|
git commit command
|
||||||
|
-> .codex/hooks/pre_commit_checks.py
|
||||||
|
-> Python Harness self-tests
|
||||||
|
-> scripts/validate_workspace.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation 흐름
|
||||||
|
```text
|
||||||
|
HARNESS_VALIDATION_COMMANDS set
|
||||||
|
-> run exact commands
|
||||||
|
|
||||||
|
Always, unless HARNESS_VALIDATION_COMMANDS overrides:
|
||||||
|
-> scripts/validate_reference_artifacts.py
|
||||||
|
-> scripts/validate_fortran.py
|
||||||
|
|
||||||
|
CMakePresets.json has msvc-debug configure preset
|
||||||
|
-> cmake --preset msvc-debug
|
||||||
|
-> cmake --build preset binary dir --config Debug
|
||||||
|
-> ctest --test-dir preset binary dir -C Debug
|
||||||
|
|
||||||
|
CMakeLists.txt exists
|
||||||
|
-> cmake -S . -B build/msvc-debug -G "Visual Studio 17 2022" -A x64
|
||||||
|
-> cmake --build build/msvc-debug --config Debug
|
||||||
|
-> ctest --test-dir build/msvc-debug --output-on-failure -C Debug
|
||||||
|
|
||||||
|
No CMake project
|
||||||
|
-> print guidance and exit successfully
|
||||||
|
|
||||||
|
HARNESS_ABAQUS_VALIDATION=detect
|
||||||
|
-> report Abaqus executable discovery only
|
||||||
|
|
||||||
|
HARNESS_ABAQUS_VALIDATION=run
|
||||||
|
-> run HARNESS_ABAQUS_VALIDATION_COMMANDS only
|
||||||
|
-> never generate reference CSVs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Abaqus UserSubroutine 확장
|
||||||
|
|
||||||
|
Fortran Abaqus UserSubroutine 개발은 thin Abaqus ABI wrapper와 no-Abaqus kernel/fake-driver tests를 분리한다.
|
||||||
|
기본 workspace validation은 Abaqus를 실행하지 않으며, Intel oneAPI Fortran compiler가 감지되고 `tests/fortran/manifest.json`이 있을 때만 Fortran compile/run tests를 수행한다.
|
||||||
|
Stored reference artifacts under `references/<feature-id>/<model-id>/` are read-only and validated through metadata, source hashes, log tails, and declared CSV files.
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
# PRD: C++/MSVC Harness
|
||||||
|
|
||||||
|
## 목표
|
||||||
|
Codex Harness가 C++/MSVC 프로젝트에서 phase planning, TDD guard, commit validation, workspace validation을 일관되게 수행하게 한다.
|
||||||
|
|
||||||
|
## 사용자
|
||||||
|
- Windows/MSVC 기반 C++ 개발자
|
||||||
|
- Harness phase를 작성하고 실행하는 Codex agent
|
||||||
|
- Harness 결과를 검토하는 reviewer
|
||||||
|
|
||||||
|
## 핵심 기능
|
||||||
|
1. CMake/MSVC/x64/Debug 기반 workspace validation
|
||||||
|
2. C++ source/header 변경에 대한 엄격한 TDD guard
|
||||||
|
3. npm 없이 Python self-test와 CMake/CTest 검증을 수행하는 pre-commit hook
|
||||||
|
4. C++ 프로젝트에 맞는 Harness workflow/review prompt
|
||||||
|
5. CMake project가 아직 없어도 Harness 자체 테스트가 가능한 no-op validation path
|
||||||
|
6. Fortran Abaqus UserSubroutine source 변경에 대한 no-Abaqus TDD guard
|
||||||
|
7. Intel oneAPI Fortran 기반 kernel/fake-driver validation
|
||||||
|
8. Abaqus 실행 opt-in validation과 reference artifact metadata validation
|
||||||
|
|
||||||
|
## 제외 사항
|
||||||
|
- 이전 FESA solver source tree 복원
|
||||||
|
- JavaScript/TypeScript fallback 유지
|
||||||
|
- Abaqus reference artifact 생성 또는 solver reference 비교 구현
|
||||||
|
- Visual Studio `.sln`/`.vcxproj` 전용 MSBuild workflow
|
||||||
|
- 기본 validation에서 Abaqus job 자동 실행
|
||||||
@@ -0,0 +1,365 @@
|
|||||||
|
# 구조해석 솔버 개발 Agent 구성안
|
||||||
|
|
||||||
|
## 목적
|
||||||
|
이 문서는 Abaqus, Nastran과 같은 유한요소법 기반 구조해석 솔버를 개발하기 위한 AI Agent 운영 구성을 정의한다.
|
||||||
|
|
||||||
|
이번 구성안은 ALL-FEM 논문의 구조를 확장하거나 재사용하는 계획이 아니다. 논문은 Agent 설계를 위한 참고 자료로만 사용하며, 본 프로젝트는 C++/MSVC 기반 독립 솔버 개발 워크플로우를 따른다.
|
||||||
|
|
||||||
|
## 설계 원칙
|
||||||
|
- 기능 요구조건, 이론 정식화, 코드 구현, 검증, 배포 역할을 분리한다.
|
||||||
|
- 실행 가능성만으로 성공을 판단하지 않고, 레퍼런스 결과와 물리량을 비교해 기능 완료를 판정한다.
|
||||||
|
- 테스트는 구현 전에 준비한다. 개발 대상 솔버 테스트와 레퍼런스 솔버 결과 비교 테스트를 함께 사용한다.
|
||||||
|
- Abaqus나 Nastran을 Agent가 직접 실행하지 않는다. `references/`에 저장된 입력 파일과 레퍼런스 CSV 결과를 검증 기준으로 사용한다.
|
||||||
|
- 기본 개발 환경은 C++17 이상, MSVC, CMake, CTest이다.
|
||||||
|
- 모든 기능은 tolerance 기준을 명시하고, 기준을 만족할 때만 배포 후보가 된다.
|
||||||
|
|
||||||
|
## 전체 Agent 구성
|
||||||
|
|
||||||
|
### Coordinator Agent
|
||||||
|
전체 개발 흐름을 관리하는 상위 조정 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 기능 개발 요청을 단계별 작업으로 분해한다.
|
||||||
|
- 각 Agent의 산출물을 연결하고 누락된 결정을 추적한다.
|
||||||
|
- 요구조건, 정식화, 테스트, 구현, 검증, 배포 단계의 진행 상태를 관리한다.
|
||||||
|
- 실패 시 어떤 Agent로 되돌릴지 결정한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 기능별 개발 계획
|
||||||
|
- 단계별 승인 상태
|
||||||
|
- 실패 원인과 재작업 지시
|
||||||
|
|
||||||
|
### Requirement Agent
|
||||||
|
솔버 기능 요구조건을 정의하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 해석 기능의 범위, 입력, 출력, 제약조건을 정의한다.
|
||||||
|
- 대상 요소, 재료 모델, 경계조건, 하중 조건, 해석 타입을 명확히 한다.
|
||||||
|
- 검증해야 할 물리량과 tolerance 기준을 정한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 기능 요구조건 문서
|
||||||
|
- acceptance criteria
|
||||||
|
- 검증 물리량 목록
|
||||||
|
|
||||||
|
예시 검증 물리량:
|
||||||
|
- 절점 변위
|
||||||
|
- 반력
|
||||||
|
- 요소 내력
|
||||||
|
- 응력
|
||||||
|
- 변형률
|
||||||
|
- 에너지 또는 잔차 기준
|
||||||
|
|
||||||
|
### Research Agent
|
||||||
|
책, 논문, 매뉴얼, 공개 benchmark를 조사하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 유한요소 정식화에 필요한 이론 자료를 수집한다.
|
||||||
|
- 요소별 benchmark와 patch test 사례를 찾는다.
|
||||||
|
- Abaqus/Nastran 결과와 비교할 수 있는 공개 예제 또는 문헌 해를 조사한다.
|
||||||
|
- 자료의 신뢰도와 적용 범위를 평가한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 연구자료 요약
|
||||||
|
- 공식, 가정, 한계 정리
|
||||||
|
- benchmark 후보 목록
|
||||||
|
|
||||||
|
### Formulation Agent
|
||||||
|
코드 구현을 위한 유한요소 정식화를 작성하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 약형, 형상함수, B matrix, constitutive matrix, 수치적분, 요소 강성 행렬을 정의한다.
|
||||||
|
- 자유도 배치, 좌표계, 단위계, 부호 규약을 명확히 한다.
|
||||||
|
- 선형/비선형, 정적/동적, small/large deformation 여부를 구분한다.
|
||||||
|
- 구현 가능한 알고리즘 형태로 정식화를 정리한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 요소별 정식화 문서
|
||||||
|
- 알고리즘 의사코드
|
||||||
|
- 수치적분 규칙
|
||||||
|
- edge case와 singular case 목록
|
||||||
|
|
||||||
|
### Numerical Review Agent
|
||||||
|
정식화와 수치 알고리즘을 독립 검토하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 수식의 차원, 부호, 좌표 변환, 적분 규칙을 검토한다.
|
||||||
|
- rigid body mode, patch test, symmetry, positive definiteness 등 기본 수치 조건을 확인한다.
|
||||||
|
- locking, hourglass mode, ill-conditioning 같은 위험을 식별한다.
|
||||||
|
- 구현 전 정식화 오류를 줄인다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 정식화 리뷰 결과
|
||||||
|
- 수치 위험 목록
|
||||||
|
- 추가 테스트 요구사항
|
||||||
|
|
||||||
|
### I/O Definition Agent
|
||||||
|
솔버 입력과 출력 데이터 구조를 정의하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- mesh, node, element, material, section, boundary condition, load, step 입력 형식을 정의한다.
|
||||||
|
- 출력 CSV 또는 result file schema를 정의한다.
|
||||||
|
- Abaqus input file과 내부 입력 모델 사이의 대응 관계를 정리한다.
|
||||||
|
- 결과 비교를 위해 레퍼런스 CSV와 구현 솔버 출력의 컬럼 규약을 맞춘다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 입력 데이터 schema
|
||||||
|
- 출력 데이터 schema
|
||||||
|
- 결과 비교용 CSV schema
|
||||||
|
- 단위와 좌표계 규약
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
TDD와 검증에 사용할 테스트 모델을 준비하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 개발 대상 기능을 검증할 최소 모델, benchmark 모델, 회귀 모델을 설계한다.
|
||||||
|
- `references/`에 보관할 Abaqus input file과 Abaqus 결과 CSV 요구사항을 정의한다.
|
||||||
|
- 레퍼런스 결과에 포함될 물리량과 tolerance를 명시한다.
|
||||||
|
- 테스트 모델이 요구조건을 실제로 검증하는지 확인한다.
|
||||||
|
|
||||||
|
중요 제약:
|
||||||
|
- Agent는 Abaqus를 직접 실행하지 않는다.
|
||||||
|
- Abaqus 해석 결과는 사람이 생성하거나 별도 승인된 절차로 생성해 `references/`에 저장한다.
|
||||||
|
- Agent는 저장된 reference artifact만 사용해 비교한다.
|
||||||
|
|
||||||
|
권장 reference 구조:
|
||||||
|
```text
|
||||||
|
references/
|
||||||
|
<feature-name>/
|
||||||
|
model.inp
|
||||||
|
metadata.json
|
||||||
|
displacements.csv
|
||||||
|
reactions.csv
|
||||||
|
element_forces.csv
|
||||||
|
stresses.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
코드 구현 전에 작업 단위와 테스트 순서를 설계하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 요구조건과 정식화를 C++ 구현 작업으로 분해한다.
|
||||||
|
- 먼저 작성할 단위 테스트, 통합 테스트, 레퍼런스 비교 테스트를 정의한다.
|
||||||
|
- 기존 architecture와 ownership boundary에 맞춰 변경 파일을 제한한다.
|
||||||
|
- 구현 Agent가 따라야 할 acceptance criteria를 제공한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 구현 계획
|
||||||
|
- 테스트 우선순위
|
||||||
|
- 변경 파일 후보
|
||||||
|
- acceptance checklist
|
||||||
|
|
||||||
|
### Implementation Agent
|
||||||
|
C++ 코드를 구현하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 테스트를 먼저 작성하고 실패를 확인한다.
|
||||||
|
- 정식화와 I/O schema에 맞춰 최소 구현을 작성한다.
|
||||||
|
- C++17 이상, MSVC, CMake, CTest 환경에서 동작하도록 구현한다.
|
||||||
|
- 불필요한 일반화나 speculative abstraction을 피한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- C++ source/header 변경
|
||||||
|
- 테스트 코드
|
||||||
|
- CMake/CTest 변경
|
||||||
|
|
||||||
|
### Build/Test Executor Agent
|
||||||
|
빌드와 테스트를 실행하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- Harness validation을 실행한다.
|
||||||
|
- MSVC x64 Debug CMake configure/build/CTest 결과를 수집한다.
|
||||||
|
- 실패 로그를 요약하고 Correction Agent에 전달한다.
|
||||||
|
|
||||||
|
기본 검증 명령:
|
||||||
|
```powershell
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
```
|
||||||
|
|
||||||
|
검증 대상:
|
||||||
|
- CMake configure
|
||||||
|
- MSVC Debug build
|
||||||
|
- CTest
|
||||||
|
- Harness self-test
|
||||||
|
|
||||||
|
### Correction Agent
|
||||||
|
빌드, 테스트, 런타임 실패를 수정하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 실패 로그를 원인별로 분류한다.
|
||||||
|
- 컴파일 오류, 링크 오류, 테스트 실패, 결과 비교 실패를 구분한다.
|
||||||
|
- 최소 수정으로 실패를 해결한다.
|
||||||
|
- 같은 실패가 반복되면 Coordinator Agent에 차단 상태를 보고한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 수정 패치
|
||||||
|
- 실패 원인 요약
|
||||||
|
- 재검증 요청
|
||||||
|
|
||||||
|
### Reference Verification Agent
|
||||||
|
구현 솔버 결과와 저장된 레퍼런스 결과를 비교하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 구현 솔버 결과 CSV와 `references/`의 Abaqus CSV를 비교한다.
|
||||||
|
- 절점 변위, 반력, 요소 내력, 응력의 tolerance 만족 여부를 평가한다.
|
||||||
|
- absolute tolerance, relative tolerance, norm-based tolerance를 구분해 적용한다.
|
||||||
|
- 결과 차이가 tolerance 밖이면 원인 후보를 분류한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- reference comparison report
|
||||||
|
- 실패한 물리량과 위치
|
||||||
|
- 최대 오차, 평균 오차, norm 오차
|
||||||
|
|
||||||
|
### Physics Evaluation Agent
|
||||||
|
수치 결과가 물리적으로 타당한지 검토하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 레퍼런스와 수치적으로 비슷해도 물리적으로 이상한 결과가 있는지 확인한다.
|
||||||
|
- 변위 방향, 반력 평형, 응력 집중, 대칭 조건, rigid body mode를 검토한다.
|
||||||
|
- 테스트 모델이 기능을 충분히 검증하지 못하면 추가 모델을 요구한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- 물리 검토 결과
|
||||||
|
- 추가 검증 모델 요구사항
|
||||||
|
- release 가능 여부 의견
|
||||||
|
|
||||||
|
### Release Agent
|
||||||
|
기능 배포 준비를 담당하는 Agent이다.
|
||||||
|
|
||||||
|
책임:
|
||||||
|
- 요구조건, 테스트, 레퍼런스 비교, 물리 검토가 모두 통과했는지 확인한다.
|
||||||
|
- 기능 문서와 release note를 정리한다.
|
||||||
|
- 알려진 제한사항과 tolerance 기준을 기록한다.
|
||||||
|
|
||||||
|
주요 산출물:
|
||||||
|
- release checklist
|
||||||
|
- 기능 문서
|
||||||
|
- known limitations
|
||||||
|
|
||||||
|
## 개발 프로세스 매핑
|
||||||
|
|
||||||
|
| 개발 과정 | 담당 Agent | 필수 산출물 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 1. 솔버 기능 요구조건 정의 | Requirement Agent | 요구조건, acceptance criteria |
|
||||||
|
| 2. 연구자료 조사 | Research Agent | 자료 요약, benchmark 후보 |
|
||||||
|
| 3. 유한요소 정식화 | Formulation Agent, Numerical Review Agent | 정식화 문서, 리뷰 결과 |
|
||||||
|
| 4. 입출력 데이터 정의 | I/O Definition Agent | 입력/출력 schema |
|
||||||
|
| 5. TDD 테스트모델 작성 | Reference Model Agent, Implementation Planning Agent | 테스트 모델, reference artifact 요구사항 |
|
||||||
|
| 6. 코드 구현 | Implementation Agent | C++ 코드, 테스트 |
|
||||||
|
| 7. 레퍼런스 결과 비교 검증 | Reference Verification Agent, Physics Evaluation Agent | 비교 리포트, 물리 검토 |
|
||||||
|
| 8. tolerance 만족 시 완료 | Coordinator Agent | 기능 완료 승인 |
|
||||||
|
| 9. 기능 배포 | Release Agent | release checklist, 문서 |
|
||||||
|
|
||||||
|
## 표준 작업 흐름
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A["기능 요청"] --> B["Requirement Agent"]
|
||||||
|
B --> C["Research Agent"]
|
||||||
|
C --> D["Formulation Agent"]
|
||||||
|
D --> E["Numerical Review Agent"]
|
||||||
|
E --> F["I/O Definition Agent"]
|
||||||
|
F --> G["Reference Model Agent"]
|
||||||
|
G --> H["Implementation Planning Agent"]
|
||||||
|
H --> I["Implementation Agent"]
|
||||||
|
I --> J["Build/Test Executor Agent"]
|
||||||
|
J --> K{"빌드/테스트 통과?"}
|
||||||
|
K -- "아니오" --> L["Correction Agent"]
|
||||||
|
L --> I
|
||||||
|
K -- "예" --> M["Reference Verification Agent"]
|
||||||
|
M --> N{"tolerance 만족?"}
|
||||||
|
N -- "아니오" --> O["Physics Evaluation Agent"]
|
||||||
|
O --> L
|
||||||
|
N -- "예" --> P["Physics Evaluation Agent"]
|
||||||
|
P --> Q{"물리 검토 통과?"}
|
||||||
|
Q -- "아니오" --> L
|
||||||
|
Q -- "예" --> R["Release Agent"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 검증 Gate
|
||||||
|
|
||||||
|
### Gate 1: 요구조건 승인
|
||||||
|
통과 조건:
|
||||||
|
- 대상 기능과 제외 범위가 명확하다.
|
||||||
|
- 입력, 출력, tolerance, 검증 물리량이 정의되어 있다.
|
||||||
|
- 레퍼런스 비교 방식이 정해져 있다.
|
||||||
|
|
||||||
|
### Gate 2: 정식화 승인
|
||||||
|
통과 조건:
|
||||||
|
- 요소 정식화와 수치적분 규칙이 문서화되어 있다.
|
||||||
|
- 좌표계, 자유도, 부호 규약이 명확하다.
|
||||||
|
- Numerical Review Agent가 주요 수치 위험을 검토했다.
|
||||||
|
|
||||||
|
### Gate 3: 테스트 준비 승인
|
||||||
|
통과 조건:
|
||||||
|
- 구현 전 실패해야 하는 테스트가 정의되어 있다.
|
||||||
|
- `references/` artifact 요구사항이 명확하다.
|
||||||
|
- 최소 모델, benchmark 모델, 회귀 모델의 목적이 구분되어 있다.
|
||||||
|
|
||||||
|
### Gate 4: 구현 검증
|
||||||
|
통과 조건:
|
||||||
|
- CMake/MSVC/CTest validation이 통과한다.
|
||||||
|
- 단위 테스트와 통합 테스트가 통과한다.
|
||||||
|
- Harness TDD guard를 만족한다.
|
||||||
|
|
||||||
|
### Gate 5: 레퍼런스 검증
|
||||||
|
통과 조건:
|
||||||
|
- 저장된 Abaqus CSV 결과와 구현 솔버 결과가 tolerance 안에 있다.
|
||||||
|
- 절점 변위, 반력, 요소 내력, 응력 비교 결과가 리포트로 남아 있다.
|
||||||
|
- 실패한 물리량이 없거나 승인된 known limitation으로 기록되어 있다.
|
||||||
|
|
||||||
|
### Gate 6: 배포 승인
|
||||||
|
통과 조건:
|
||||||
|
- 요구조건의 acceptance criteria가 모두 만족된다.
|
||||||
|
- 문서와 release note가 준비되어 있다.
|
||||||
|
- 남은 제한사항이 명확히 기록되어 있다.
|
||||||
|
|
||||||
|
## Reference CSV 비교 기준
|
||||||
|
|
||||||
|
권장 비교 방식:
|
||||||
|
- scalar 값: absolute tolerance와 relative tolerance를 함께 적용한다.
|
||||||
|
- vector 값: component-wise 비교와 norm 비교를 함께 기록한다.
|
||||||
|
- stress tensor: component-wise 비교를 기본으로 하고, 필요한 경우 principal stress 또는 von Mises stress를 추가 비교한다.
|
||||||
|
- 반력: 전체 하중 평형과 개별 구속 자유도 반력을 모두 확인한다.
|
||||||
|
|
||||||
|
권장 리포트 항목:
|
||||||
|
- model name
|
||||||
|
- compared quantity
|
||||||
|
- number of compared rows
|
||||||
|
- maximum absolute error
|
||||||
|
- maximum relative error
|
||||||
|
- RMS error
|
||||||
|
- worst node or element id
|
||||||
|
- pass/fail
|
||||||
|
|
||||||
|
## 반복 실패 처리
|
||||||
|
|
||||||
|
반복 실패가 발생하면 Correction Agent가 무한 수정 루프를 계속하지 않는다. 다음 중 하나로 분류해 Coordinator Agent에 보고한다.
|
||||||
|
|
||||||
|
- 요구조건 불명확
|
||||||
|
- 정식화 오류 가능성
|
||||||
|
- reference artifact 오류 가능성
|
||||||
|
- I/O schema 불일치
|
||||||
|
- 구현 결함
|
||||||
|
- tolerance 기준 부적절
|
||||||
|
- 테스트 모델이 기능을 과도하게 또는 불충분하게 검증함
|
||||||
|
|
||||||
|
Coordinator Agent는 분류 결과에 따라 Requirement, Formulation, I/O Definition, Reference Model, Implementation Agent 중 적절한 단계로 되돌린다.
|
||||||
|
|
||||||
|
## 초기 적용 우선순위
|
||||||
|
|
||||||
|
1. 선형 정적 해석의 최소 골격
|
||||||
|
2. 1D truss 또는 bar element
|
||||||
|
3. 2D plane stress/plane strain element
|
||||||
|
4. 3D solid element
|
||||||
|
5. material model 확장
|
||||||
|
6. nonlinear 또는 dynamic analysis 확장
|
||||||
|
|
||||||
|
각 단계는 요구조건, 정식화, 테스트모델, 구현, 레퍼런스 비교, 배포 Gate를 독립적으로 통과해야 한다.
|
||||||
|
|
||||||
|
## 운영 메모
|
||||||
|
|
||||||
|
- Agent 산출물은 가능한 한 문서, 테스트, 비교 리포트 형태로 남긴다.
|
||||||
|
- 사람이 생성한 Abaqus reference artifact의 출처와 생성 조건을 `metadata.json`에 기록한다.
|
||||||
|
- reference artifact가 바뀌면 기능 구현 변경과 같은 수준으로 검토한다.
|
||||||
|
- 기능 완료 판정은 코드 실행 성공이 아니라 reference validation과 physics evaluation 통과를 기준으로 한다.
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# FESA Solver Skill Rebuild Plan
|
||||||
|
|
||||||
|
## 목적
|
||||||
|
|
||||||
|
이 문서는 FESA 유한요소 기반 구조해석 솔버 개발에 사용할 project-local Codex skill 구성을 정의한다.
|
||||||
|
|
||||||
|
Agent는 역할과 책임 단위이고, skill은 여러 Agent가 반복적으로 사용하는 절차와 검증 도구 단위다. 따라서 skill은 Agent와 1:1로 대응하지 않는다. 대신 요구조건, 연구, 정식화, I/O 계약, reference model, C++ TDD 구현, reference 비교, 물리 검토, release readiness처럼 솔버 개발 과정에서 반복되는 작업 흐름을 기준으로 구성한다.
|
||||||
|
|
||||||
|
## 설계 원칙
|
||||||
|
|
||||||
|
- Skill은 `.codex/skills/<skill-name>/SKILL.md`에 둔다.
|
||||||
|
- 각 skill은 필수 frontmatter `name`, `description`과 UI metadata `agents/openai.yaml`을 가진다.
|
||||||
|
- Skill 본문은 agent TOML의 역할 설명을 반복하지 않고, 입력, 절차, 산출물, 금지사항, 품질 gate, handoff를 정의한다.
|
||||||
|
- Skill은 `AGENTS.md`와 `docs/SOLVER_AGENT_DESIGN.md`를 공통 상위 기준으로 읽는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver 실행은 skill 범위에 포함하지 않는다.
|
||||||
|
- Reference CSV 생성 또는 수정은 skill 범위에 포함하지 않는다.
|
||||||
|
- C++ 구현 관련 skill은 C++17 이상, MSVC, CMake, CTest, TDD 원칙을 따른다.
|
||||||
|
- 기본 workspace validation 명령은 `python scripts/validate_workspace.py`이다.
|
||||||
|
|
||||||
|
## Skill 구성
|
||||||
|
|
||||||
|
| Skill | 적용 개발 과정 | 주요 사용자 Agent | 대표 산출물 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `fesa-requirements-baseline` | 1. 솔버 기능 요구조건 정의 | Requirement Agent, Coordinator Agent | `docs/requirements/<feature-id>.md` |
|
||||||
|
| `fesa-research-evidence` | 2. 책, 논문 등 연구자료 조사 | Research Agent, Formulation Agent | `docs/research/<feature-id>-research.md` |
|
||||||
|
| `fesa-formulation-spec` | 3. 코드 구현을 위한 유한요소 정식화 | Formulation Agent, Implementation Planning Agent | `docs/formulations/<feature-id>-formulation.md` |
|
||||||
|
| `fesa-numerical-review` | 3. 정식화 독립 수치 검토 | Numerical Review Agent, Coordinator Agent | `docs/numerical-reviews/<feature-id>-review.md` |
|
||||||
|
| `fesa-io-contract` | 4. 솔버 입출력 데이터 정의 | I/O Definition Agent, Reference Verification Agent | `docs/io-definitions/<feature-id>-io.md` |
|
||||||
|
| `fesa-reference-models` | 5. TDD/reference 테스트모델 작성 | Reference Model Agent, Implementation Planning Agent | `docs/reference-models/<feature-id>-reference-models.md` |
|
||||||
|
| `fesa-cpp-msvc-tdd` | 6. 코드 구현 및 build/test correction | Implementation Planning Agent, Implementation Agent, Build/Test Executor Agent, Correction Agent | implementation plan/report, build/test report, correction report |
|
||||||
|
| `fesa-reference-comparison` | 7. reference solver 결과와 구현 solver 결과 비교 | Reference Verification Agent | `docs/reference-verifications/<feature-id>-reference-verification.md` |
|
||||||
|
| `fesa-physics-sanity` | 8. tolerance 통과 후 물리 타당성 검토 | Physics Evaluation Agent | `docs/physics-evaluations/<feature-id>-physics-evaluation.md` |
|
||||||
|
| `fesa-release-readiness` | 9. 솔버 기능 배포 준비 | Release Agent, Coordinator Agent | `docs/releases/<feature-id>-release.md` |
|
||||||
|
|
||||||
|
## 개발 과정별 사용 예
|
||||||
|
|
||||||
|
예시 기능: `linear-truss-1d`
|
||||||
|
|
||||||
|
1. Requirement Agent는 `fesa-requirements-baseline`을 사용해 기능 범위, 제외 범위, 입력, 출력, 검증 물리량, tolerance, `Requirement Verification Matrix`를 작성한다.
|
||||||
|
2. Research Agent는 `fesa-research-evidence`를 사용해 truss/bar element 이론, benchmark 후보, source reliability, applicability limits를 정리한다.
|
||||||
|
3. Formulation Agent는 `fesa-formulation-spec`을 사용해 strong form, weak form, shape functions, B matrix, element stiffness, output recovery를 정리한다.
|
||||||
|
4. Numerical Review Agent는 `fesa-numerical-review`를 사용해 rigid body modes, patch test, stiffness symmetry, Jacobian, locking 위험을 검토하고 `pass-for-implementation-planning` 여부를 판단한다.
|
||||||
|
5. I/O Definition Agent는 `fesa-io-contract`를 사용해 지원할 Abaqus `.inp` keyword subset과 `displacements.csv`, `reactions.csv`, `element_forces.csv`, `stresses.csv` schema를 정의한다.
|
||||||
|
6. Reference Model Agent는 `fesa-reference-models`를 사용해 `references/linear-truss-1d/<model-id>/` artifact bundle 계약과 coverage matrix를 작성한다.
|
||||||
|
7. Implementation Planning Agent와 Implementation Agent는 `fesa-cpp-msvc-tdd`를 사용해 테스트 작성, 실패 확인, 최소 구현, CMake/CTest 등록, validation을 수행한다.
|
||||||
|
8. Reference Verification Agent는 `fesa-reference-comparison`을 사용해 구현 solver CSV와 저장된 reference CSV를 tolerance 기준으로 비교한다.
|
||||||
|
9. Physics Evaluation Agent는 `fesa-physics-sanity`를 사용해 global equilibrium, reaction consistency, displacement direction, symmetry, model coverage를 검토한다.
|
||||||
|
10. Release Agent는 `fesa-release-readiness`를 사용해 gate evidence, acceptance traceability, known limitations, release notes draft를 작성한다.
|
||||||
|
|
||||||
|
## Skill별 핵심 계약
|
||||||
|
|
||||||
|
### `fesa-requirements-baseline`
|
||||||
|
|
||||||
|
- 기능 요청을 검증 가능한 요구조건 baseline으로 만든다.
|
||||||
|
- `shall` 문장과 `FESA-REQ-<FEATURE>-###` id를 사용한다.
|
||||||
|
- 모든 `must` 요구조건은 verification method와 acceptance criteria를 가져야 한다.
|
||||||
|
- FEM 정식화, C++ 구현, reference CSV 생성, release readiness 판단은 하지 않는다.
|
||||||
|
|
||||||
|
### `fesa-research-evidence`
|
||||||
|
|
||||||
|
- 연구 질문, source inventory, source reliability tier, benchmark 후보를 정리한다.
|
||||||
|
- 검증된 사실과 추론을 분리한다.
|
||||||
|
- source gap은 open issue로 남긴다.
|
||||||
|
- FEM 정식화 확정이나 reference value 생성을 하지 않는다.
|
||||||
|
|
||||||
|
### `fesa-formulation-spec`
|
||||||
|
|
||||||
|
- strong form, weak form, discretization, kinematics, constitutive contract, element equations를 구분해 작성한다.
|
||||||
|
- Jacobian, derivative transform, numerical integration, output recovery, numerical risks를 명시한다.
|
||||||
|
- C++ API, parser, file ownership은 설계하지 않는다.
|
||||||
|
- Numerical Review Agent 검토 전 최종 승인 상태로 두지 않는다.
|
||||||
|
|
||||||
|
### `fesa-numerical-review`
|
||||||
|
|
||||||
|
- 정식화를 수치 알고리즘 계약으로 독립 검토한다.
|
||||||
|
- dimensions, signs, DOF ordering, coordinate transforms, Jacobian, integration rule, stiffness symmetry, rigid body modes, patch test, hourglass, locking을 확인한다.
|
||||||
|
- `pass-for-implementation-planning`은 구현 계획 가능 상태만 의미한다.
|
||||||
|
- 정식화 문서를 직접 수정하지 않는다.
|
||||||
|
|
||||||
|
### `fesa-io-contract`
|
||||||
|
|
||||||
|
- FESA solver input이 지원할 Abaqus `.inp` subset을 정의한다.
|
||||||
|
- model data와 history data를 구분한다.
|
||||||
|
- 내부 semantic model 계약과 output/CSV schema를 정의한다.
|
||||||
|
- parser 구현이나 full Abaqus compatibility claim은 하지 않는다.
|
||||||
|
|
||||||
|
### `fesa-reference-models`
|
||||||
|
|
||||||
|
- smoke, analytical, patch test, benchmark, regression, negative/invalid-input 모델을 구분한다.
|
||||||
|
- `references/<feature-id>/<model-id>/` artifact bundle 계약을 정의한다.
|
||||||
|
- `model.inp`, `metadata.json`, `displacements.csv`, `reactions.csv`, `element_forces.csv`, `stresses.csv`를 기준 artifact로 둔다.
|
||||||
|
- Reference CSV가 없으면 완료 상태가 아니라 `needs-reference-artifacts`로 둔다.
|
||||||
|
|
||||||
|
### `fesa-cpp-msvc-tdd`
|
||||||
|
|
||||||
|
- C++ 구현을 `RED -> GREEN -> VERIFY` 순서로 수행한다.
|
||||||
|
- C++ production 변경에는 관련 C++ test file이 있어야 한다.
|
||||||
|
- 기본 검증 명령:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
ctest -C Debug -R <feature-or-label>
|
||||||
|
```
|
||||||
|
|
||||||
|
- 실패는 `configure | compile | link | test | reference-comparison | harness | environment | upstream-contract`로 분류한다.
|
||||||
|
- 요구조건, 정식화, I/O 계약, reference artifact, tolerance policy를 바꾸지 않는다.
|
||||||
|
|
||||||
|
### `fesa-reference-comparison`
|
||||||
|
|
||||||
|
- `ARTIFACT CHECK -> COMPARE -> CLASSIFY -> REPORT` 순서로 수행한다.
|
||||||
|
- `metadata.json`, schema version, units, coordinate system, step/frame identity, ID matching, output location, tolerance source를 확인한다.
|
||||||
|
- max absolute error, max relative error, RMS error, norm error, missing rows, extra rows를 보고한다.
|
||||||
|
- Reference pass는 physics validation이나 release readiness를 의미하지 않는다.
|
||||||
|
|
||||||
|
### `fesa-physics-sanity`
|
||||||
|
|
||||||
|
- Reference comparison 통과 후 물리 타당성을 검토한다.
|
||||||
|
- global equilibrium, reaction consistency, displacement direction, symmetry, element force balance, stress/strain sanity, rigid body mode, model coverage를 확인한다.
|
||||||
|
- 문서화된 물리 기대값이 없으면 pass를 선언하지 않는다.
|
||||||
|
- `pass-for-release-agent`는 Release Agent 검토 가능 상태만 의미한다.
|
||||||
|
|
||||||
|
### `fesa-release-readiness`
|
||||||
|
|
||||||
|
- `GATE AUDIT -> TRACEABILITY CHECK -> RELEASE DOCUMENTATION -> RELEASE VERDICT` 순서로 수행한다.
|
||||||
|
- `pass-for-reference-verification`, `pass-for-physics-evaluation`, `pass-for-release-agent` evidence를 요구한다.
|
||||||
|
- Known Limitations와 Release Notes Draft를 작성한다.
|
||||||
|
- 사용자 명시 요청 없이 publish, deploy, package, tag, commit, external release를 수행하지 않는다.
|
||||||
|
|
||||||
|
## Agent와 Skill 관계
|
||||||
|
|
||||||
|
| Agent | 주로 사용하는 Skill |
|
||||||
|
| --- | --- |
|
||||||
|
| Coordinator Agent | `fesa-requirements-baseline`, `fesa-reference-models`, `fesa-release-readiness` |
|
||||||
|
| Requirement Agent | `fesa-requirements-baseline` |
|
||||||
|
| Research Agent | `fesa-research-evidence` |
|
||||||
|
| Formulation Agent | `fesa-formulation-spec` |
|
||||||
|
| Numerical Review Agent | `fesa-numerical-review` |
|
||||||
|
| I/O Definition Agent | `fesa-io-contract` |
|
||||||
|
| Reference Model Agent | `fesa-reference-models` |
|
||||||
|
| Implementation Planning Agent | `fesa-formulation-spec`, `fesa-reference-models`, `fesa-cpp-msvc-tdd` |
|
||||||
|
| Implementation Agent | `fesa-cpp-msvc-tdd` |
|
||||||
|
| Build/Test Executor Agent | `fesa-cpp-msvc-tdd` |
|
||||||
|
| Correction Agent | `fesa-cpp-msvc-tdd` |
|
||||||
|
| Reference Verification Agent | `fesa-reference-comparison`, `fesa-io-contract` |
|
||||||
|
| Physics Evaluation Agent | `fesa-physics-sanity` |
|
||||||
|
| Release Agent | `fesa-release-readiness` |
|
||||||
|
|
||||||
|
## 검증 기준
|
||||||
|
|
||||||
|
Skill 구성 검증은 `scripts/test_fesa_solver_skills.py`가 담당한다.
|
||||||
|
|
||||||
|
검증 항목:
|
||||||
|
|
||||||
|
- 10개 solver skill의 `SKILL.md` 존재 여부
|
||||||
|
- YAML frontmatter의 `name`, `description`
|
||||||
|
- 공통 섹션: `Inputs`, `Workflow`, `Output Contract`, `Boundaries`, `Quality Gate`, `Handoff`
|
||||||
|
- `AGENTS.md`와 `docs/SOLVER_AGENT_DESIGN.md` 참조
|
||||||
|
- skill-specific 핵심 문구와 산출물 경로
|
||||||
|
- `agents/openai.yaml` UI metadata
|
||||||
|
- 이 문서가 아니라 실제 skill 파일이 기준이 되도록 `docs/SOLVER_SKILL_DESIGN.md`에 대한 skill 본문 참조 금지
|
||||||
|
|
||||||
|
검증 명령:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Skill 구조 검증:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python C:\Users\user\.codex\skills\.system\skill-creator\scripts\quick_validate.py .codex\skills\<skill-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## v1 범위
|
||||||
|
|
||||||
|
- v1은 `SKILL.md`와 `agents/openai.yaml`만 포함한다.
|
||||||
|
- 별도 `scripts/`, `references/`, `assets/`는 만들지 않는다.
|
||||||
|
- 반복 사용 중 절차가 안정화되면 deterministic comparison script, reference artifact template, report template 같은 resource를 별도 후속 작업으로 분리한다.
|
||||||
|
- 이 문서는 skill 구성을 설명하는 계획 문서이며, 실제 실행 지침의 source of truth는 각 `.codex/skills/<skill-name>/SKILL.md`이다.
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# Build/Test Report 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Build/Test Executor Agent가 작성하거나 제안하는 기능별 build/test 실행 리포트를 보관하는 위치다.
|
||||||
|
|
||||||
|
Build/Test Executor Agent는 Implementation Agent 이후 독립적으로 C++/MSVC/CMake/CTest 검증을 실행하고, 실패를 분류해 다음 agent로 handoff한다. 이 agent는 source code, tests, CMake files, requirements, formulations, I/O contracts, reference artifacts, tolerance policies를 수정하지 않는다. build artifacts와 test outputs는 `build/` 아래 생성될 수 있다.
|
||||||
|
|
||||||
|
기본 문서명은 `docs/build-test-reports/<feature-id>-build-test.md` 형식을 사용한다.
|
||||||
|
|
||||||
|
## Build/Test Executor Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- `python scripts/validate_workspace.py`를 기본 검증 명령으로 실행한다.
|
||||||
|
- implementation plan/report에 명시된 경우 harness self-test와 feature-specific CTest를 실행한다.
|
||||||
|
- `HARNESS_VALIDATION_COMMANDS`, `CMakePresets.json`의 `msvc-debug`, 기본 CMake/MSVC x64 Debug 경로 중 어떤 검증 경로가 사용되었는지 기록한다.
|
||||||
|
- configure, compile, link, test, reference-comparison, harness, environment, upstream-contract 실패를 구분한다.
|
||||||
|
- command, exit code, duration, stdout/stderr tail, failed test name을 요약한다.
|
||||||
|
- 실패 원인에 따라 Implementation Agent, Correction Agent, Reference Verification Agent, Implementation Planning Agent 중 handoff 대상을 제안한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- source code를 수정하지 않는다.
|
||||||
|
- tests를 수정하지 않는다.
|
||||||
|
- CMake files를 수정하지 않는다.
|
||||||
|
- requirements, formulations, I/O contracts, reference artifacts, tolerance policies를 수정하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- release readiness, reference tolerance success, physics validation success를 승인하지 않는다.
|
||||||
|
- 최종 reference verification report를 작성하지 않는다.
|
||||||
|
|
||||||
|
## 실행 순서
|
||||||
|
|
||||||
|
기본 순서는 implementation plan/report에 따라 다음 중 필요한 항목만 실행한다.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
python scripts/validate_fortran.py
|
||||||
|
python scripts/validate_reference_artifacts.py
|
||||||
|
ctest -C Debug -R <feature-or-label>
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
```
|
||||||
|
|
||||||
|
`scripts/validate_workspace.py`의 command discovery 우선순위는 다음과 같다.
|
||||||
|
|
||||||
|
1. `HARNESS_VALIDATION_COMMANDS`
|
||||||
|
2. `CMakePresets.json`의 `msvc-debug`
|
||||||
|
3. 기본 CMake/MSVC x64 Debug 명령
|
||||||
|
4. `CMakeLists.txt`가 없고 override도 없으면 안내 메시지와 함께 성공 종료
|
||||||
|
|
||||||
|
For Abaqus UserSubroutine work, workspace validation also supports:
|
||||||
|
|
||||||
|
- `HARNESS_FORTRAN_VALIDATION=off|detect|auto|compile`
|
||||||
|
- `HARNESS_FORTRAN_COMPILER=auto|ifx|ifort`
|
||||||
|
- `HARNESS_ONEAPI_VARS_BAT=<path>`
|
||||||
|
- `HARNESS_ABAQUS_VALIDATION=off|detect|run`
|
||||||
|
- `HARNESS_ABAQUS_COMMAND=<path-or-name>`
|
||||||
|
- `HARNESS_ABAQUS_VALIDATION_COMMANDS=<newline commands>`
|
||||||
|
- `HARNESS_ABAQUS_USE_ONEAPI_ENV=auto|on|off`
|
||||||
|
|
||||||
|
Default validation does not run Abaqus jobs. Abaqus execution is valid only when `HARNESS_ABAQUS_VALIDATION=run` and explicit commands are provided.
|
||||||
|
|
||||||
|
기본 CMake/MSVC x64 Debug 명령은 다음과 같다.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cmake -S . -B build/msvc-debug -G "Visual Studio 17 2022" -A x64
|
||||||
|
cmake --build build/msvc-debug --config Debug
|
||||||
|
ctest --test-dir build/msvc-debug --output-on-failure -C Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Build/Test Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_implementation_report: <path or N/A>
|
||||||
|
- source_implementation_plan: docs/implementation-plans/<feature-id>-implementation-plan.md
|
||||||
|
- status: pass-for-reference-verification | needs-correction | needs-environment-fix | needs-upstream-decision | blocked
|
||||||
|
- owner_agent: build-test-executor-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Execution Environment
|
||||||
|
- os: <OS and version>
|
||||||
|
- generator: Visual Studio 17 2022 | <observed generator>
|
||||||
|
- platform: x64 | <observed platform>
|
||||||
|
- config: Debug | <observed config>
|
||||||
|
- build_dir: build/msvc-debug | <observed build dir>
|
||||||
|
- active_override_env_vars: HARNESS_VALIDATION_COMMANDS | HARNESS_CMAKE_GENERATOR | HARNESS_CMAKE_PLATFORM | HARNESS_CMAKE_CONFIG | HARNESS_BUILD_DIR | none
|
||||||
|
- command_discovery_path: HARNESS_VALIDATION_COMMANDS | CMakePresets.json msvc-debug | default CMake/MSVC x64 Debug | no-CMake informational success
|
||||||
|
|
||||||
|
## Command Log Summary
|
||||||
|
|
||||||
|
| order | command | exit_code | duration | stdout_stderr_tail |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1 | python -m unittest discover -s scripts -p "test_*.py" | <code> | <duration> | <tail summary> |
|
||||||
|
| 2 | ctest -C Debug -R <feature-or-label> | <code> | <duration> | <tail summary> |
|
||||||
|
| 3 | python scripts/validate_workspace.py | <code> | <duration> | <tail summary> |
|
||||||
|
|
||||||
|
## Validation Results
|
||||||
|
|
||||||
|
| validation_stage | result | evidence |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| harness self-test | pass | fail | skipped | <summary> |
|
||||||
|
| configure | pass | fail | skipped | <summary> |
|
||||||
|
| build | pass | fail | skipped | <summary> |
|
||||||
|
| CTest | pass | fail | skipped | <summary> |
|
||||||
|
| feature-specific tests | pass | fail | skipped | <summary> |
|
||||||
|
|
||||||
|
## Failure Classification
|
||||||
|
|
||||||
|
- classification: configure | compile | link | test | reference-comparison | harness | environment | upstream-contract | N/A
|
||||||
|
- primary_failure: <short reason>
|
||||||
|
- first_failed_command: <command or N/A>
|
||||||
|
- evidence_tail: <short excerpt or summary>
|
||||||
|
|
||||||
|
## Failed Test Inventory
|
||||||
|
|
||||||
|
| test_name | label | command | failure_summary |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| <test name> | <label or N/A> | <command> | <summary> |
|
||||||
|
|
||||||
|
## Handoff Recommendation
|
||||||
|
|
||||||
|
| target_agent | reason | required_input |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Implementation Agent | <when implementation-owned failure is found> | <command log and failing test> |
|
||||||
|
| Correction Agent | <when focused repair/rollback is needed> | <failure classification and changed files from implementation report> |
|
||||||
|
| Reference Verification Agent | <when build/test passes and reference comparison report is next> | <passing command evidence> |
|
||||||
|
| Implementation Planning Agent | <when plan/test contract is incomplete> | <missing or contradictory plan item> |
|
||||||
|
|
||||||
|
## No-Change Assertion
|
||||||
|
- source_files_modified: false
|
||||||
|
- test_files_modified: false
|
||||||
|
- cmake_files_modified: false
|
||||||
|
- reference_artifacts_modified: false
|
||||||
|
- notes: <observed no-change evidence or exception>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <environment gap, missing CMake preset, missing reference artifact, repeated failure, or upstream-contract issue>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 상태 값
|
||||||
|
|
||||||
|
- `pass-for-reference-verification`: build/test 검증이 통과해 Reference Verification Agent로 넘길 수 있다.
|
||||||
|
- `needs-correction`: compile, link, ordinary test, implementation-owned failure가 있어 Correction Agent 또는 Implementation Agent 작업이 필요하다.
|
||||||
|
- `needs-environment-fix`: MSVC, CMake generator, Python, path, permission 등 로컬 환경 문제로 검증이 막혔다.
|
||||||
|
- `needs-upstream-decision`: implementation plan, requirements, formulation, I/O, reference artifact, tolerance policy가 불완전하거나 충돌한다.
|
||||||
|
- `blocked`: 반복 실패 또는 외부 조건 때문에 사용자나 Coordinator Agent 결정 없이는 진행할 수 없다.
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 모든 실행 명령과 exit code를 기록해야 한다.
|
||||||
|
- 실패 로그는 전체 원문을 복제하지 않고 마지막 핵심 구간과 실패 원인을 요약한다.
|
||||||
|
- configure, compile, link, test, reference-comparison, harness, environment, upstream-contract 실패를 구분한다.
|
||||||
|
- no-CMake 상황은 `scripts/validate_workspace.py` 정책대로 안내 메시지와 성공 종료로 기록한다.
|
||||||
|
- 성공 판정은 build/test 통과까지만 의미한다.
|
||||||
|
- reference tolerance, physics validation, release readiness는 판정하지 않는다.
|
||||||
|
- upstream 계약 문제는 Implementation Agent에 임의 수정으로 넘기지 않고 적절한 upstream agent로 handoff한다.
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
# Coordination Report 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Coordinator Agent가 작성하거나 제안하는 기능별 workflow coordination report를 보관하는 위치다.
|
||||||
|
|
||||||
|
Coordinator Agent는 FESA solver 기능 개발의 전체 lifecycle에서 gate evidence, handoff, rework loop, blocker, user decision을 관리한다. 이 Agent는 specialist agent의 기술 판정을 대체하지 않고, 다음 agent가 어떤 입력으로 무엇을 산출해야 하는지 명확히 기록한다.
|
||||||
|
|
||||||
|
기본 문서명은 `docs/coordination/<feature-id>-coordination.md` 형식을 사용한다.
|
||||||
|
|
||||||
|
## Coordinator Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- feature request를 `feature_id`, target capability, initial priority, expected first agent로 분류한다.
|
||||||
|
- existing docs/reports/artifacts를 읽고 workflow state를 audit한다.
|
||||||
|
- gate별 source evidence, missing evidence, contradictory evidence를 inventory로 만든다.
|
||||||
|
- 다음 agent handoff package를 작성한다.
|
||||||
|
- repeated failure와 blocker를 추적하고 escalation target을 정한다.
|
||||||
|
- final workflow closure를 기록한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- source code를 수정하지 않는다.
|
||||||
|
- tests를 수정하지 않는다.
|
||||||
|
- CMake files 또는 build configuration을 수정하지 않는다.
|
||||||
|
- build/test validation을 실행하지 않는다.
|
||||||
|
- reference comparison을 실행하지 않는다.
|
||||||
|
- physics evaluation을 실행하지 않는다.
|
||||||
|
- requirements, formulations, I/O contracts, numerical review reports를 수정하지 않는다.
|
||||||
|
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- subagents를 자동 spawn하지 않는다.
|
||||||
|
- release readiness를 독립적으로 승인하지 않는다.
|
||||||
|
|
||||||
|
## 실행 순서
|
||||||
|
|
||||||
|
Coordinator Agent는 다음 순서를 따른다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
INTAKE -> STATE AUDIT -> GATE DECISION -> HANDOFF PACKAGE -> STATUS REPORT
|
||||||
|
```
|
||||||
|
|
||||||
|
`STATE AUDIT`에서는 다음 evidence를 확인한다.
|
||||||
|
|
||||||
|
- Requirement Agent output
|
||||||
|
- Research Agent output
|
||||||
|
- Formulation Agent output
|
||||||
|
- Numerical Review Agent output
|
||||||
|
- I/O Definition Agent output
|
||||||
|
- Reference Model Agent output
|
||||||
|
- Implementation Planning Agent output
|
||||||
|
- Implementation Agent report
|
||||||
|
- Build/Test Executor Agent report
|
||||||
|
- Correction Agent report
|
||||||
|
- Reference Verification Agent report
|
||||||
|
- Physics Evaluation Agent report
|
||||||
|
- Release Agent report
|
||||||
|
- validation command evidence: `python scripts/validate_workspace.py`
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Coordination Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- status: intake | needs-requirements | needs-research | needs-formulation | needs-numerical-review | needs-io-definition | needs-reference-model | needs-implementation-plan | ready-for-implementation | needs-build-test | needs-correction | needs-reference-verification | needs-physics-evaluation | needs-release | ready-for-release | completed | needs-user-decision | blocked
|
||||||
|
- owner_agent: coordinator-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
- source_docs: <docs/reports used>
|
||||||
|
|
||||||
|
## Feature Request Summary
|
||||||
|
- requested_feature: <short summary>
|
||||||
|
- current_goal: <current coordination goal>
|
||||||
|
- included_scope: <included scope>
|
||||||
|
- excluded_scope: <excluded scope>
|
||||||
|
- priority: <initial priority>
|
||||||
|
|
||||||
|
## Current Workflow State
|
||||||
|
|
||||||
|
| item | value | notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| current_gate | <gate> | <notes> |
|
||||||
|
| completed_outputs | <outputs> | <notes> |
|
||||||
|
| missing_outputs | <outputs> | <notes> |
|
||||||
|
| active_blockers | <blockers> | <notes> |
|
||||||
|
| next_eligible_gate | <gate> | <notes> |
|
||||||
|
|
||||||
|
## Gate Evidence Inventory
|
||||||
|
|
||||||
|
| gate | owning_agent | expected_evidence | observed_evidence | status | notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| requirements | Requirement Agent | docs/requirements/<feature-id>.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| research | Research Agent | docs/research/<feature-id>-research.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| formulation | Formulation Agent | docs/formulations/<feature-id>-formulation.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| numerical_review | Numerical Review Agent | docs/numerical-reviews/<feature-id>-review.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| io_definition | I/O Definition Agent | docs/io-definitions/<feature-id>-io.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| reference_model | Reference Model Agent | docs/reference-models/<feature-id>-reference-models.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| implementation_planning | Implementation Planning Agent | docs/implementation-plans/<feature-id>-implementation-plan.md | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| implementation | Implementation Agent | implementation report | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| build_test | Build/Test Executor Agent | pass-for-reference-verification | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| correction | Correction Agent | correction report when needed | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| reference_verification | Reference Verification Agent | pass-for-physics-evaluation | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| physics_evaluation | Physics Evaluation Agent | pass-for-release-agent | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
| release | Release Agent | ready-for-release | <path/status> | pass | fail | missing | <notes> |
|
||||||
|
|
||||||
|
## Decision Log
|
||||||
|
|
||||||
|
| date | decision_type | decision | source_evidence | rationale |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| <YYYY-MM-DD> | gate transition | blocker | user decision | rework decision | <decision> | <path/status> | <reason> |
|
||||||
|
|
||||||
|
## Next Agent Handoff
|
||||||
|
|
||||||
|
| field | value |
|
||||||
|
| --- | --- |
|
||||||
|
| target_agent | <agent name> |
|
||||||
|
| reason | <why this agent is next> |
|
||||||
|
| required_inputs | <docs/reports/artifacts> |
|
||||||
|
| expected_output | <expected report or artifact contract> |
|
||||||
|
| acceptance_gate | <status or gate required after handoff> |
|
||||||
|
| stop_condition | <when the agent should stop and hand back> |
|
||||||
|
| missing_evidence | <missing inputs or decisions> |
|
||||||
|
|
||||||
|
## Traceability Snapshot
|
||||||
|
|
||||||
|
| requirement_id | gate | report | artifact | status | current_disposition |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| <req-id> | <gate> | <report path> | <artifact path> | <status> | <released | deferred | blocked | pending> |
|
||||||
|
|
||||||
|
## Risk and Blocker Register
|
||||||
|
|
||||||
|
| risk_or_blocker | category | owner | status | next_action |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| <issue> | upstream ambiguity | repeated failure | reference artifact gap | environment blocker | <agent/user> | open | mitigated | blocked | <action> |
|
||||||
|
|
||||||
|
## Rework Loop Control
|
||||||
|
|
||||||
|
| failure_classification | correction_attempt_count | escalation_target | stop_condition | notes |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| <classification> | <count> | <agent/user> | <condition> | <notes> |
|
||||||
|
|
||||||
|
## No-Change Assertion
|
||||||
|
- source_files_modified: false
|
||||||
|
- test_files_modified: false
|
||||||
|
- cmake_files_modified: false
|
||||||
|
- reference_artifacts_modified: false
|
||||||
|
- tolerance_policies_modified: false
|
||||||
|
- notes: <observed no-change evidence or exception>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <unresolved user decision, missing evidence, contradictory report, or blocked transition>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 상태 값
|
||||||
|
|
||||||
|
- `intake`: 기능 요청은 들어왔지만 첫 handoff가 완료되지 않았다.
|
||||||
|
- `needs-requirements`: Requirement Agent가 요구조건을 정의하거나 수정해야 한다.
|
||||||
|
- `needs-research`: Research Agent가 source-backed research evidence를 제공하거나 수정해야 한다.
|
||||||
|
- `needs-formulation`: Formulation Agent가 FEM 정식화를 작성하거나 수정해야 한다.
|
||||||
|
- `needs-numerical-review`: Numerical Review Agent가 정식화를 검토하거나 재검토해야 한다.
|
||||||
|
- `needs-io-definition`: I/O Definition Agent가 Abaqus input/output 계약을 정의하거나 수정해야 한다.
|
||||||
|
- `needs-reference-model`: Reference Model Agent가 reference model artifacts를 정의하거나 수정해야 한다.
|
||||||
|
- `needs-implementation-plan`: Implementation Planning Agent가 TDD implementation plan을 작성하거나 수정해야 한다.
|
||||||
|
- `ready-for-implementation`: implementation plan이 준비되었고 downstream 구현을 막는 upstream gate가 없다.
|
||||||
|
- `needs-build-test`: 구현 이후 독립 Build/Test Executor 검증이 필요하다.
|
||||||
|
- `needs-correction`: implementation-owned failure가 있어 Correction Agent가 필요하다.
|
||||||
|
- `needs-reference-verification`: Build/Test evidence가 `pass-for-reference-verification`이다.
|
||||||
|
- `needs-physics-evaluation`: Reference Verification report가 `pass-for-physics-evaluation`이다.
|
||||||
|
- `needs-release`: Physics Evaluation report가 `pass-for-release-agent`이다.
|
||||||
|
- `ready-for-release`: Release Agent report가 `ready-for-release`이고 final closure 기록이 필요하다.
|
||||||
|
- `completed`: Release Agent report가 `ready-for-release`이고 Coordinator가 final workflow closure를 기록했다.
|
||||||
|
- `needs-user-decision`: 사용자 또는 project decision 없이는 안전하게 진행할 수 없다.
|
||||||
|
- `blocked`: 사용자 결정, 환경 변경, upstream correction 없이는 진행할 수 없다.
|
||||||
|
|
||||||
|
## Handoff 원칙
|
||||||
|
|
||||||
|
- 다음 단계 handoff는 source evidence, missing evidence, expected output, acceptance gate, stop condition을 포함해야 한다.
|
||||||
|
- specialist agent가 소유한 기술 판정을 Coordinator가 대체하지 않는다.
|
||||||
|
- `ready-for-implementation`은 Implementation Planning report가 `ready-for-implementation`일 때만 가능하다.
|
||||||
|
- `needs-reference-verification`은 Build/Test evidence가 `pass-for-reference-verification`일 때만 가능하다.
|
||||||
|
- `needs-physics-evaluation`은 Reference Verification report가 `pass-for-physics-evaluation`일 때만 가능하다.
|
||||||
|
- `needs-release`는 Physics Evaluation report가 `pass-for-release-agent`일 때만 가능하다.
|
||||||
|
- `completed`는 Release Agent report가 `ready-for-release`이고 final workflow closure가 기록된 경우에만 가능하다.
|
||||||
|
- 동일 failure classification이 두 번 이상 반복되거나 upstream 계약 변경이 필요하면 `needs-user-decision` 또는 `blocked`로 전환한다.
|
||||||
|
|
||||||
|
## 검증 기준
|
||||||
|
|
||||||
|
- Coordinator Agent config와 문서 템플릿 검증은 Python unittest로 수행한다.
|
||||||
|
- workspace 검증은 `python scripts/validate_workspace.py`를 사용한다.
|
||||||
|
- 현재 repository에 CMake 프로젝트가 없으면 harness 정책에 따라 no-CMake validation 경로가 성공으로 기록될 수 있다.
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
# Correction Report 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Correction Agent가 작성하거나 제안하는 기능별 correction report를 보관하는 위치다.
|
||||||
|
|
||||||
|
Correction Agent는 Build/Test Executor Agent, Reference Verification Agent, Physics Evaluation Agent가 전달한 실패를 triage하고, implementation-owned failure만 최소 수정으로 복구한다. 이 agent는 source, header, test, CMake 수정은 수행할 수 있지만 requirements, formulations, I/O contracts, reference artifacts, tolerance policies는 수정하지 않는다.
|
||||||
|
|
||||||
|
기본 문서명은 `docs/corrections/<feature-id>-correction.md` 형식을 사용한다.
|
||||||
|
|
||||||
|
## Correction Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- 실패 로그와 implementation report를 읽고 failure classification을 먼저 확정한다.
|
||||||
|
- configure, compile, link, test, reference-comparison, harness, environment, upstream-contract 실패를 구분한다.
|
||||||
|
- implementation-owned failure에 한해 source/header/test/CMake를 최소 수정한다.
|
||||||
|
- 수정 후 targeted command를 먼저 실행하고 `python scripts/validate_workspace.py`를 실행한다.
|
||||||
|
- harness, hook, agent config 관련 수정에서는 `python -m unittest discover -s scripts -p "test_*.py"`도 실행한다.
|
||||||
|
- 반복 실패 또는 upstream 계약 문제를 Coordinator Agent나 관련 upstream agent로 handoff한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- requirements를 수정하지 않는다.
|
||||||
|
- formulations를 수정하지 않는다.
|
||||||
|
- I/O contracts를 수정하지 않는다.
|
||||||
|
- numerical review reports를 수정하지 않는다.
|
||||||
|
- reference artifacts를 수정하지 않는다.
|
||||||
|
- tolerance policies를 수정하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- release readiness, reference tolerance success, physics validation success를 승인하지 않는다.
|
||||||
|
- 최종 reference verification report 또는 physics validation report를 작성하지 않는다.
|
||||||
|
|
||||||
|
## 실행 순서
|
||||||
|
|
||||||
|
Correction Agent는 항상 다음 순서를 따른다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
TRIAGE -> MINIMAL FIX -> VERIFY -> REPORT
|
||||||
|
```
|
||||||
|
|
||||||
|
기본 검증 명령은 다음과 같다.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
<targeted command that reproduced the failure>
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
```
|
||||||
|
|
||||||
|
`python -m unittest discover -s scripts -p "test_*.py"`는 harness, hook, agent config, Python validation behavior가 correction 범위에 포함될 때 실행한다.
|
||||||
|
|
||||||
|
## Failure Classification
|
||||||
|
|
||||||
|
- `configure`: CMake configure, preset, generator, cache setup 실패
|
||||||
|
- `compile`: C++ compilation 실패
|
||||||
|
- `link`: linker, symbol resolution, target dependency 실패
|
||||||
|
- `test`: CTest, unit, integration, parser/I/O, ordinary regression test 실패
|
||||||
|
- `reference-comparison`: 저장된 reference artifact와 deterministic comparison 실패
|
||||||
|
- `harness`: Python harness self-test, TDD guard, hook, validation script 실패
|
||||||
|
- `environment`: MSVC, CMake, Python, path, permission, generator, local dependency 문제
|
||||||
|
- `upstream-contract`: requirements, formulation, I/O, reference artifact, tolerance, implementation plan 불일치 또는 누락
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Correction Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_failure_report: docs/build-test-reports/<feature-id>-build-test.md | <reference/physics report path>
|
||||||
|
- source_implementation_report: <path or N/A>
|
||||||
|
- source_implementation_plan: docs/implementation-plans/<feature-id>-implementation-plan.md
|
||||||
|
- status: corrected-for-build-test | corrected-for-reference-verification | needs-build-test-rerun | needs-environment-fix | needs-upstream-decision | blocked
|
||||||
|
- owner_agent: correction-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Failure Triage
|
||||||
|
- classification: configure | compile | link | test | reference-comparison | harness | environment | upstream-contract
|
||||||
|
- first_failed_command: <command>
|
||||||
|
- failed_target_or_test: <target, test, label, or N/A>
|
||||||
|
- evidence_tail: <short relevant tail, not full log>
|
||||||
|
- triage_decision: implementation-owned | environment-owned | upstream-owned | blocked
|
||||||
|
|
||||||
|
## Root Cause Summary
|
||||||
|
- root_cause_type: implementation defect | test defect | CMake registration issue | environment issue | upstream-contract issue
|
||||||
|
- summary: <short explanation>
|
||||||
|
- why_minimal_fix_is_allowed: <contract or failure evidence>
|
||||||
|
|
||||||
|
## Correction Scope
|
||||||
|
|
||||||
|
| file | change_type | reason | in_scope |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| include/fesa/<module>/<file>.hpp | source/header | <reason> | true |
|
||||||
|
| src/<module>/<file>.cpp | source | <reason> | true |
|
||||||
|
| tests/<module>/<file>_test.cpp | test | <reason> | true |
|
||||||
|
| CMakeLists.txt | CMake | <reason> | true |
|
||||||
|
|
||||||
|
Excluded files:
|
||||||
|
- requirements: unchanged
|
||||||
|
- formulations: unchanged
|
||||||
|
- I/O contracts: unchanged
|
||||||
|
- reference artifacts: unchanged
|
||||||
|
- tolerance policies: unchanged
|
||||||
|
|
||||||
|
## Verification Evidence
|
||||||
|
|
||||||
|
| order | command | exit_code | result | evidence |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 1 | <targeted command> | <code> | pass | fail | <summary> |
|
||||||
|
| 2 | python scripts/validate_workspace.py | <code> | pass | fail | <summary> |
|
||||||
|
| 3 | python -m unittest discover -s scripts -p "test_*.py" | <code or skipped> | pass | fail | skipped | <summary> |
|
||||||
|
|
||||||
|
## Traceability
|
||||||
|
|
||||||
|
| requirement_id | task_id | test_id | failing_command | corrected_file | acceptance_criterion |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| <req-id or N/A> | <task-id or N/A> | <test-id or N/A> | <command> | <file> | <criterion> |
|
||||||
|
|
||||||
|
## Handoff Recommendation
|
||||||
|
|
||||||
|
| target_agent | reason | required_input |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Build/Test Executor Agent | <independent full validation required> | <commands and correction summary> |
|
||||||
|
| Reference Verification Agent | <reference comparison rerun required> | <corrected-for-reference-verification evidence> |
|
||||||
|
| Physics Evaluation Agent | <physics sanity rerun required> | <corrected solver behavior evidence> |
|
||||||
|
| Implementation Agent | <new implementation task required> | <unfixed implementation gap> |
|
||||||
|
| upstream agent | <contract issue> | <required upstream decision> |
|
||||||
|
| Coordinator Agent | <repeated failure or blocked state> | <classification history and stop condition> |
|
||||||
|
|
||||||
|
## Stop Condition
|
||||||
|
- repeated_failure: true | false
|
||||||
|
- upstream_ambiguity: true | false
|
||||||
|
- reference_artifact_gap: true | false
|
||||||
|
- environment_blocker: true | false
|
||||||
|
- next_required_decision: <decision or N/A>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 상태 값
|
||||||
|
|
||||||
|
- `corrected-for-build-test`: correction이 Build/Test Executor Agent 재실행 단계로 넘어갈 수 있다.
|
||||||
|
- `corrected-for-reference-verification`: correction이 Reference Verification Agent 재실행 단계로 넘어갈 수 있다.
|
||||||
|
- `needs-build-test-rerun`: targeted correction은 통과했지만 독립 build/test 재실행이 필요하다.
|
||||||
|
- `needs-environment-fix`: 로컬 toolchain, generator, Python, path, permission 문제가 correction 또는 verification을 막는다.
|
||||||
|
- `needs-upstream-decision`: upstream contract, reference artifact, tolerance, formulation ambiguity가 안전한 수정을 막는다.
|
||||||
|
- `blocked`: 사용자 또는 Coordinator Agent 결정 없이는 안전하게 진행할 수 없다.
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 수정 전 failure classification을 기록해야 한다.
|
||||||
|
- 모든 변경은 실패 로그 또는 implementation plan acceptance criterion에 trace되어야 한다.
|
||||||
|
- production C++ 수정에는 관련 테스트 또는 기존 실패 테스트가 있어야 한다.
|
||||||
|
- requirements, formulations, I/O contracts, reference artifacts, tolerance policies는 수정하지 않는다.
|
||||||
|
- 실패 로그는 전체 원문을 복제하지 않고 핵심 tail과 원인 요약만 기록한다.
|
||||||
|
- 동일 classification이 두 번 반복되면 Coordinator Agent 또는 관련 upstream agent로 handoff한다.
|
||||||
|
- 성공 판정은 correction verification까지만 의미한다.
|
||||||
|
- release readiness, reference tolerance success, physics validation success는 판정하지 않는다.
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# 정식화 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Formulation Agent가 작성하거나 제안한 기능별 유한요소 정식화 문서를 보관하는 위치다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/formulations/<feature-id>-formulation.md` 형식을 사용한다. 각 문서는 Requirement Agent의 요구조건과 Research Agent의 연구 브리프를 입력으로 받아 Implementation Planning Agent와 Implementation Agent가 사용할 수 있는 수학/알고리즘 계약을 제공해야 한다.
|
||||||
|
|
||||||
|
## Formulation Agent 역할
|
||||||
|
|
||||||
|
Formulation Agent는 구현 가능한 FEM 정식화 문서를 작성한다.
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- strong form, weak form, discretization을 정리한다.
|
||||||
|
- shape functions, `B` matrix 또는 kinematic operator를 정의한다.
|
||||||
|
- constitutive contract, element residual/internal force, stiffness/tangent matrix를 정리한다.
|
||||||
|
- numerical integration, mapping, Jacobian 규칙을 명시한다.
|
||||||
|
- output recovery, algorithm pseudocode, edge case, numerical risk를 정리한다.
|
||||||
|
- Numerical Review Agent가 검토할 handoff 항목을 남긴다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- C++ 코드를 구현하지 않는다.
|
||||||
|
- C++ API나 파일 구조를 설계하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV 결과를 생성하지 않는다.
|
||||||
|
- release readiness를 승인하지 않는다.
|
||||||
|
- Numerical Review Agent 검토 전 정식화를 최종 승인하지 않는다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Formulation
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- source_research: docs/research/<feature-id>-research.md
|
||||||
|
- status: draft | needs-research | ready-for-numerical-review
|
||||||
|
- owner_agent: formulation-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Scope and Assumptions
|
||||||
|
- analysis_type: linear static | nonlinear static | modal | dynamic | other
|
||||||
|
- element_type: <target element>
|
||||||
|
- deformation: small | large | TBD
|
||||||
|
- linearity: linear | nonlinear | TBD
|
||||||
|
- material_model_boundary: <scope>
|
||||||
|
- coordinate_system: <global/local coordinates>
|
||||||
|
- units: <unit system>
|
||||||
|
|
||||||
|
## Primary Variables and DOFs
|
||||||
|
- nodal_variables: <variables>
|
||||||
|
- dof_ordering: <ordering>
|
||||||
|
- sign_convention: <convention>
|
||||||
|
- constrained_free_dof_assumptions: <assumptions>
|
||||||
|
|
||||||
|
## Strong Form and Boundary Conditions
|
||||||
|
- governing_equation: <equation>
|
||||||
|
- dirichlet_boundary: <essential BC>
|
||||||
|
- neumann_boundary: <natural BC>
|
||||||
|
- natural_boundary_terms: <terms>
|
||||||
|
|
||||||
|
## Weak or Variational Form
|
||||||
|
- test_functions: <definition>
|
||||||
|
- integration_by_parts: <steps>
|
||||||
|
- internal_virtual_work: <expression>
|
||||||
|
- external_virtual_work: <expression>
|
||||||
|
|
||||||
|
## Discretization
|
||||||
|
- interpolation: <field interpolation>
|
||||||
|
- shape_functions: <shape functions>
|
||||||
|
- partition_of_unity_check: <expected check>
|
||||||
|
- kronecker_delta_check: <expected check>
|
||||||
|
- nodal_layout: <layout>
|
||||||
|
|
||||||
|
## Kinematics
|
||||||
|
- strain_displacement_relation: <relation>
|
||||||
|
- B_matrix_or_kinematic_operator: <definition>
|
||||||
|
- deformation_gradient: <definition or N/A>
|
||||||
|
- strain_measure: <definition or N/A>
|
||||||
|
|
||||||
|
## Constitutive Contract
|
||||||
|
- elasticity_matrix_or_stress_update: <contract>
|
||||||
|
- material_state_variables: <variables or N/A>
|
||||||
|
- assumptions_and_constraints: <assumptions>
|
||||||
|
|
||||||
|
## Element Equations
|
||||||
|
- internal_force_or_residual: <expression>
|
||||||
|
- external_force: <expression>
|
||||||
|
- stiffness_or_tangent_matrix: <expression>
|
||||||
|
- mass_or_damping: <required expression or N/A>
|
||||||
|
- vector_matrix_dimensions: <dimensions>
|
||||||
|
|
||||||
|
## Mapping and Numerical Integration
|
||||||
|
- reference_coordinates: <coordinates>
|
||||||
|
- isoparametric_mapping: <mapping>
|
||||||
|
- jacobian: <definition>
|
||||||
|
- determinant_checks: <validity checks>
|
||||||
|
- gauss_points_and_weights: <rule>
|
||||||
|
- integration_policy: full | reduced | selective | analytical | TBD
|
||||||
|
|
||||||
|
## Output Recovery
|
||||||
|
- displacement: <location and convention>
|
||||||
|
- reaction: <calculation>
|
||||||
|
- element_force: <calculation>
|
||||||
|
- strain: <location and recovery>
|
||||||
|
- stress: <location and recovery>
|
||||||
|
- nodal_extrapolation: <policy or N/A>
|
||||||
|
|
||||||
|
## Algorithm Pseudocode
|
||||||
|
```text
|
||||||
|
math-level element routine and assembly flow only
|
||||||
|
no C++ signatures, class names, or file paths
|
||||||
|
```
|
||||||
|
|
||||||
|
## Numerical Risks
|
||||||
|
- rigid_body_modes: <risk/check>
|
||||||
|
- patch_test: <expected test>
|
||||||
|
- symmetry: <expected property>
|
||||||
|
- positive_definiteness: <expected property>
|
||||||
|
- hourglass: <risk or N/A>
|
||||||
|
- shear_locking: <risk or N/A>
|
||||||
|
- volumetric_locking: <risk or N/A>
|
||||||
|
- distortion: <risk/check>
|
||||||
|
- singular_jacobian: <risk/check>
|
||||||
|
|
||||||
|
## Open Issues and Downstream Handoff
|
||||||
|
|
||||||
|
### Numerical Review Agent
|
||||||
|
- <derivations, assumptions, numerical risks, open issues>
|
||||||
|
|
||||||
|
### I/O Definition Agent
|
||||||
|
- <required inputs, outputs, units, coordinate conventions, output locations>
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- <benchmarkable quantities, patch test needs, expected invariants, edge cases>
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- <math-level pseudocode, acceptance-relevant quantities, tests to write first>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 요구조건과 연구 브리프에 없는 값을 임의로 확정하지 않는다.
|
||||||
|
- strong form, weak form, discretization, kinematics, constitutive contract, element equations를 구분한다.
|
||||||
|
- shape functions는 가능한 경우 partition of unity와 Kronecker delta 검사를 포함한다.
|
||||||
|
- numerical integration은 integration point, weight, 적분 대상, full/reduced/selective 정책을 포함한다.
|
||||||
|
- mapping은 reference coordinates, Jacobian, determinant validity check를 포함한다.
|
||||||
|
- output recovery는 nodal, element-level, integration-point 위치를 구분한다.
|
||||||
|
- numerical risk는 rigid body modes, patch test, hourglass, locking, Jacobian 문제를 명시한다.
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# Implementation Plan 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Implementation Planning Agent가 작성하거나 제안한 기능별 구현계획 문서를 보관하는 위치다.
|
||||||
|
|
||||||
|
Implementation Planning Agent는 승인된 요구조건, 연구 브리프, 정식화, 수치 리뷰, I/O 정의, reference model 계약을 C++/MSVC 구현 전 TDD 작업계획으로 변환한다. Agent는 코드, 테스트, CMake 파일을 작성하지 않고, Abaqus/Nastran을 실행하지 않으며, reference CSV 생성이나 solver 결과 비교, release readiness 승인도 하지 않는다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/implementation-plans/<feature-id>-implementation-plan.md` 형식을 사용한다. 각 문서는 Implementation Agent가 먼저 작성해야 할 실패 테스트, 최소 구현 순서, CMake/CTest 등록 계획, acceptance traceability를 제공해야 한다.
|
||||||
|
|
||||||
|
## Implementation Planning Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- upstream 문서가 구현 계획에 충분한지 Readiness Check를 수행한다.
|
||||||
|
- 요구조건과 정식화를 작은 Work Breakdown task로 나눈다.
|
||||||
|
- unit, integration, parser/I/O, reference-comparison 테스트를 TDD 순서로 정렬한다.
|
||||||
|
- CMake/CTest target, `add_test`, label, `ctest -C Debug` 검증 계획을 정의한다.
|
||||||
|
- candidate source/header/test/CMake 파일과 ownership boundary를 제안한다.
|
||||||
|
- requirement, task, test, reference model, acceptance criterion을 Acceptance Traceability Matrix로 연결한다.
|
||||||
|
- `python scripts/validate_workspace.py`를 포함한 validation command를 명시한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- C++ 코드를 구현하지 않는다.
|
||||||
|
- 테스트 파일을 작성하지 않는다.
|
||||||
|
- CMake 파일을 수정하지 않는다.
|
||||||
|
- CMake/CTest를 실행하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- solver 결과를 비교하지 않는다.
|
||||||
|
- release readiness를 승인하지 않는다.
|
||||||
|
- C++ API, class name, storage layout, file ownership을 확정하지 않는다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Implementation Plan
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- source_research: docs/research/<feature-id>-research.md
|
||||||
|
- source_formulation: docs/formulations/<feature-id>-formulation.md
|
||||||
|
- source_numerical_review: docs/numerical-reviews/<feature-id>-review.md
|
||||||
|
- source_io_definition: docs/io-definitions/<feature-id>-io.md
|
||||||
|
- source_reference_models: docs/reference-models/<feature-id>-reference-models.md
|
||||||
|
- status: draft | needs-upstream-decision | ready-for-implementation | blocked
|
||||||
|
- owner_agent: implementation-planning-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Readiness Check
|
||||||
|
|
||||||
|
| input | required_status | observed_status | decision |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| requirement | approved or sufficient draft | <status> | proceed | needs-upstream-decision | blocked |
|
||||||
|
| formulation | pass-for-implementation-planning or sufficient draft | <status> | proceed | needs-upstream-decision | blocked |
|
||||||
|
| numerical_review | pass-for-implementation-planning | <status> | proceed | needs-upstream-decision | blocked |
|
||||||
|
| io_definition | ready-for-implementation-planning or sufficient draft | <status> | proceed | needs-upstream-decision | blocked |
|
||||||
|
| reference_models | ready-for-implementation-planning or planned artifacts | <status> | proceed | needs-upstream-decision | blocked |
|
||||||
|
|
||||||
|
## Implementation Scope
|
||||||
|
- included_behavior: <behavior to implement>
|
||||||
|
- excluded_behavior: <behavior explicitly out of scope>
|
||||||
|
- non_goals: <items not to design or implement in this phase>
|
||||||
|
|
||||||
|
## Work Breakdown
|
||||||
|
|
||||||
|
| task_id | order | purpose | upstream_trace | depends_on | expected_test_first |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| TASK-001 | 1 | <small implementation task> | <requirement/formulation/io/reference id> | none | TEST-001 |
|
||||||
|
|
||||||
|
## TDD Test Plan
|
||||||
|
|
||||||
|
| test_id | order | test_type | red_condition | green_condition | linked_task | command |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| TEST-001 | 1 | unit | test fails because behavior is missing | test passes after minimal implementation | TASK-001 | ctest -C Debug -R <test-name> |
|
||||||
|
| TEST-002 | 2 | integration | integrated path fails before implementation | integrated path passes | TASK-002 | ctest -C Debug -R <test-name> |
|
||||||
|
| TEST-003 | 3 | parser/I/O | Abaqus .inp case is not accepted or mapped | input maps to expected semantic model | TASK-003 | ctest -C Debug -R <test-name> |
|
||||||
|
| TEST-004 | 4 | reference-comparison | solver CSV comparison fails before implementation | comparison is within planned tolerance | TASK-004 | ctest -C Debug -R <test-name> |
|
||||||
|
|
||||||
|
## CMake/CTest Plan
|
||||||
|
- target_candidates: <library/test executable targets>
|
||||||
|
- add_test_needs: <CTest registration needs>
|
||||||
|
- labels: unit | integration | reference | parser | io
|
||||||
|
- msvc_config: Debug
|
||||||
|
- expected_feature_command: ctest -C Debug -R <feature-or-label>
|
||||||
|
- workspace_validation: python scripts/validate_workspace.py
|
||||||
|
|
||||||
|
## Candidate Files and Ownership
|
||||||
|
|
||||||
|
| file_candidate | purpose | owner_boundary | notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| include/fesa/<module>/<candidate>.hpp | <candidate public header role> | candidate only, not final API | <notes> |
|
||||||
|
| src/<module>/<candidate>.cpp | <candidate implementation role> | candidate only, not final API | <notes> |
|
||||||
|
| tests/<module>/<candidate>_test.cpp | <test role> | required before production change | <notes> |
|
||||||
|
| CMakeLists.txt | <target/test registration role> | candidate only | <notes> |
|
||||||
|
|
||||||
|
## Data Flow Contract
|
||||||
|
1. Abaqus `.inp` input follows docs/io-definitions/<feature-id>-io.md.
|
||||||
|
2. Parser/I/O path maps model data and history data into the internal semantic model.
|
||||||
|
3. Solver path produces displacement, reaction, element force, stress, or feature-specific result CSV.
|
||||||
|
4. Reference comparison tests compare solver CSV against `references/<feature-id>/<model-id>/` artifacts.
|
||||||
|
|
||||||
|
## Acceptance Traceability Matrix
|
||||||
|
|
||||||
|
| requirement_id | task_id | test_id | reference_model_id | acceptance_criterion | status |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| <req-id> | TASK-001 | TEST-001 | <model-id or N/A> | <criterion> | draft |
|
||||||
|
|
||||||
|
## Validation Commands
|
||||||
|
```powershell
|
||||||
|
python -m unittest discover -s scripts -p "test_*.py"
|
||||||
|
python scripts/validate_workspace.py
|
||||||
|
ctest -C Debug -R <feature-or-label>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Risks and Downstream Handoff
|
||||||
|
|
||||||
|
### Implementation Agent
|
||||||
|
- <task order, tests to write first, candidate files, acceptance criteria>
|
||||||
|
|
||||||
|
### Build/Test Executor Agent
|
||||||
|
- <validation commands, expected CTest labels, feature-specific commands>
|
||||||
|
|
||||||
|
### Correction Agent
|
||||||
|
- <likely failure classifications and upstream rollback guidance>
|
||||||
|
|
||||||
|
### Reference Verification Agent
|
||||||
|
- <planned CSV comparison tests, reference model ids, tolerance mapping, ID matching assumptions>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <requirement, formulation, I/O, reference artifact, tolerance, or architecture issue>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 모든 `must` requirement는 최소 하나의 task와 test에 연결되어야 한다.
|
||||||
|
- C++ production 변경마다 선행 테스트 파일 또는 테스트 추가 계획이 있어야 한다.
|
||||||
|
- reference artifact가 필요한 기능은 `references/<feature-id>/<model-id>/`와 CSV 비교 테스트 계획을 가져야 한다.
|
||||||
|
- CMake/CTest 계획은 MSVC x64 Debug 검증 경로와 호환되어야 한다.
|
||||||
|
- 구현 계획은 테스트 작성, 실패 확인, 최소 구현, validation 순서를 명시해야 한다.
|
||||||
|
- upstream 문서가 불완전하면 값을 임의로 채우지 않고 `needs-upstream-decision` 또는 `blocked`로 표시한다.
|
||||||
|
- release 완료나 reference tolerance 통과 판정은 하지 않는다.
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
# I/O 정의 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 I/O Definition Agent가 작성하거나 제안한 기능별 입출력 정의 문서를 보관하는 위치다.
|
||||||
|
|
||||||
|
FESA 솔버의 입력 파일은 Abaqus input file이다. 다만 초기 FESA는 Abaqus 전체 문법 호환을 목표로 하지 않고, 기능별로 지원할 Abaqus keyword subset과 내부 모델 매핑을 명확히 정의한다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/io-definitions/<feature-id>-io.md` 형식을 사용한다. 각 문서는 Requirement Agent, Formulation Agent, Numerical Review Agent의 산출물을 입력으로 받아 Abaqus `.inp` 입력 계약과 결과 CSV schema를 정의해야 한다.
|
||||||
|
|
||||||
|
## I/O Definition Agent 역할
|
||||||
|
|
||||||
|
I/O Definition Agent는 Abaqus input file subset, 내부 solver model mapping, output request mapping, comparison CSV schema를 정의한다.
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- 기능별 supported Abaqus keyword subset을 정의한다.
|
||||||
|
- unsupported, ignored-with-warning, requires-user-decision keyword 정책을 정의한다.
|
||||||
|
- model data와 history data를 내부 solver 개념으로 매핑한다.
|
||||||
|
- node, element, set, material, section, boundary condition, load, step, output request의 의미 계약을 정의한다.
|
||||||
|
- `displacements.csv`, `reactions.csv`, `element_forces.csv`, `stresses.csv` schema를 정의한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- parser를 구현하지 않는다.
|
||||||
|
- C++ API나 파일 구조를 설계하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV 결과를 생성하지 않는다.
|
||||||
|
- solver 결과와 reference 결과를 비교하지 않는다.
|
||||||
|
- release readiness를 승인하지 않는다.
|
||||||
|
- 명시적으로 정의되지 않은 Abaqus full compatibility를 주장하지 않는다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> I/O Definition
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- source_formulation: docs/formulations/<feature-id>-formulation.md
|
||||||
|
- source_numerical_review: docs/numerical-reviews/<feature-id>-review.md
|
||||||
|
- source_research: docs/research/<feature-id>-research.md
|
||||||
|
- status: draft | needs-user-decision | ready-for-implementation-planning
|
||||||
|
- owner_agent: io-definition-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Abaqus Input Scope
|
||||||
|
- input_format: Abaqus input file (`.inp`)
|
||||||
|
- abaqus_documentation_source: <version/source URL>
|
||||||
|
- compatibility_disclaimer: FESA supports only the keyword subset defined in this document.
|
||||||
|
|
||||||
|
| keyword | support_status | level | required_parameters | mapped_internal_concept | notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| *HEADING | supported | model | N/A | model title | optional |
|
||||||
|
| *INCLUDE | supported | model/history | INPUT | include file | path policy required |
|
||||||
|
| *NODE | supported | model | N/A | node label and coordinates | |
|
||||||
|
| *NSET | supported | model | NSET | node set | sorted/unsorted policy required |
|
||||||
|
| *ELEMENT | supported | model | TYPE | element label, type, connectivity | |
|
||||||
|
| *ELSET | supported | model | ELSET | element set | |
|
||||||
|
| *MATERIAL | supported | model | NAME | material | |
|
||||||
|
| *ELASTIC | supported | model | N/A or TYPE | elastic material data | |
|
||||||
|
| <section keyword> | supported | model | ELSET, MATERIAL | section assignment | e.g. *SOLID SECTION |
|
||||||
|
| *BOUNDARY | supported | model/history | N/A | boundary condition | |
|
||||||
|
| *CLOAD | supported | history | N/A | concentrated load | feature-dependent |
|
||||||
|
| *DLOAD | supported | history | N/A | distributed load | feature-dependent |
|
||||||
|
| *STEP | supported | history | N/A | analysis step | |
|
||||||
|
| <procedure keyword> | supported | history | N/A | analysis procedure | e.g. *STATIC |
|
||||||
|
| *OUTPUT | supported | history | N/A | output request root | |
|
||||||
|
| *NODE OUTPUT | supported | history | N/A | nodal output request | |
|
||||||
|
| *ELEMENT OUTPUT | supported | history | N/A | element output request | |
|
||||||
|
|
||||||
|
## Syntax Policy
|
||||||
|
- case_insensitivity: <policy>
|
||||||
|
- comma_separated_fields: <policy>
|
||||||
|
- comment_lines: lines beginning with `**`
|
||||||
|
- keyword_continuation: <policy>
|
||||||
|
- include_files: <relative path policy>
|
||||||
|
- labels: <case/quote/name policy>
|
||||||
|
- line_length_limit: <policy>
|
||||||
|
- ascii_assumption: <policy>
|
||||||
|
- empty_data_fields: <policy>
|
||||||
|
|
||||||
|
## Model Data Mapping
|
||||||
|
- nodes: <node label, coordinate dimension, coordinate system>
|
||||||
|
- elements: <element label, element type, connectivity>
|
||||||
|
- node_sets: <set name, sorted/unsorted, expansion rules>
|
||||||
|
- element_sets: <set name, expansion rules>
|
||||||
|
- material: <material name and data>
|
||||||
|
- section: <section assignment>
|
||||||
|
- coordinates: <global/local coordinate conventions>
|
||||||
|
- units: <unit system policy>
|
||||||
|
|
||||||
|
## History Data Mapping
|
||||||
|
- steps: <step naming and order>
|
||||||
|
- procedure: <analysis procedure keyword mapping>
|
||||||
|
- boundary_conditions: <boundary condition mapping>
|
||||||
|
- loads: <load keyword mapping>
|
||||||
|
- output_requests: <node/element output mapping>
|
||||||
|
|
||||||
|
## Internal Model Contract
|
||||||
|
- node_label: <semantic contract>
|
||||||
|
- element_label: <semantic contract>
|
||||||
|
- element_type: <semantic contract>
|
||||||
|
- connectivity: <semantic contract>
|
||||||
|
- set_membership: <semantic contract>
|
||||||
|
- material: <semantic contract>
|
||||||
|
- section: <semantic contract>
|
||||||
|
- boundary_condition: <semantic contract>
|
||||||
|
- load: <semantic contract>
|
||||||
|
- step: <semantic contract>
|
||||||
|
- output_request: <semantic contract>
|
||||||
|
|
||||||
|
## Output and CSV Schemas
|
||||||
|
|
||||||
|
### displacements.csv
|
||||||
|
| column | type | description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| step | string | step name or index |
|
||||||
|
| frame | integer | frame or increment id |
|
||||||
|
| node_id | integer/string | Abaqus node label |
|
||||||
|
| ux | float | displacement component |
|
||||||
|
| uy | float | displacement component or 0/N/A |
|
||||||
|
| uz | float | displacement component or 0/N/A |
|
||||||
|
|
||||||
|
### reactions.csv
|
||||||
|
| column | type | description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| step | string | step name or index |
|
||||||
|
| frame | integer | frame or increment id |
|
||||||
|
| node_id | integer/string | Abaqus node label |
|
||||||
|
| rfx | float | reaction component |
|
||||||
|
| rfy | float | reaction component or 0/N/A |
|
||||||
|
| rfz | float | reaction component or 0/N/A |
|
||||||
|
|
||||||
|
### element_forces.csv
|
||||||
|
| column | type | description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| step | string | step name or index |
|
||||||
|
| frame | integer | frame or increment id |
|
||||||
|
| element_id | integer/string | Abaqus element label |
|
||||||
|
| location | string | element/nodal/integration_point location |
|
||||||
|
| component | string | force component name |
|
||||||
|
| value | float | component value |
|
||||||
|
|
||||||
|
### stresses.csv
|
||||||
|
| column | type | description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| step | string | step name or index |
|
||||||
|
| frame | integer | frame or increment id |
|
||||||
|
| element_id | integer/string | Abaqus element label |
|
||||||
|
| integration_point | integer/string | integration point id or N/A |
|
||||||
|
| component | string | stress component name |
|
||||||
|
| value | float | stress value |
|
||||||
|
|
||||||
|
## Validation Rules
|
||||||
|
- required_fields: <required input fields>
|
||||||
|
- duplicate_labels: <policy>
|
||||||
|
- missing_references: <policy>
|
||||||
|
- unsupported_keywords: unsupported | ignored-with-warning | requires-user-decision
|
||||||
|
- set_expansion: <policy>
|
||||||
|
- coordinate_conventions: <policy>
|
||||||
|
- output_quantity_availability: <policy>
|
||||||
|
|
||||||
|
## Open Issues and Downstream Handoff
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- <Abaqus input examples and reference artifact schema needs>
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- <parser acceptance cases, unsupported keyword diagnostics, CSV writer tests>
|
||||||
|
|
||||||
|
### Reference Verification Agent
|
||||||
|
- <CSV schemas, ID matching rules, units, coordinate conventions, tolerance-relevant fields>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 입력 파일은 Abaqus `.inp`임을 명시해야 한다.
|
||||||
|
- Abaqus full compatibility를 주장하지 않고 기능별 supported keyword subset을 명시해야 한다.
|
||||||
|
- model data와 history data의 매핑을 구분해야 한다.
|
||||||
|
- unsupported keyword 처리 정책을 명확히 해야 한다.
|
||||||
|
- 내부 모델 계약은 semantic fields로 작성하고 C++ class/function/API를 확정하지 않는다.
|
||||||
|
- CSV schema는 column name, ID field, component naming, coordinate system, units, step/frame identity, quantity location을 포함해야 한다.
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
# 수치 검토 리포트 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Numerical Review Agent가 작성하거나 제안한 기능별 수치 검토 리포트를 보관하는 위치다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/numerical-reviews/<feature-id>-review.md` 형식을 사용한다. 각 리포트는 Formulation Agent의 정식화 문서를 독립 검토해, 구현 계획 단계로 넘겨도 되는지 판단한다.
|
||||||
|
|
||||||
|
## Numerical Review Agent 역할
|
||||||
|
|
||||||
|
Numerical Review Agent는 정식화의 수학적 일관성, 수치 안정성 위험, 검증 준비 상태를 검토한다.
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- 수식의 차원, 부호, 좌표 변환, 적분 규칙을 검토한다.
|
||||||
|
- `B` matrix 또는 kinematic operator, constitutive contract, element equation을 검토한다.
|
||||||
|
- rigid body modes, patch test, symmetry, positive definiteness를 확인한다.
|
||||||
|
- hourglass, shear locking, volumetric locking, distortion, singular Jacobian, conditioning 위험을 식별한다.
|
||||||
|
- 구현 계획 전에 필요한 정식화 수정, 연구 보강, reference model 요구사항을 작성한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- C++ 코드를 구현하지 않는다.
|
||||||
|
- 정식화 문서를 직접 수정하지 않는다.
|
||||||
|
- C++ API나 파일 구조를 설계하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV 결과를 생성하지 않는다.
|
||||||
|
- release readiness를 승인하지 않는다.
|
||||||
|
- 레퍼런스 결과와 구현 솔버 결과의 일치 여부를 판정하지 않는다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Numerical Review
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_formulation: docs/formulations/<feature-id>-formulation.md
|
||||||
|
- status: pass-for-implementation-planning | needs-formulation-revision | needs-research | needs-reference-model | blocked
|
||||||
|
- owner_agent: numerical-review-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Review Verdict
|
||||||
|
- verdict: pass-for-implementation-planning | needs-formulation-revision | needs-research | needs-reference-model | blocked
|
||||||
|
- reason: <판정 이유>
|
||||||
|
|
||||||
|
## Critical Findings
|
||||||
|
- <구현 전 반드시 수정할 수식 또는 수치 결함>
|
||||||
|
|
||||||
|
## Numerical Risk Assessment
|
||||||
|
- rigid_body_modes: <check/risk>
|
||||||
|
- patch_test: <check/risk>
|
||||||
|
- symmetry: <check/risk>
|
||||||
|
- positive_definiteness: <check/risk>
|
||||||
|
- hourglass: <check/risk or N/A>
|
||||||
|
- shear_locking: <check/risk or N/A>
|
||||||
|
- volumetric_locking: <check/risk or N/A>
|
||||||
|
- distortion: <check/risk>
|
||||||
|
- singular_jacobian: <check/risk>
|
||||||
|
- conditioning: <check/risk>
|
||||||
|
- convergence: <check/risk or N/A>
|
||||||
|
|
||||||
|
## Consistency Checks
|
||||||
|
- units: <pass/fail/TBD>
|
||||||
|
- dimensions: <pass/fail/TBD>
|
||||||
|
- signs: <pass/fail/TBD>
|
||||||
|
- dof_ordering: <pass/fail/TBD>
|
||||||
|
- coordinate_transforms: <pass/fail/TBD>
|
||||||
|
- matrix_vector_dimensions: <pass/fail/TBD>
|
||||||
|
- integration_weights: <pass/fail/TBD>
|
||||||
|
- output_locations: <pass/fail/TBD>
|
||||||
|
|
||||||
|
## Verification Readiness
|
||||||
|
- unit_tests: <필요한 단위 테스트>
|
||||||
|
- patch_tests: <필요한 patch test>
|
||||||
|
- mms_or_mes: <MMS/MES 후보 또는 N/A>
|
||||||
|
- benchmark_reference_comparison: <필요한 benchmark/reference 비교>
|
||||||
|
- missing_evidence: <누락된 검증 근거>
|
||||||
|
|
||||||
|
## Required Revisions
|
||||||
|
|
||||||
|
### Formulation Agent
|
||||||
|
- <정식화 수정 지시>
|
||||||
|
|
||||||
|
### Research Agent
|
||||||
|
- <연구 보강 지시>
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- <reference model 또는 artifact 요구사항>
|
||||||
|
|
||||||
|
## Downstream Handoff
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- <테스트와 acceptance criteria로 변환할 항목>
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- <테스트 모델로 변환할 항목>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 확인된 결함, 위험, open question을 구분해야 한다.
|
||||||
|
- `pass-for-implementation-planning`은 구현 계획으로 넘겨도 된다는 뜻이며 기능 완료나 release 승인이 아니다.
|
||||||
|
- 정식화 문서를 직접 수정하지 않고 필요한 수정을 명확히 지시해야 한다.
|
||||||
|
- 모든 검토는 dimension, sign, DOF ordering, coordinate transform, Jacobian, integration weight, element equation, output recovery를 포함해야 한다.
|
||||||
|
- numerical risk는 rigid body modes, patch test, symmetry, positive definiteness, hourglass, locking, singular Jacobian, conditioning을 포함해야 한다.
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
# Physics Evaluation Report 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Physics Evaluation Agent가 작성하거나 제안하는 기능별 physics evaluation report를 보관하는 위치다.
|
||||||
|
|
||||||
|
Physics Evaluation Agent는 Reference Verification Agent가 `pass-for-physics-evaluation`으로 넘긴 결과에 대해 물리적 타당성을 검토한다. 이 agent는 reference tolerance를 다시 판정하지 않고, 평형, 반력 부호/합력, 변위 방향, 대칭성, 요소내력/응력 위치, rigid body mode 징후, energy/residual sanity, 테스트 모델 coverage를 검토한다.
|
||||||
|
|
||||||
|
기본 문서명은 `docs/physics-evaluations/<feature-id>-physics-evaluation.md` 형식을 사용한다.
|
||||||
|
|
||||||
|
## Physics Evaluation Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- Reference Verification report가 `pass-for-physics-evaluation`인지 확인한다.
|
||||||
|
- documented physical expectation이 있는 항목만 pass/fail로 판정한다.
|
||||||
|
- global equilibrium, reaction consistency, displacement direction, symmetry, element force balance, stress/strain sanity, rigid body mode, energy/residual, model coverage를 검토한다.
|
||||||
|
- 물리 검토 실패를 equilibrium-failure, reaction-inconsistency, displacement-direction-failure, symmetry-failure, stress-location-failure, element-force-inconsistency, rigid-body-mode-suspected, nonfinite-result, model-coverage-gap, upstream-contract, environment로 분류한다.
|
||||||
|
- 실패 원인에 따라 Correction Agent, Reference Model Agent, Formulation Agent, I/O Definition Agent, Coordinator Agent로 handoff한다.
|
||||||
|
- 모든 물리 검토가 문서화된 기대값을 만족하면 Release Agent로 handoff한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- source code를 수정하지 않는다.
|
||||||
|
- tests를 수정하지 않는다.
|
||||||
|
- CMake files를 수정하지 않는다.
|
||||||
|
- requirements, formulations, I/O contracts, reference model contracts를 수정하지 않는다.
|
||||||
|
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- reference tolerance를 다시 판정하지 않는다.
|
||||||
|
- release readiness를 승인하지 않는다.
|
||||||
|
- release notes 또는 final release checklist를 작성하지 않는다.
|
||||||
|
|
||||||
|
## 실행 순서
|
||||||
|
|
||||||
|
Physics Evaluation Agent는 다음 순서를 따른다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
EVIDENCE CHECK -> PHYSICS CHECKS -> CLASSIFY -> REPORT
|
||||||
|
```
|
||||||
|
|
||||||
|
`EVIDENCE CHECK`에서 다음 항목을 확인한다.
|
||||||
|
|
||||||
|
- Reference Verification report status가 `pass-for-physics-evaluation`인지 여부
|
||||||
|
- checked solver/reference CSVs
|
||||||
|
- compared quantities
|
||||||
|
- model purpose
|
||||||
|
- documented physical expectations
|
||||||
|
- sign convention
|
||||||
|
- units and coordinate system
|
||||||
|
- output location and component naming
|
||||||
|
|
||||||
|
## Physics Checks
|
||||||
|
|
||||||
|
- `global equilibrium`: 적용 하중, 반력, sign convention이 문서화된 경우 전체 힘/모멘트 평형을 검토한다.
|
||||||
|
- `reaction consistency`: constrained DOF와 reaction component가 경계조건과 일관적인지 검토한다.
|
||||||
|
- `displacement direction`: 하중 방향, 구속조건, 예상 변형 모드와 변위 부호/방향이 맞는지 검토한다.
|
||||||
|
- `symmetry`: symmetry, antisymmetry, expected zero component가 모델 목적과 일치하는지 검토한다.
|
||||||
|
- `element force balance`: element internal force와 외력/반력의 균형 또는 부호 일관성을 검토한다.
|
||||||
|
- `stress/strain`: stress/strain 부호, component, coordinate system, output location이 모델 expectation과 일치하는지 검토한다.
|
||||||
|
- `rigid body mode`: 불완전 구속, 비정상적으로 큰 변위, near-zero stiffness 징후를 검토한다.
|
||||||
|
- `energy/residual`: energy_or_residual.csv 또는 residual output이 있을 때 energy balance, residual trend, convergence sanity를 검토한다.
|
||||||
|
- `model coverage`: reference model이 claimed feature를 충분히 검증하는지 검토한다.
|
||||||
|
|
||||||
|
## Failure Classification
|
||||||
|
|
||||||
|
- `equilibrium-failure`: 전체 하중-반력 또는 모멘트 평형이 기대와 다르다.
|
||||||
|
- `reaction-inconsistency`: constrained DOF reaction이 boundary condition 또는 load path와 일관되지 않다.
|
||||||
|
- `displacement-direction-failure`: 변위 방향 또는 부호가 하중/구속조건과 물리적으로 맞지 않다.
|
||||||
|
- `symmetry-failure`: expected symmetry, antisymmetry, zero component가 깨졌다.
|
||||||
|
- `stress-location-failure`: stress/strain output location 또는 component 해석이 물리 expectation과 맞지 않다.
|
||||||
|
- `element-force-inconsistency`: element internal force balance 또는 sign이 일관되지 않다.
|
||||||
|
- `rigid-body-mode-suspected`: rigid body mode 또는 under-constrained model 징후가 있다.
|
||||||
|
- `nonfinite-result`: NaN 또는 infinite value가 있다.
|
||||||
|
- `model-coverage-gap`: reference model이 기능을 충분히 검증하지 못한다.
|
||||||
|
- `upstream-contract`: physical expectation, sign convention, unit, coordinate, output location 계약이 누락 또는 충돌한다.
|
||||||
|
- `environment`: 로컬 실행/읽기 환경 문제로 평가가 불가능하다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Physics Evaluation Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_reference_verification_report: docs/reference-verifications/<feature-id>-reference-verification.md
|
||||||
|
- source_reference_model: docs/reference-models/<feature-id>-reference-models.md
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- source_formulation: docs/formulations/<feature-id>-formulation.md
|
||||||
|
- status: pass-for-release-agent | needs-correction | needs-reference-model | needs-formulation-review | needs-io-decision | needs-upstream-decision | blocked
|
||||||
|
- owner_agent: physics-evaluation-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Input Evidence
|
||||||
|
|
||||||
|
| evidence | path_or_source | status | notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| reference_verification | docs/reference-verifications/<feature-id>-reference-verification.md | pass-for-physics-evaluation | <summary> |
|
||||||
|
| solver_results | <solver CSV path> | present | missing | <summary> |
|
||||||
|
| reference_results | references/<feature-id>/<model-id>/ | present | missing | <summary> |
|
||||||
|
| model_purpose | docs/reference-models/<feature-id>-reference-models.md | documented | missing | <summary> |
|
||||||
|
| physical_expectations | <source docs> | documented | missing | <summary> |
|
||||||
|
|
||||||
|
## Physics Checks
|
||||||
|
|
||||||
|
| check | documented_expectation | observed_evidence | verdict | classification |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| global equilibrium | <expected force/moment balance> | <observed> | pass | fail | skipped | equilibrium-failure |
|
||||||
|
| reaction consistency | <expected reaction behavior> | <observed> | pass | fail | skipped | reaction-inconsistency |
|
||||||
|
| displacement direction | <expected direction/sign> | <observed> | pass | fail | skipped | displacement-direction-failure |
|
||||||
|
| symmetry | <expected symmetry/zero components> | <observed> | pass | fail | skipped | symmetry-failure |
|
||||||
|
| element force balance | <expected element force relation> | <observed> | pass | fail | skipped | element-force-inconsistency |
|
||||||
|
| stress/strain sanity | <expected sign/location/component> | <observed> | pass | fail | skipped | stress-location-failure |
|
||||||
|
| rigid body mode | <expected constrained behavior> | <observed> | pass | fail | skipped | rigid-body-mode-suspected |
|
||||||
|
| energy/residual | <expected energy/residual sanity> | <observed> | pass | fail | skipped | upstream-contract |
|
||||||
|
| model coverage | <claimed feature coverage> | <observed> | pass | fail | skipped | model-coverage-gap |
|
||||||
|
|
||||||
|
## Failure Classification
|
||||||
|
- classification: equilibrium-failure | reaction-inconsistency | displacement-direction-failure | symmetry-failure | stress-location-failure | element-force-inconsistency | rigid-body-mode-suspected | nonfinite-result | model-coverage-gap | upstream-contract | environment | N/A
|
||||||
|
- primary_failure: <short summary>
|
||||||
|
- evidence: <short relevant evidence>
|
||||||
|
|
||||||
|
## Evaluation Verdict
|
||||||
|
- verdict: pass-for-release-agent | needs-correction | needs-reference-model | needs-formulation-review | needs-io-decision | needs-upstream-decision | blocked
|
||||||
|
- reason: <short reason>
|
||||||
|
|
||||||
|
## Handoff Recommendation
|
||||||
|
|
||||||
|
| target_agent | reason | required_input |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Correction Agent | <implementation-owned physical failure> | <failed check and evidence> |
|
||||||
|
| Reference Model Agent | <model coverage or missing physical expectation issue> | <coverage gap> |
|
||||||
|
| Formulation Agent | <formulation or sign convention issue> | <failed physics check> |
|
||||||
|
| I/O Definition Agent | <output location/component/unit/coordinate ambiguity> | <contract gap> |
|
||||||
|
| Coordinator Agent | <blocked or repeated ambiguity> | <classification and open issue> |
|
||||||
|
| Release Agent | <all documented physics checks passed> | <evaluation report> |
|
||||||
|
|
||||||
|
## No-Change Assertion
|
||||||
|
- source_files_modified: false
|
||||||
|
- test_files_modified: false
|
||||||
|
- cmake_files_modified: false
|
||||||
|
- reference_artifacts_modified: false
|
||||||
|
- tolerance_policies_modified: false
|
||||||
|
- notes: <observed no-change evidence or exception>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <missing physical expectation, incomplete model coverage, contradictory sign convention, or unavailable energy/residual evidence>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 상태 값
|
||||||
|
|
||||||
|
- `pass-for-release-agent`: documented physics checks가 통과했고 Release Agent가 release readiness를 평가할 수 있다.
|
||||||
|
- `needs-correction`: implementation-owned physical failure가 있어 Correction Agent가 필요하다.
|
||||||
|
- `needs-reference-model`: reference model coverage가 부족하거나 추가 physical expectation이 필요하다.
|
||||||
|
- `needs-formulation-review`: formulation 또는 numerical review 재검토가 필요하다.
|
||||||
|
- `needs-io-decision`: output location, component naming, sign convention, unit, coordinate mapping이 evaluation을 막는다.
|
||||||
|
- `needs-upstream-decision`: physical expectation, sign convention, model purpose, acceptance criterion이 누락 또는 충돌한다.
|
||||||
|
- `blocked`: 사용자 또는 Coordinator Agent 결정 없이는 안전하게 진행할 수 없다.
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- Reference Verification report가 `pass-for-physics-evaluation`이 아니면 physics pass를 판정하지 않는다.
|
||||||
|
- documented expectation이 없는 항목은 pass/fail로 판정하지 않고 `skipped`, `needs-upstream-decision`, 또는 `needs-reference-model`로 둔다.
|
||||||
|
- 평형 검토는 적용 하중, 반력, element/internal force sign convention이 문서화된 경우에만 수행한다.
|
||||||
|
- stress/strain 검토는 output location, component naming, coordinate system, units가 정의된 경우에만 수행한다.
|
||||||
|
- pass는 Release Agent로 넘길 수 있다는 뜻이며 release readiness 승인이 아니다.
|
||||||
|
- reference artifacts와 tolerance policies는 수정하지 않는다.
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
# Reference Model 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Reference Model Agent가 작성하거나 제안한 기능별 reference model 설계 문서를 보관하는 위치다.
|
||||||
|
|
||||||
|
Reference Model Agent는 FESA 기능 검증에 필요한 Abaqus `.inp` 기반 테스트 모델 포트폴리오와 `references/<feature-id>/<model-id>/` artifact bundle 계약을 정의한다. Agent는 Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않고, reference CSV 값을 생성하지 않으며, solver 결과 비교나 release readiness 승인도 하지 않는다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/reference-models/<feature-id>-reference-models.md` 형식을 사용한다. 각 문서는 요구조건, 연구 브리프, 정식화, 수치 리뷰, I/O 정의를 입력으로 받아 구현 전에 준비해야 할 테스트 모델과 reference artifact 요구사항을 정의해야 한다.
|
||||||
|
|
||||||
|
## Reference Model Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- 기능별 reference model portfolio를 smoke, analytical, patch test, benchmark, regression, negative/invalid-input model로 구분한다.
|
||||||
|
- `model.inp`가 I/O Definition Agent의 supported Abaqus keyword subset 안에 있는지 확인한다.
|
||||||
|
- `references/<feature-id>/<model-id>/` artifact bundle 구조와 필수 파일을 정의한다.
|
||||||
|
- `metadata.json` provenance, 단위, 좌표계, Abaqus version/source, output request, tolerance 정책을 정의한다.
|
||||||
|
- `displacements.csv`, `reactions.csv`, `element_forces.csv`, `stresses.csv` 요구사항을 정의한다.
|
||||||
|
- requirement와 model, compared quantity, tolerance, artifact status를 연결하는 Coverage Matrix를 작성한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- C++ 코드를 구현하지 않는다.
|
||||||
|
- parser를 구현하지 않는다.
|
||||||
|
- C++ API나 파일 구조를 설계하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- solver 결과를 비교하지 않는다.
|
||||||
|
- release readiness를 승인하지 않는다.
|
||||||
|
- reference 값, tolerance, Abaqus compatibility를 임의로 만들지 않는다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Reference Models
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- source_research: docs/research/<feature-id>-research.md
|
||||||
|
- source_formulation: docs/formulations/<feature-id>-formulation.md
|
||||||
|
- source_numerical_review: docs/numerical-reviews/<feature-id>-review.md
|
||||||
|
- source_io_definition: docs/io-definitions/<feature-id>-io.md
|
||||||
|
- status: draft | needs-user-decision | needs-reference-artifacts | ready-for-implementation-planning | blocked
|
||||||
|
- owner_agent: reference-model-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Reference Strategy
|
||||||
|
- verification_scope: <feature verification purpose>
|
||||||
|
- code_verification: <unit/math-level checks supported by this portfolio>
|
||||||
|
- solution_verification: <mesh, convergence, patch, or analytical checks>
|
||||||
|
- benchmark_reference_comparison: <Abaqus/NAFEMS/NASA/paper-derived comparison plan>
|
||||||
|
- excluded_validation_scope: <physical experiment validation excluded unless explicitly available>
|
||||||
|
|
||||||
|
## Model Inventory
|
||||||
|
|
||||||
|
| model_id | category | purpose | status | required_artifacts |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| <model-id> | smoke | <basic parser/solve path> | draft | model.inp, metadata.json, required CSVs |
|
||||||
|
| <model-id> | analytical | <closed-form comparison> | draft | model.inp, metadata.json, required CSVs |
|
||||||
|
| <model-id> | patch test | <element consistency check> | draft | model.inp, metadata.json, required CSVs |
|
||||||
|
| <model-id> | benchmark | <trusted benchmark comparison> | draft | model.inp, metadata.json, required CSVs |
|
||||||
|
| <model-id> | regression | <known defect guard> | draft | model.inp, metadata.json, required CSVs |
|
||||||
|
| <model-id> | negative/invalid-input | <unsupported keyword or invalid model diagnostic> | draft | model.inp, metadata.json |
|
||||||
|
|
||||||
|
## Model Record
|
||||||
|
|
||||||
|
### <model-id>
|
||||||
|
- category: smoke | analytical | patch test | benchmark | regression | negative/invalid-input
|
||||||
|
- purpose: <what this model proves>
|
||||||
|
- verified_requirements: [<requirement-id>]
|
||||||
|
- analysis_type: <linear static | nonlinear static | modal | other>
|
||||||
|
- element_type: <Abaqus element type and FESA feature element>
|
||||||
|
- material: <material model and values>
|
||||||
|
- boundary_conditions: <BC summary>
|
||||||
|
- loads: <load summary>
|
||||||
|
- expected_physical_quantities: displacement | reaction | element force | stress | strain | energy | residual
|
||||||
|
- tolerance: <absolute/relative/norm policy or needs-user-decision>
|
||||||
|
- source: <user | analytical | Abaqus Verification Guide | Abaqus Benchmarks Guide | NAFEMS | NASA/FEMCI | paper>
|
||||||
|
- artifact_status: draft | needs-reference-artifacts | ready-for-implementation-planning | blocked
|
||||||
|
|
||||||
|
## Abaqus Input Requirements
|
||||||
|
- input_file: references/<feature-id>/<model-id>/model.inp
|
||||||
|
- supported_keyword_subset: <keywords from docs/io-definitions/<feature-id>-io.md>
|
||||||
|
- model_data: <nodes, elements, sets, material, section, coordinates, units>
|
||||||
|
- history_data: <step, procedure, boundary conditions, loads, output requests>
|
||||||
|
- output_requests: <requests needed to populate reference CSV files>
|
||||||
|
- unsupported_keyword_policy: unsupported | ignored-with-warning | requires-user-decision
|
||||||
|
|
||||||
|
## Artifact Bundle Contract
|
||||||
|
|
||||||
|
```text
|
||||||
|
references/
|
||||||
|
<feature-id>/
|
||||||
|
<model-id>/
|
||||||
|
model.inp
|
||||||
|
metadata.json
|
||||||
|
displacements.csv
|
||||||
|
reactions.csv
|
||||||
|
element_forces.csv
|
||||||
|
stresses.csv
|
||||||
|
README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Required files:
|
||||||
|
- `model.inp`: Abaqus input file for the reference model.
|
||||||
|
- `metadata.json`: provenance and model contract metadata.
|
||||||
|
- `displacements.csv`: nodal displacement reference results.
|
||||||
|
- `reactions.csv`: nodal reaction force reference results.
|
||||||
|
- `element_forces.csv`: element internal force reference results.
|
||||||
|
- `stresses.csv`: stress reference results.
|
||||||
|
- `README.md`: short description, generation notes, and limitations.
|
||||||
|
|
||||||
|
Optional files:
|
||||||
|
- `strains.csv`: strain reference results when required.
|
||||||
|
- `energy_or_residual.csv`: energy, residual, or convergence reference results when required.
|
||||||
|
- `notes.md`: manual review notes.
|
||||||
|
|
||||||
|
## Metadata JSON Contract
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"feature_id": "<feature-id>",
|
||||||
|
"model_id": "<model-id>",
|
||||||
|
"artifact_status": "draft | needs-reference-artifacts | ready-for-implementation-planning | blocked",
|
||||||
|
"abaqus_version": "<version or needs-user-decision>",
|
||||||
|
"generation_owner": "<person/procedure>",
|
||||||
|
"generation_date": "<YYYY-MM-DD>",
|
||||||
|
"source_documents": ["docs/requirements/<feature-id>.md"],
|
||||||
|
"units": "<unit system>",
|
||||||
|
"coordinate_system": "global Cartesian unless otherwise documented",
|
||||||
|
"analysis_type": "<analysis type>",
|
||||||
|
"element_types": ["<Abaqus element type>"],
|
||||||
|
"material_values": {},
|
||||||
|
"boundary_condition_summary": "<summary>",
|
||||||
|
"load_summary": "<summary>",
|
||||||
|
"output_requests": ["U", "RF", "S", "<feature-specific quantities>"],
|
||||||
|
"csv_schema_version": "<version>",
|
||||||
|
"tolerance_policy": "<absolute/relative/norm policy>",
|
||||||
|
"limitations": ["<known limitation>"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference CSV Requirements
|
||||||
|
|
||||||
|
### displacements.csv
|
||||||
|
- Required when nodal displacement is a verification quantity.
|
||||||
|
- Must include step/frame identity, node id, displacement components, coordinate system, and units.
|
||||||
|
|
||||||
|
### reactions.csv
|
||||||
|
- Required when constrained DOF reactions or global equilibrium are verification quantities.
|
||||||
|
- Must include step/frame identity, node id, reaction components, coordinate system, and units.
|
||||||
|
|
||||||
|
### element_forces.csv
|
||||||
|
- Required when element internal force is a verification quantity.
|
||||||
|
- Must include step/frame identity, element id, output location, component, value, and units.
|
||||||
|
|
||||||
|
### stresses.csv
|
||||||
|
- Required when stress is a verification quantity.
|
||||||
|
- Must include step/frame identity, element id, integration point or recovery location, component, value, coordinate system, and units.
|
||||||
|
|
||||||
|
### Optional CSVs
|
||||||
|
- `strains.csv`: required when strain is part of the acceptance criteria.
|
||||||
|
- `energy_or_residual.csv`: required when energy balance, residual, or convergence data is part of the acceptance criteria.
|
||||||
|
|
||||||
|
## Coverage Matrix
|
||||||
|
|
||||||
|
| requirement_id | model_id | compared_quantity | artifact_file | tolerance | verification_method | status |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| <req-id> | <model-id> | displacement | displacements.csv | <policy> | reference-comparison | draft |
|
||||||
|
| <req-id> | <model-id> | reaction | reactions.csv | <policy> | reference-comparison | draft |
|
||||||
|
| <req-id> | <model-id> | element force | element_forces.csv | <policy> | reference-comparison | draft |
|
||||||
|
| <req-id> | <model-id> | stress | stresses.csv | <policy> | reference-comparison | draft |
|
||||||
|
|
||||||
|
## Artifact Acceptance Checklist
|
||||||
|
- 모든 `must` requirement가 최소 하나의 `model_id`와 `compared_quantity`에 연결되어 있다.
|
||||||
|
- `model.inp`가 기능별 supported Abaqus keyword subset을 벗어나지 않는다.
|
||||||
|
- `metadata.json`에 provenance, Abaqus version/source, units, coordinate system, tolerance, CSV schema version이 기록되어 있다.
|
||||||
|
- 필수 CSV 파일이 존재하거나, 기능상 불필요한 파일은 명확한 reason과 함께 제외되어 있다.
|
||||||
|
- output request가 필요한 CSV 물리량을 생성할 수 있도록 정의되어 있다.
|
||||||
|
- reference CSV가 없으면 status는 `needs-reference-artifacts`다.
|
||||||
|
- tolerance, source, units, coordinate system이 불명확하면 status는 `needs-user-decision`이다.
|
||||||
|
|
||||||
|
## Open Issues and Downstream Handoff
|
||||||
|
|
||||||
|
### I/O Definition Agent
|
||||||
|
- <supported keyword, output request, CSV schema clarification>
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- <tests that should fail before implementation, model order, acceptance criteria>
|
||||||
|
|
||||||
|
### Reference Verification Agent
|
||||||
|
- <CSV schema, ID matching, units, coordinate conventions, output locations, tolerance mapping>
|
||||||
|
|
||||||
|
### Physics Evaluation Agent
|
||||||
|
- <equilibrium, symmetry, displacement direction, stress location, rigid body mode, load path sanity checks>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- Reference model의 목적과 검증 대상 requirement가 명확해야 한다.
|
||||||
|
- `model.inp`는 Abaqus input file이며, 기능별 supported keyword subset을 따라야 한다.
|
||||||
|
- model data와 history data를 구분해야 한다.
|
||||||
|
- output request와 required CSV 사이의 연결이 명확해야 한다.
|
||||||
|
- `references/<feature-id>/<model-id>/` 구조와 필수 artifact가 명시되어야 한다.
|
||||||
|
- `metadata.json`에는 provenance, Abaqus version/source, units, coordinate system, tolerance, CSV schema version이 포함되어야 한다.
|
||||||
|
- reference CSV가 없으면 완료 상태가 아니라 `needs-reference-artifacts` 상태로 둔다.
|
||||||
|
- 모든 `must` requirement는 Coverage Matrix에서 model, compared quantity, tolerance, verification method로 추적되어야 한다.
|
||||||
|
|
||||||
|
## Abaqus UserSubroutine artifact metadata v1
|
||||||
|
|
||||||
|
For Fortran Abaqus UserSubroutine work, each stored artifact bundle may include `metadata.json` with:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||||
|
"feature_id": "<feature-id>",
|
||||||
|
"model_id": "<model-id>",
|
||||||
|
"artifact_status": "draft | needs-reference-artifacts | ready-for-comparison | blocked",
|
||||||
|
"abaqus": {
|
||||||
|
"version": "<Abaqus version>",
|
||||||
|
"precision": "single | double",
|
||||||
|
"command": "abaqus job=<job> user=<subroutine>"
|
||||||
|
},
|
||||||
|
"compiler": {
|
||||||
|
"vendor": "Intel oneAPI",
|
||||||
|
"name": "ifx | ifort",
|
||||||
|
"version": "<compiler version>"
|
||||||
|
},
|
||||||
|
"subroutine": {
|
||||||
|
"entry_points": ["UMAT"],
|
||||||
|
"source_files": [
|
||||||
|
{
|
||||||
|
"path": "src/fortran/abaqus/UMAT.for",
|
||||||
|
"language": "Fortran",
|
||||||
|
"sha256": "<source sha256>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"input_file": "model.inp",
|
||||||
|
"outputs": {
|
||||||
|
"tails": {
|
||||||
|
"msg": "job.msg.tail.txt",
|
||||||
|
"dat": "job.dat.tail.txt",
|
||||||
|
"log": "job.log.tail.txt"
|
||||||
|
},
|
||||||
|
"csv": {
|
||||||
|
"stresses": "stresses.csv"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`artifact_status=ready-for-comparison` means `scripts/validate_reference_artifacts.py` must find all declared files and confirm source SHA-256 values. Agents must not generate or edit the declared reference CSVs unless an explicit reference-artifact phase authorizes that work.
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
# Reference Verification Report 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Reference Verification Agent가 작성하거나 제안하는 기능별 reference comparison report를 보관하는 위치다.
|
||||||
|
|
||||||
|
Reference Verification Agent는 Build/Test Executor Agent 통과 후 generated solver result CSV와 stored Abaqus reference CSV artifacts를 tolerance 기준으로 비교한다. 이 agent는 comparison과 report만 수행하며, source code, tests, CMake files, requirements, formulations, I/O contracts, reference artifacts, tolerance policies를 수정하지 않는다.
|
||||||
|
|
||||||
|
기본 문서명은 `docs/reference-verifications/<feature-id>-reference-verification.md` 형식을 사용한다.
|
||||||
|
|
||||||
|
## Reference Verification Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- `references/<feature-id>/<model-id>/` artifact bundle과 generated solver result CSV를 확인한다.
|
||||||
|
- `metadata.json`, schema version, units, coordinate system, step/frame identity, node/element IDs, output location, tolerance source를 확인한다.
|
||||||
|
- `displacements.csv`, `reactions.csv`, `element_forces.csv`, `stresses.csv`를 기본 비교 대상으로 삼는다.
|
||||||
|
- upstream 문서가 요구할 때만 `strains.csv`, `energy_or_residual.csv`를 추가 비교한다.
|
||||||
|
- max absolute error, max relative error, RMS error, norm error, worst node/element/component, missing rows, extra rows, pass/fail을 보고한다.
|
||||||
|
- 실패를 missing-reference-artifact, missing-solver-output, schema-mismatch, id-mismatch, unit-or-coordinate-mismatch, tolerance-failure, nonfinite-result, upstream-contract, environment로 분류한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- source code를 수정하지 않는다.
|
||||||
|
- tests를 수정하지 않는다.
|
||||||
|
- CMake files를 수정하지 않는다.
|
||||||
|
- requirements, formulations, I/O contracts, reference model contracts를 수정하지 않는다.
|
||||||
|
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- solver output CSV를 tolerance에 맞추기 위해 보정하지 않는다.
|
||||||
|
- physics validation success 또는 release readiness를 승인하지 않는다.
|
||||||
|
|
||||||
|
## 실행 순서
|
||||||
|
|
||||||
|
Reference Verification Agent는 항상 다음 순서를 따른다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
ARTIFACT CHECK -> COMPARE -> CLASSIFY -> REPORT
|
||||||
|
```
|
||||||
|
|
||||||
|
`ARTIFACT CHECK`에서 다음 항목이 없으면 비교를 시작하지 않는다.
|
||||||
|
|
||||||
|
- `metadata.json`
|
||||||
|
- required reference CSV files
|
||||||
|
- generated solver result CSV files
|
||||||
|
- schema version
|
||||||
|
- units
|
||||||
|
- coordinate system
|
||||||
|
- step/frame identity
|
||||||
|
- node/element ID matching rule
|
||||||
|
- output location
|
||||||
|
- tolerance policy
|
||||||
|
|
||||||
|
## 비교 대상
|
||||||
|
|
||||||
|
기본 비교 대상:
|
||||||
|
- `displacements.csv`: nodal displacement
|
||||||
|
- `reactions.csv`: nodal reaction force
|
||||||
|
- `element_forces.csv`: element internal force
|
||||||
|
- `stresses.csv`: element stress
|
||||||
|
|
||||||
|
선택 비교 대상:
|
||||||
|
- `strains.csv`: strain이 acceptance criteria에 포함된 경우
|
||||||
|
- `energy_or_residual.csv`: energy, residual, convergence quantity가 acceptance criteria에 포함된 경우
|
||||||
|
|
||||||
|
## Failure Classification
|
||||||
|
|
||||||
|
- `missing-reference-artifact`: required stored reference file 또는 provenance가 없다.
|
||||||
|
- `missing-solver-output`: generated solver result CSV 또는 comparison command가 없다.
|
||||||
|
- `schema-mismatch`: reference CSV와 solver CSV column/schema가 다르다.
|
||||||
|
- `id-mismatch`: node id, element id, step/frame, integration point, component matching이 실패했다.
|
||||||
|
- `unit-or-coordinate-mismatch`: units 또는 coordinate system이 비교 가능하지 않다.
|
||||||
|
- `tolerance-failure`: schema와 matching은 유효하지만 error가 tolerance를 초과했다.
|
||||||
|
- `nonfinite-result`: NaN 또는 infinite value가 발견됐다.
|
||||||
|
- `upstream-contract`: tolerance, schema, units, output location, ID matching policy가 누락 또는 충돌한다.
|
||||||
|
- `environment`: 로컬 실행 환경 문제로 비교가 불가능하다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Reference Verification Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_build_test_report: docs/build-test-reports/<feature-id>-build-test.md
|
||||||
|
- source_reference_models: docs/reference-models/<feature-id>-reference-models.md
|
||||||
|
- source_io_definition: docs/io-definitions/<feature-id>-io.md
|
||||||
|
- source_implementation_report: <path or N/A>
|
||||||
|
- status: pass-for-physics-evaluation | needs-correction | needs-reference-artifacts | needs-solver-results | needs-upstream-decision | blocked
|
||||||
|
- owner_agent: reference-verification-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Artifact Inventory
|
||||||
|
|
||||||
|
| item | path | status | notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| reference_bundle | references/<feature-id>/<model-id>/ | present | missing | <notes> |
|
||||||
|
| metadata | references/<feature-id>/<model-id>/metadata.json | present | missing | <provenance summary> |
|
||||||
|
| reference_displacements | references/<feature-id>/<model-id>/displacements.csv | present | missing | <notes> |
|
||||||
|
| reference_reactions | references/<feature-id>/<model-id>/reactions.csv | present | missing | <notes> |
|
||||||
|
| reference_element_forces | references/<feature-id>/<model-id>/element_forces.csv | present | missing | <notes> |
|
||||||
|
| reference_stresses | references/<feature-id>/<model-id>/stresses.csv | present | missing | <notes> |
|
||||||
|
| solver_outputs | <solver output directory> | present | missing | <notes> |
|
||||||
|
|
||||||
|
## Comparison Contract
|
||||||
|
- schema_version: <version>
|
||||||
|
- id_matching: node_id | element_id | step/frame | integration_point | component
|
||||||
|
- units: <unit system>
|
||||||
|
- coordinate_system: <global/local convention>
|
||||||
|
- output_location: nodal | element | integration_point | centroid | recovery_location
|
||||||
|
- component_naming: <component naming policy>
|
||||||
|
- tolerance_source: <requirement/reference model/I/O document>
|
||||||
|
- tolerance_policy: absolute | relative | norm-based | combined
|
||||||
|
- zero_reference_policy: <policy or N/A>
|
||||||
|
|
||||||
|
## Quantity Results
|
||||||
|
|
||||||
|
| quantity | model_id | artifact_file | compared_rows | missing_rows | extra_rows | max_abs_error | max_rel_error | rms_error | norm_error | worst_id | worst_component | result |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| displacement | <model-id> | displacements.csv | <n> | <n> | <n> | <value> | <value> | <value> | <value or N/A> | <node id> | <component> | pass | fail |
|
||||||
|
| reaction | <model-id> | reactions.csv | <n> | <n> | <n> | <value> | <value> | <value> | <value or N/A> | <node id> | <component> | pass | fail |
|
||||||
|
| element force | <model-id> | element_forces.csv | <n> | <n> | <n> | <value> | <value> | <value> | <value or N/A> | <element id> | <component> | pass | fail |
|
||||||
|
| stress | <model-id> | stresses.csv | <n> | <n> | <n> | <value> | <value> | <value> | <value or N/A> | <element/ip id> | <component> | pass | fail |
|
||||||
|
|
||||||
|
## Failure Classification
|
||||||
|
- classification: missing-reference-artifact | missing-solver-output | schema-mismatch | id-mismatch | unit-or-coordinate-mismatch | tolerance-failure | nonfinite-result | upstream-contract | environment | N/A
|
||||||
|
- primary_failure: <short summary>
|
||||||
|
- evidence: <short relevant excerpt or computed metric>
|
||||||
|
|
||||||
|
## Handoff Recommendation
|
||||||
|
|
||||||
|
| target_agent | reason | required_input |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Correction Agent | <implementation-owned mismatch or nonfinite result> | <comparison metrics and failing quantity> |
|
||||||
|
| Reference Model Agent | <missing or invalid reference artifact/provenance> | <artifact inventory> |
|
||||||
|
| I/O Definition Agent | <schema, units, coordinate, output location mismatch> | <contract mismatch> |
|
||||||
|
| Physics Evaluation Agent | <reference comparisons passed> | <quantity results and report> |
|
||||||
|
| Coordinator Agent | <blocked or repeated ambiguity> | <classification and open issue> |
|
||||||
|
|
||||||
|
## No-Change Assertion
|
||||||
|
- source_files_modified: false
|
||||||
|
- test_files_modified: false
|
||||||
|
- cmake_files_modified: false
|
||||||
|
- reference_artifacts_modified: false
|
||||||
|
- tolerance_policies_modified: false
|
||||||
|
- notes: <observed no-change evidence or exception>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <missing solver outputs, missing reference artifacts, schema gaps, tolerance gaps, or repeated comparison failures>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 상태 값
|
||||||
|
|
||||||
|
- `pass-for-physics-evaluation`: required reference comparisons가 모두 통과했고 Physics Evaluation Agent로 넘길 수 있다.
|
||||||
|
- `needs-correction`: implementation-owned solver result mismatch 또는 nonfinite result가 있다.
|
||||||
|
- `needs-reference-artifacts`: required reference artifact 또는 provenance가 누락됐다.
|
||||||
|
- `needs-solver-results`: generated solver result CSV 또는 comparison command가 없다.
|
||||||
|
- `needs-upstream-decision`: schema, tolerance, units, coordinate system, output location, ID matching policy가 누락 또는 충돌한다.
|
||||||
|
- `blocked`: 사용자 또는 Coordinator Agent 결정 없이는 안전하게 진행할 수 없다.
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 모든 `must` requirement의 reference-comparison 항목은 model id, compared quantity, artifact file, tolerance에 trace되어야 한다.
|
||||||
|
- reference artifact는 읽기 전용이다. `model.inp`, `metadata.json`, reference CSV를 수정하지 않는다.
|
||||||
|
- solver output CSV는 비교 입력일 뿐이며 tolerance에 맞추기 위해 후처리 보정하지 않는다.
|
||||||
|
- stress/strain은 element id, integration point 또는 recovery location, component naming이 일치할 때만 비교한다.
|
||||||
|
- nodal displacement/reaction은 node id, DOF/component, coordinate system, unit이 일치할 때만 비교한다.
|
||||||
|
- missing rows와 extra rows를 숨기지 않고 보고한다.
|
||||||
|
- NaN 또는 infinite value는 `nonfinite-result`로 분류한다.
|
||||||
|
- pass는 reference tolerance 통과만 의미한다.
|
||||||
|
- physics validation과 release readiness는 각각 Physics Evaluation Agent와 Release Agent가 판정한다.
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
# Release Report 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Release Agent가 작성하거나 제안하는 기능별 release readiness report를 보관하는 위치다.
|
||||||
|
|
||||||
|
Release Agent는 Physics Evaluation Agent가 `pass-for-release-agent`로 넘긴 기능에 대해 최종 gate evidence를 감사한다. 이 Agent는 source code, tests, CMake, upstream 계약, reference artifacts, tolerance policies를 수정하지 않는다. 또한 Abaqus/Nastran 실행, reference CSV 생성, 외부 publish/deploy/package/tag/commit 작업을 수행하지 않는다.
|
||||||
|
|
||||||
|
기본 문서명은 `docs/releases/<feature-id>-release.md` 형식을 사용한다.
|
||||||
|
|
||||||
|
## Release Agent 역할
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- upstream gate report가 같은 `feature_id`를 대상으로 하는지 확인한다.
|
||||||
|
- Build/Test report의 `pass-for-reference-verification` 상태를 확인한다.
|
||||||
|
- Reference Verification report의 `pass-for-physics-evaluation` 상태를 확인한다.
|
||||||
|
- Physics Evaluation report의 `pass-for-release-agent` 상태를 확인한다.
|
||||||
|
- 모든 `must` requirement가 acceptance criterion, test/reference evidence, release scope에 trace되는지 확인한다.
|
||||||
|
- known limitations, deferred issues, unsupported Abaqus keyword, accepted risks를 release note에 기록한다.
|
||||||
|
- release checklist와 Release Notes Draft를 작성한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- source code를 수정하지 않는다.
|
||||||
|
- tests를 수정하지 않는다.
|
||||||
|
- CMake files 또는 build configuration을 수정하지 않는다.
|
||||||
|
- requirements, formulations, I/O contracts, numerical review reports, reference verification reports, physics evaluation reports를 수정하지 않는다.
|
||||||
|
- reference artifacts 또는 tolerance policies를 수정하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 reference solver를 실행하지 않는다.
|
||||||
|
- reference CSV를 생성하지 않는다.
|
||||||
|
- 실패하거나 누락된 upstream gate를 우회하지 않는다.
|
||||||
|
- 사용자 명시 요청 없이 publish, deploy, package, tag, commit, external release를 수행하지 않는다.
|
||||||
|
|
||||||
|
## 실행 순서
|
||||||
|
|
||||||
|
Release Agent는 다음 순서를 따른다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
GATE AUDIT -> TRACEABILITY CHECK -> RELEASE DOCUMENTATION -> RELEASE VERDICT
|
||||||
|
```
|
||||||
|
|
||||||
|
`GATE AUDIT`에서는 다음 evidence를 확인한다.
|
||||||
|
|
||||||
|
- Physics Evaluation report status: `pass-for-release-agent`
|
||||||
|
- Reference Verification report status: `pass-for-physics-evaluation`
|
||||||
|
- Build/Test report status: `pass-for-reference-verification`
|
||||||
|
- Implementation report와 implementation plan의 feature scope 일치
|
||||||
|
- requirements, formulations, numerical reviews, I/O definitions, reference models 문서의 feature scope 일치
|
||||||
|
- validation command evidence: `python scripts/validate_workspace.py`
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Release Report
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- source_formulation: docs/formulations/<feature-id>-formulation.md
|
||||||
|
- source_numerical_review: docs/numerical-reviews/<feature-id>-review.md
|
||||||
|
- source_io_definition: docs/io-definitions/<feature-id>-io.md
|
||||||
|
- source_reference_model: docs/reference-models/<feature-id>-reference-models.md
|
||||||
|
- source_implementation_plan: docs/implementation-plans/<feature-id>-implementation-plan.md
|
||||||
|
- source_build_test_report: docs/build-test-reports/<feature-id>-build-test.md
|
||||||
|
- source_reference_verification_report: docs/reference-verifications/<feature-id>-reference-verification.md
|
||||||
|
- source_physics_evaluation_report: docs/physics-evaluations/<feature-id>-physics-evaluation.md
|
||||||
|
- status: ready-for-release | needs-correction | needs-reference-verification | needs-physics-evaluation | needs-documentation | needs-upstream-decision | blocked
|
||||||
|
- owner_agent: release-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Release Scope
|
||||||
|
|
||||||
|
| item | included | excluded | notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| analysis_type | <supported analysis> | <unsupported analysis> | <notes> |
|
||||||
|
| element_type | <supported elements> | <unsupported elements> | <notes> |
|
||||||
|
| material_model | <supported materials> | <unsupported materials> | <notes> |
|
||||||
|
| Abaqus input subset | <supported keywords> | <unsupported keywords> | <notes> |
|
||||||
|
| output_quantities | <supported outputs> | <unsupported outputs> | <notes> |
|
||||||
|
|
||||||
|
## Gate Evidence Inventory
|
||||||
|
|
||||||
|
| gate | source | expected_status | observed_status | verdict |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| requirements | docs/requirements/<feature-id>.md | approved or release-ready | <status> | pass | fail | missing |
|
||||||
|
| formulation | docs/formulations/<feature-id>-formulation.md | reviewed | <status> | pass | fail | missing |
|
||||||
|
| numerical_review | docs/numerical-reviews/<feature-id>-review.md | pass-for-implementation-planning | <status> | pass | fail | missing |
|
||||||
|
| io_definition | docs/io-definitions/<feature-id>-io.md | ready | <status> | pass | fail | missing |
|
||||||
|
| reference_model | docs/reference-models/<feature-id>-reference-models.md | ready or artifacts present | <status> | pass | fail | missing |
|
||||||
|
| implementation | <implementation report> | implemented | <status> | pass | fail | missing |
|
||||||
|
| build_test | docs/build-test-reports/<feature-id>-build-test.md | pass-for-reference-verification | <status> | pass | fail | missing |
|
||||||
|
| reference_verification | docs/reference-verifications/<feature-id>-reference-verification.md | pass-for-physics-evaluation | <status> | pass | fail | missing |
|
||||||
|
| physics_evaluation | docs/physics-evaluations/<feature-id>-physics-evaluation.md | pass-for-release-agent | <status> | pass | fail | missing |
|
||||||
|
|
||||||
|
## Acceptance Traceability
|
||||||
|
|
||||||
|
| requirement_id | acceptance_criterion | test_id | reference_model_id | verification_report | release_disposition |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| <req-id> | <criterion> | <test-id> | <model-id> | <report path> | released | deferred | blocked |
|
||||||
|
|
||||||
|
## Validation Evidence
|
||||||
|
|
||||||
|
| command_or_report | expected | observed | notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| python scripts/validate_workspace.py | pass | <result> | <summary> |
|
||||||
|
| CMake/MSVC/CTest | pass | <result> | <summary> |
|
||||||
|
| reference verification | pass-for-physics-evaluation | <status> | <summary> |
|
||||||
|
| physics evaluation | pass-for-release-agent | <status> | <summary> |
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
| limitation | category | user_impact | disposition |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| <unsupported Abaqus keyword or solver scope limit> | input | physics | numerical | output | <impact> | documented | deferred | blocker |
|
||||||
|
|
||||||
|
## Release Notes Draft
|
||||||
|
|
||||||
|
### Feature Summary
|
||||||
|
- <user-facing summary>
|
||||||
|
|
||||||
|
### Verification Scope
|
||||||
|
- <validated analysis, element, material, I/O, reference model scope>
|
||||||
|
|
||||||
|
### Main Limitations
|
||||||
|
- <known limitation>
|
||||||
|
|
||||||
|
### Artifacts
|
||||||
|
- <release report, reference bundle, verification report paths>
|
||||||
|
|
||||||
|
## Release Verdict
|
||||||
|
- verdict: ready-for-release | needs-correction | needs-reference-verification | needs-physics-evaluation | needs-documentation | needs-upstream-decision | blocked
|
||||||
|
- reason: <short reason>
|
||||||
|
|
||||||
|
## Handoff Recommendation
|
||||||
|
|
||||||
|
| target_agent | reason | required_input |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Coordinator Agent | <release decision or blocked issue> | <summary> |
|
||||||
|
| Correction Agent | <implementation-owned release blocker> | <failure evidence> |
|
||||||
|
| Reference Verification Agent | <missing or failed reference comparison> | <artifact and report gap> |
|
||||||
|
| Physics Evaluation Agent | <missing or failed physics evaluation> | <reference verification evidence> |
|
||||||
|
| Requirement Agent | <requirement or acceptance gap> | <open decision> |
|
||||||
|
| I/O Definition Agent | <I/O scope or Abaqus keyword limitation gap> | <contract gap> |
|
||||||
|
| Reference Model Agent | <reference artifact or coverage gap> | <model gap> |
|
||||||
|
|
||||||
|
## No-Change Assertion
|
||||||
|
- source_files_modified: false
|
||||||
|
- test_files_modified: false
|
||||||
|
- cmake_files_modified: false
|
||||||
|
- reference_artifacts_modified: false
|
||||||
|
- tolerance_policies_modified: false
|
||||||
|
- notes: <observed no-change evidence or exception>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <missing evidence, contradictory upstream report, unresolved defect, incomplete reference artifact, or documentation gap>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 상태 값
|
||||||
|
|
||||||
|
- `ready-for-release`: required gate가 모두 통과했고, 모든 `must` requirement traceability와 known limitations 문서화가 완료되었다.
|
||||||
|
- `needs-correction`: implementation-owned defect 또는 unresolved test/build/reference/physics issue가 있어 Correction Agent가 필요하다.
|
||||||
|
- `needs-reference-verification`: reference verification report가 없거나 `pass-for-physics-evaluation`이 아니다.
|
||||||
|
- `needs-physics-evaluation`: physics evaluation report가 없거나 `pass-for-release-agent`가 아니다.
|
||||||
|
- `needs-documentation`: gate evidence는 통과했지만 release scope, known limitations, release notes, traceability 문서가 불완전하다.
|
||||||
|
- `needs-upstream-decision`: requirement, tolerance, reference artifact, I/O, acceptance evidence가 누락되었거나 상충한다.
|
||||||
|
- `blocked`: 사용자 또는 Coordinator Agent 결정 없이는 안전하게 진행할 수 없다.
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- `ready-for-release`는 Build/Test, Reference Verification, Physics Evaluation gate evidence가 모두 present and passing일 때만 사용할 수 있다.
|
||||||
|
- 모든 `must` requirement는 acceptance criterion, test/reference evidence, release scope에 trace되어야 한다.
|
||||||
|
- known limitations와 deferred/open issue는 Release Notes Draft에 명확히 기록되어야 한다.
|
||||||
|
- missing evidence, contradictory upstream reports, unresolved defects, incomplete reference artifacts는 release pass가 아니라 적절한 `needs-*` 상태로 분류한다.
|
||||||
|
- 이 문서는 FESA 내부 feature release readiness 판정을 위한 것이며, 외부 publish/deploy/package/tag/commit 자동화는 포함하지 않는다.
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
# 요구조건 문서 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Requirement Agent가 작성하거나 제안한 기능별 요구조건 문서를 보관하는 위치다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/requirements/<feature-id>.md` 형식을 사용한다. 각 문서는 구현 전에 작성되며, Formulation Agent, I/O Definition Agent, Reference Model Agent, Implementation Planning Agent가 이어받을 수 있는 검증 가능한 baseline이어야 한다.
|
||||||
|
|
||||||
|
## Requirement Agent 역할
|
||||||
|
|
||||||
|
Requirement Agent는 솔버 기능 요청을 검증 가능한 요구조건으로 바꾼다.
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- 기능 범위, 제외 범위, 입력, 출력, 제약조건을 정의한다.
|
||||||
|
- 해석 타입, 대상 요소, 자유도, 재료 모델, 경계조건, 하중 조건을 명확히 한다.
|
||||||
|
- 절점 변위, 반력, 요소 내력, 응력 등 검증 물리량을 정한다.
|
||||||
|
- tolerance와 reference artifact 요구사항을 기록한다.
|
||||||
|
- Requirement Verification Matrix를 작성한다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- C++ 코드를 구현하지 않는다.
|
||||||
|
- 유한요소 정식화를 확정하지 않는다.
|
||||||
|
- C++ API나 파일 구조를 설계하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV 결과를 생성하지 않는다.
|
||||||
|
- 기능 완료 여부를 승인하지 않는다.
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Requirements
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- title: <title>
|
||||||
|
- status: draft | needs-user-decision | approved
|
||||||
|
- owner_agent: requirement-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
<기능 목적과 사용자/개발자 관점의 기대 동작>
|
||||||
|
|
||||||
|
## In Scope
|
||||||
|
- <포함 범위>
|
||||||
|
|
||||||
|
## Out Of Scope
|
||||||
|
- <제외 범위>
|
||||||
|
|
||||||
|
## Analysis Definition
|
||||||
|
- analysis_type: linear static | nonlinear static | modal | other
|
||||||
|
- elements: <대상 요소>
|
||||||
|
- dofs: <자유도>
|
||||||
|
- material_model: <재료 모델>
|
||||||
|
- boundary_conditions: <경계조건>
|
||||||
|
- loads: <하중 조건>
|
||||||
|
- coordinate_system: <좌표계>
|
||||||
|
- units: <단위계>
|
||||||
|
|
||||||
|
## Input Requirements
|
||||||
|
- <입력 요구조건>
|
||||||
|
|
||||||
|
## Output Requirements
|
||||||
|
- <출력 요구조건>
|
||||||
|
|
||||||
|
## Verification Quantities
|
||||||
|
- nodal_displacement: required | not-applicable
|
||||||
|
- reaction: required | not-applicable
|
||||||
|
- element_internal_force: required | not-applicable
|
||||||
|
- stress: required | not-applicable
|
||||||
|
- strain: required | not-applicable
|
||||||
|
- energy_or_residual: required | not-applicable
|
||||||
|
|
||||||
|
## Tolerance Policy
|
||||||
|
- absolute_tolerance: <value or TBD>
|
||||||
|
- relative_tolerance: <value or TBD>
|
||||||
|
- norm_based_tolerance: <value or TBD>
|
||||||
|
|
||||||
|
## Reference Artifact Requirements
|
||||||
|
Expected location: `references/<feature-id>/`
|
||||||
|
|
||||||
|
- `model.inp`: required | not-applicable
|
||||||
|
- `metadata.json`: required
|
||||||
|
- `displacements.csv`: required | not-applicable
|
||||||
|
- `reactions.csv`: required | not-applicable
|
||||||
|
- `element_forces.csv`: required | not-applicable
|
||||||
|
- `stresses.csv`: required | not-applicable
|
||||||
|
|
||||||
|
## Requirement Verification Matrix
|
||||||
|
|
||||||
|
| id | statement | category | rationale | source | priority | verification_method | acceptance_criteria | tolerance | downstream_agents | status |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| FESA-REQ-<FEATURE>-001 | The FESA solver shall ... | functional | ... | user | must | reference-comparison | ... | ... | Reference Model Agent; Implementation Planning Agent | draft |
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
- <미확정 값 또는 사용자 결정 필요 사항>
|
||||||
|
|
||||||
|
## Downstream Handoff
|
||||||
|
|
||||||
|
### Research Agent
|
||||||
|
- <조사할 이론, 논문, benchmark, 표준>
|
||||||
|
|
||||||
|
### Formulation Agent
|
||||||
|
- <정식화 단계에 넘길 해석 타입, 요소, 재료, 자유도, 출력 물리량 계약>
|
||||||
|
|
||||||
|
### I/O Definition Agent
|
||||||
|
- <입력/출력 schema 요구조건>
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- <필요한 references/<feature-id>/ artifact 목록>
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- <먼저 작성할 테스트와 acceptance criteria>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 모든 `must` 요구조건은 검증 방법과 acceptance criteria를 가져야 한다.
|
||||||
|
- 모든 수치 요구조건은 단위, 좌표계, tolerance 또는 `TBD with owner`를 가져야 한다.
|
||||||
|
- reference 비교가 필요한 요구조건은 필요한 CSV artifact를 명시해야 한다.
|
||||||
|
- "빠르게", "정확하게", "Abaqus처럼" 같은 문장은 검증 가능한 기준으로 바꾸거나 open question으로 남겨야 한다.
|
||||||
|
- 구현 방법, 정식화 세부식, C++ API는 이 문서에서 확정하지 않는다.
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
# 연구 브리프 작성 가이드
|
||||||
|
|
||||||
|
이 디렉터리는 Research Agent가 작성하거나 제안한 기능별 연구 브리프를 보관하는 위치다.
|
||||||
|
|
||||||
|
기본 파일명은 `docs/research/<feature-id>-research.md` 형식을 사용한다. 각 브리프는 Requirement Agent의 요구조건을 입력으로 받아 Formulation Agent, Numerical Review Agent, Reference Model Agent, Implementation Planning Agent가 사용할 수 있는 근거 자료를 제공해야 한다.
|
||||||
|
|
||||||
|
## Research Agent 역할
|
||||||
|
|
||||||
|
Research Agent는 FEM 이론, benchmark, verification reference, solver manual, 논문 자료를 조사한다.
|
||||||
|
|
||||||
|
수행한다:
|
||||||
|
- 기능 요구조건과 관련된 이론 자료를 조사한다.
|
||||||
|
- 요소별 benchmark, patch test, MMS, MES, convergence study 후보를 찾는다.
|
||||||
|
- Abaqus/Nastran 결과와 비교 가능한 공개 benchmark 또는 문헌 해를 정리한다.
|
||||||
|
- 자료의 신뢰도, 적용 범위, 한계, 상충 여부를 평가한다.
|
||||||
|
- downstream agent가 사용할 수 있도록 출처와 근거를 추적 가능하게 남긴다.
|
||||||
|
|
||||||
|
수행하지 않는다:
|
||||||
|
- C++ 코드를 구현하지 않는다.
|
||||||
|
- 유한요소 정식화를 확정하지 않는다.
|
||||||
|
- C++ API나 파일 구조를 설계하지 않는다.
|
||||||
|
- Abaqus, Nastran 또는 레퍼런스 솔버를 직접 실행하지 않는다.
|
||||||
|
- reference CSV 결과를 생성하지 않는다.
|
||||||
|
- 기능 완료 여부를 승인하지 않는다.
|
||||||
|
|
||||||
|
## Source Reliability Tier
|
||||||
|
|
||||||
|
| tier | source type | examples | use |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Tier 1 | 공식 표준, 공식 solver manual, 공식 benchmark, 공공기관 자료 | ASME V&V 10, Abaqus Verification Guide, Abaqus Benchmarks Guide, NAFEMS benchmarks, NASA FEMCI, official solver manuals | 우선 근거 |
|
||||||
|
| Tier 2 | peer-reviewed paper, reproducible arXiv preprint, textbook | MMS/MES 논문, finite element textbook | 이론/검증 후보 |
|
||||||
|
| Tier 3 | vendor example, university course note, technical blog | 공개 강의노트, 기술 블로그 | 보조 근거 |
|
||||||
|
| Reject | forum answer, LLM summary, unsourced page, illegal PDF mirror, citation 없는 wiki성 문서 | forum, mirror PDF, 출처 없는 요약 | primary evidence로 사용 금지 |
|
||||||
|
|
||||||
|
## 문서 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# <feature title> Research Brief
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: <feature-id>
|
||||||
|
- source_requirement: docs/requirements/<feature-id>.md
|
||||||
|
- status: draft | needs-user-decision | ready-for-formulation
|
||||||
|
- owner_agent: research-agent
|
||||||
|
- date: <YYYY-MM-DD>
|
||||||
|
|
||||||
|
## Research Questions
|
||||||
|
- <Requirement Agent 또는 사용자가 넘긴 조사 질문>
|
||||||
|
|
||||||
|
## Source Inventory
|
||||||
|
|
||||||
|
| source_type | title | author_or_org | URL_or_DOI | access_date | reliability_tier | notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| standard | ASME V&V 10 | ASME | <URL> | <YYYY-MM-DD> | Tier 1 | VVUQ framework |
|
||||||
|
|
||||||
|
## Extracted Facts
|
||||||
|
- <정식화에 필요한 사실, benchmark 조건, 검증 물리량, 재료/좌표/단위 가정>
|
||||||
|
|
||||||
|
## Candidate Benchmarks
|
||||||
|
|
||||||
|
| benchmark_id | source | benchmark_type | physics | target_quantities | artifact_needs | applicability |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| <id> | <source title> | analytical \| NAFEMS \| Abaqus Verification/Benchmark \| NASA/FEMCI \| paper-derived | <physics> | <targets> | <needed artifacts> | <limits> |
|
||||||
|
|
||||||
|
## Verification Relevance
|
||||||
|
- code_verification: <관련성>
|
||||||
|
- solution_verification: <관련성>
|
||||||
|
- validation: <관련성>
|
||||||
|
- reference_comparison: <관련성>
|
||||||
|
|
||||||
|
## Applicability Limits
|
||||||
|
- linear_or_nonlinear: <scope>
|
||||||
|
- deformation: small | large | TBD
|
||||||
|
- element_type: <scope>
|
||||||
|
- material_model: <scope>
|
||||||
|
- geometry: <scope>
|
||||||
|
- boundary_conditions: <scope>
|
||||||
|
- loads: <scope>
|
||||||
|
- coordinate_system: <scope>
|
||||||
|
- units: <scope>
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
- <근거 부족, 상충 자료, 유료/비공개 자료, 사용자 결정 필요 사항>
|
||||||
|
|
||||||
|
## Downstream Handoff
|
||||||
|
|
||||||
|
### Formulation Agent
|
||||||
|
- <이론 사실, governing assumptions, candidate equations, unresolved formulation questions>
|
||||||
|
|
||||||
|
### Numerical Review Agent
|
||||||
|
- <수치 위험, convergence expectations, patch test/MMS/MES evidence, source disagreements>
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- <benchmark candidates, required reference artifacts, target quantities, source limitations>
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- <verification scenarios and testable acceptance evidence>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 품질 기준
|
||||||
|
|
||||||
|
- 모든 외부 근거는 source metadata와 reliability tier를 가져야 한다.
|
||||||
|
- verified fact와 inference를 구분해야 한다.
|
||||||
|
- benchmark 후보는 target quantity와 applicability limit을 가져야 한다.
|
||||||
|
- Abaqus Benchmarks Guide와 Abaqus Verification Guide의 용도를 구분해야 한다.
|
||||||
|
- NAFEMS benchmark는 independent standard test와 target value 후보로 기록해야 한다.
|
||||||
|
- MMS/MES 자료는 code verification 후보로 기록하되 정식화 확정으로 취급하지 않는다.
|
||||||
|
- 사용 불가능하거나 유료/비공개인 자료는 Open Issues에 남겨야 한다.
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
# Abaqus User Subroutines Research Brief
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
- feature_id: abaqus-user-subroutines
|
||||||
|
- source_requirement: N/A
|
||||||
|
- status: draft
|
||||||
|
- owner_agent: research-agent
|
||||||
|
- date: 2026-06-08
|
||||||
|
|
||||||
|
## Research Questions
|
||||||
|
- Abaqus User Subroutine은 어떤 해석 기능을 확장하며, Standard와 Explicit에서 어떤 subroutine family로 나뉘는가?
|
||||||
|
- User subroutine 개발 시 고정해야 할 ABI, include, 입력 파일, 상태변수, debug, compile/link 계약은 무엇인가?
|
||||||
|
- UMAT, VUMAT, UEL, VUEL, USDFLD/VUSDFLD, UVARM, UEXTERNALDB/VEXTERNALDB 중 FESA harness에 우선 반영해야 할 개발/검증 패턴은 무엇인가?
|
||||||
|
- 현재 C++/MSVC/CMake/CTest 중심 harness를 Abaqus user subroutine 개발에 맞추려면 어떤 gate와 artifact 계약이 필요해지는가?
|
||||||
|
|
||||||
|
## Source Inventory
|
||||||
|
|
||||||
|
| source_type | title | author_or_org | URL_or_DOI | access_date | reliability_tier | notes |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| vendor manual mirror | Abaqus Analysis User's Guide 18.1.1, User subroutines: overview | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/usb/pt04ch18s01aus106.html | 2026-06-08 | Tier 1, version-specific mirror | Core lifecycle, include, execution, debugging, state variable, vectorization, parallelization rules. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide A.1, User subroutines index | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ap01s01.html | 2026-06-08 | Tier 1, version-specific mirror | Categorizes Standard, Explicit, CFD user subroutines by function. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide A.2, User subroutine functions listing | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ap01s02.html | 2026-06-08 | Tier 1, version-specific mirror | Defines one-line purpose for each user subroutine. |
|
||||||
|
| vendor manual mirror | Abaqus Analysis User's Guide 26.7.1, User-defined mechanical material behavior | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/usb/pt05ch26s07abm69.html | 2026-06-08 | Tier 1, version-specific mirror | UMAT/VUMAT material behavior, stress/strain conventions, material constants, state variables, deletion, hourglass/shear caveats. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide 1.1.44, UMAT | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ch01s01asb44.html | 2026-06-08 | Tier 1, version-specific mirror | Standard user material interface; source page had slow/scripted HTML but search/open snippets exposed key warnings and variables. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide 1.2.22, VUMAT | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ch01s02asb22.html | 2026-06-08 | Tier 1, version-specific mirror | Explicit vectorized user material interface. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide 1.1.28, UEL | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ch01s01asb28.html | 2026-06-08 | Tier 1, version-specific mirror | Standard user element interface and LFLAGS procedure contract. |
|
||||||
|
| vendor manual mirror | Abaqus Analysis User's Guide 3.2.18, Making user-defined executables and subroutines | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/usb/pt01ch03s02abx18.html | 2026-06-08 | Tier 1, version-specific mirror | `abaqus make`, compile/link environment parameters, shared library deployment. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide 2.1.15, Terminating an analysis | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ch02s01abu15.html | 2026-06-08 | Tier 1, version-specific mirror | `XIT` and `XPLB_EXIT` instead of Fortran `STOP`. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide 2.1.22, Ensuring thread safety | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ch02s01abu22.html | 2026-06-08 | Tier 1, version-specific mirror | Mutex/thread-safety guidance for common blocks, files, and shared resources. |
|
||||||
|
| vendor manual mirror | Abaqus User Subroutines Reference Guide 2.1.23, Allocatable arrays | Dassault Systemes SIMULIA, mirrored by University of Colorado | https://ceae-server.colorado.edu/v2016/books/sub/ch02s01abu23.html | 2026-06-08 | Tier 1, version-specific mirror | Thread-local/global arrays as safer alternatives to common blocks and save variables. |
|
||||||
|
| public code repository | davidmorinNTNU/ABAQUS_subroutines | David Morin, NTNU | https://github.com/davidmorinNTNU/ABAQUS_subroutines | 2026-06-08 | Tier 3 example repository | Fortran examples for UVARM, USDFLD/VUSDFLD, UHARD/VUHARD, UMAT/VUMAT, UEXTERNALDB/VEXTERNALDB. README states examples were checked in Abaqus 2019 double precision with Intel ifort 16.0.8 but are not guaranteed bug-free or validated. |
|
||||||
|
|
||||||
|
## Extracted Facts
|
||||||
|
|
||||||
|
### Scope and execution model
|
||||||
|
|
||||||
|
- Abaqus user subroutines extend features where normal data input is too restrictive. They can be written in C, C++, or Fortran and are supplied at analysis execution time with `abaqus job=job-name user={source-file | object-file}` or through Abaqus/CAE's user subroutine file field.
|
||||||
|
- User subroutines are not saved to restart files. A restarted run must include the subroutine again and may include a revised one.
|
||||||
|
- User subroutines cannot call one another directly. They can call Abaqus-provided utility routines where supported.
|
||||||
|
- Fortran user subroutines must include `aba_param.inc` for Standard or `vaba_param.inc` for Explicit as the first statement after the argument list. C/C++ user subroutines must include `aba_for_c.h`, use Abaqus Fortran-callable naming conventions, and pass arguments by reference.
|
||||||
|
- User code must only define variables listed by the subroutine documentation as variables to be defined. Rewriting information-only variables has unpredictable effects.
|
||||||
|
- The command `abaqus make` can build user postprocessing executables and user subroutine object/shared libraries. The relevant environment parameters include `compile_cpp`, `compile_fortran`, `link_exe`, and `link_sl`. Prebuilt user subroutine shared libraries can be found through `usub_lib_dir`.
|
||||||
|
|
||||||
|
### Development and debugging constraints
|
||||||
|
|
||||||
|
- Abaqus recommends thorough testing on small examples before production use. The manual specifically emphasizes small models where the user subroutine is the only complicated part.
|
||||||
|
- Debug output can be written to Abaqus-owned units: Standard `.msg` through unit 7, Standard `.dat` or Explicit `.log` through unit 6. Those units must not be opened by user code. Other user files should use allowed unit ranges and full paths because Abaqus uses scratch directories.
|
||||||
|
- `ABA_PARALLEL_DEBUG` can increase verbosity and expose compile/link/debug information.
|
||||||
|
- Use `XIT` in Standard and `XPLB_EXIT` in Explicit instead of `STOP` so Abaqus closes analysis files properly.
|
||||||
|
- Large arrays should not live on the stack. Native allocatable arrays or Abaqus allocatable-array utilities should be used for large or persistent data.
|
||||||
|
- Parallel jobs are allowed, but common blocks, common files, global arrays, and shared resources must be guarded for thread safety. Abaqus provides mutex utilities and local/global allocatable array utilities.
|
||||||
|
|
||||||
|
### Model identity and data conventions
|
||||||
|
|
||||||
|
- Coordinates passed to user subroutines are generally global assembly coordinates unless a specific interface says otherwise.
|
||||||
|
- Node and element numbers passed into user subroutines are Abaqus internal global numbers. `GETPARTINFO`/`VGETPARTINFO` and `GETINTERNAL`/`VGETINTERNAL` are available when original part instance names and local numbers are needed, but their use is not free.
|
||||||
|
- Set and surface names passed into user subroutines are uppercase and, for assemblies, prefixed by assembly and part instance names.
|
||||||
|
- Solution-dependent state variables are allocated differently depending on the subroutine family. Common material subroutines usually use `*DEPVAR`; UEL uses `*USER ELEMENT, VARIABLES=...`; contact/interface subroutines use their own option-specific `DEPVAR` contracts.
|
||||||
|
- State variable output is available through `SDV`/`SDVn` for supported material/integration-point cases.
|
||||||
|
|
||||||
|
### Standard vs Explicit API shape
|
||||||
|
|
||||||
|
- Abaqus/Standard subroutines are generally scalar per material point, element, node, or contact point. Standard material/element/interface subroutines are often called twice in the first iteration of an increment to form initial stiffness and once in later iterations, with extra calls in some dynamic procedures.
|
||||||
|
- Abaqus/Explicit subroutines use a vector interface: blocks of data for `nblock` material points are passed to routines such as VUMAT. `vaba_param.inc` defines `maxblk` for dimensioning temporary arrays.
|
||||||
|
- Abaqus/Explicit has single and double precision executables. The precision is determined by the executable and `vaba_param.inc`; user code should follow Abaqus precision conventions instead of hard-coding incompatible types.
|
||||||
|
|
||||||
|
### UMAT and VUMAT
|
||||||
|
|
||||||
|
- User-defined mechanical behavior is implemented through UMAT for Abaqus/Standard and VUMAT for Abaqus/Explicit. This interface allows arbitrary mechanical constitutive models but is explicitly not a routine exercise.
|
||||||
|
- UMAT and VUMAT operate on Cauchy stress components. VUMAT quantities are expressed in a corotational coordinate system at the material point, and Abaqus uses the Green-Naghdi stress rate in VUMAT; built-in Explicit materials may use different objective stress rates.
|
||||||
|
- Mechanical material constants are supplied through `*USER MATERIAL`. Abaqus/Explicit also requires `*DENSITY`.
|
||||||
|
- In Standard, UMAT must return updated stress, updated state variables, and the material Jacobian `DDSDDE`. The Jacobian strongly controls Newton convergence and computational efficiency. If the Jacobian is nonsymmetric, `UNSYMM` should be requested.
|
||||||
|
- In Explicit, VUMAT receives blocks of points and must return `stressNew` and `stateNew`; it can also update internal and inelastic energy arrays.
|
||||||
|
- Element deletion can be controlled by a state variable with `*DEPVAR, DELETE=...`; deleted material points carry no stress and cannot be reactivated.
|
||||||
|
- For reduced-integration, beam, shell, and transverse-shear cases, user material behavior may require explicit hourglass or transverse shear stiffness choices because Abaqus may not be able to infer them from user material data.
|
||||||
|
- Hybrid element behavior with UMAT has special total/incremental/incompressible formulations. Nearly incompressible hyperelastic user materials can converge poorly if the wrong hybrid formulation is used.
|
||||||
|
|
||||||
|
### UEL and VUEL
|
||||||
|
|
||||||
|
- UEL defines an Abaqus/Standard user element. The core interface includes `RHS`, `AMATRX`, `SVARS`, `ENERGY`, element-level DOF counts, properties, coordinates, displacements, velocities/accelerations as relevant, time, step/increment, and flags.
|
||||||
|
- `LFLAGS` drives what the UEL must compute. For normal implicit time incrementation, UEL must define residual vector `RHS` and Jacobian/stiffness matrix `AMATRX`; other flag values request stiffness-only, damping-only, mass-only, residual-only, initial acceleration, or perturbation output contributions.
|
||||||
|
- UEL examples in the manual include a two-node structural user element behaving as a linear truss, with `*USER ELEMENT`, `*ELEMENT`, and `*UEL PROPERTY` input contracts. This is a strong candidate for a first reproducible artifact pattern if the project targets user elements.
|
||||||
|
- VUEL is the Explicit user element analogue, but this investigation did not yet drill into its detailed interface. It should be treated as a separate research item before implementation planning.
|
||||||
|
|
||||||
|
### Other relevant subroutine families
|
||||||
|
|
||||||
|
- `USDFLD`/`VUSDFLD`: redefine field variables at material points; useful for field-dependent material behavior and damage/softening controls.
|
||||||
|
- `UFIELD`/`VUFIELD`: define predefined field variables, often nodal or field-level before interpolation.
|
||||||
|
- `UVARM`: generate custom element output in Standard; useful for exposing derived variables from existing material state.
|
||||||
|
- `UEXTERNALDB`/`VEXTERNALDB`: manage external databases, files, cross-subroutine data exchange, or coupling with external programs at key analysis points.
|
||||||
|
- `UHARD`/`VUHARD`: define hardening/yield surface size behavior without replacing the full material update.
|
||||||
|
- `ORIENT`: define material/local directions.
|
||||||
|
- `DLOAD`/`VDLOAD`, `DISP`/`VDISP`, `UAMP`/`VUAMP`: load, motion, and amplitude customization.
|
||||||
|
- `UINTER`/`VUINTER`/`VUINTERACTION`, `FRIC`/`VFRIC`: contact/interface behavior customization.
|
||||||
|
|
||||||
|
### Observed public example repository patterns
|
||||||
|
|
||||||
|
- The NTNU repository contains examples for UVARM, USDFLD/VUSDFLD, UHARD/VUHARD, UMAT/VUMAT, UEXTERNALDB/VEXTERNALDB, plus a Modified Johnson-Cook example combining VUHARD and VUSDFLD.
|
||||||
|
- Each example folder generally contains a Fortran subroutine, Abaqus input files, post-processing Python scripts, plotting scripts, and a PDF describing the subroutine, input file structure, and results.
|
||||||
|
- The V_UMAT folder includes paired Standard/Explicit material examples: `UMAT.f`, `UMAT_MODEL.f`, `VUMAT.f`, `VUMAT_SHELL.f`, Standard/Explicit `.inp` files, post-processing scripts, plotting scripts, and a talk PDF.
|
||||||
|
- The V_USDFLD folder contains Standard and Explicit field-variable variants and both patch and two-element post-processing scripts.
|
||||||
|
- The repository README cautions that the examples were checked but may not be bug-free and are not necessarily validation-quality. Therefore this repository is useful as a development-pattern source, not as acceptance evidence.
|
||||||
|
|
||||||
|
## Candidate Benchmarks and Verification Artifacts
|
||||||
|
|
||||||
|
| benchmark_id | source | benchmark_type | physics | target_quantities | artifact_needs | applicability |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| umat-single-element-elastic | Abaqus manuals, inferred from single-element testing guidance | smoke / analytical | Standard user material | stress, `DDSDDE`, state variables, convergence behavior | one-element `.inp`, user material constants, expected analytical stress/Jacobian CSV, `.msg` summary | Best first harness target for UMAT ABI and constitutive update tests. |
|
||||||
|
| vumat-single-element-elastic | Abaqus manuals, inferred from single-element testing guidance | smoke / analytical | Explicit vectorized user material | `stressNew`, `stateNew`, energy arrays, stable explicit response | one-element Explicit `.inp`, density, expected stress history CSV | Tests `nblock` loop and tensor ordering/precision assumptions. |
|
||||||
|
| umat-vs-built-in-linear-elastic | Abaqus material docs and UMAT/VUMAT contract | regression / reference comparison | Standard Cauchy stress update | stress, strain, SDV, reaction/displacement if run through Abaqus | built-in and UMAT `.inp` pair, reference CSVs from approved Abaqus run | Requires user-generated Abaqus artifacts; not generated by agents. |
|
||||||
|
| vumat-vs-built-in-linear-elastic | Abaqus material docs and VUMAT contract | regression / reference comparison | Explicit user material | stress, strain, internal energy, displacement/reaction | built-in and VUMAT `.inp` pair, reference CSVs | Must control objective-rate and tensor-ordering assumptions. |
|
||||||
|
| uel-two-node-truss | Abaqus UEL manual example | analytical / user element | Standard user element | element residual, stiffness, nodal displacement, reaction, energy | `*USER ELEMENT` truss `.inp`, UEL source, expected truss analytical CSV | Strong first UEL target; maps cleanly to existing FESA truss/bar solver ideas. |
|
||||||
|
| usdfld-field-update | NTNU V_USDFLD examples plus Abaqus field-variable docs | regression / patch | Field-dependent material data | field values, SDV, stress changes driven by field | Standard/Explicit `.inp`, field/SDV CSVs, post scripts | Example repository useful for structure; official acceptance must come from controlled reference artifacts. |
|
||||||
|
| uexternaldb-file-exchange | Abaqus overview and NTNU V_UEXTERNALDB examples | integration / harness | External file/database lifecycle | call order, file creation, increment/step metadata | `.inp`, user subroutine, expected external log file schema | Useful for harnessing file I/O and thread-safety policy. |
|
||||||
|
|
||||||
|
## Verification Relevance
|
||||||
|
|
||||||
|
- code_verification: High. UMAT/VUMAT/UEL logic can be unit-tested outside Abaqus if constitutive kernels or element kernels are factored away from the Abaqus ABI wrapper.
|
||||||
|
- solution_verification: High but artifact-dependent. Abaqus runs must be performed by a human or approved external process and stored as reference artifacts.
|
||||||
|
- validation: Out of scope for this first research pass. Public examples and single-element checks do not validate physical material models against experiments.
|
||||||
|
- reference_comparison: High. The current FESA reference-comparison pattern can be adapted to compare approved Abaqus `.odb`-extracted CSVs, `.dat`/`.msg` summaries, and post-processing outputs.
|
||||||
|
|
||||||
|
## Applicability Limits
|
||||||
|
|
||||||
|
- The main manual sources are Abaqus 2016 mirrors. Interface details must be rechecked against the target installed Abaqus version before implementation.
|
||||||
|
- Official Dassault documentation may require customer access; the accessible sources here are university mirrors of the 2016 manuals.
|
||||||
|
- This research does not approve any specific material model, element formulation, stress integration algorithm, or tangent derivation.
|
||||||
|
- This research does not create, modify, or validate reference CSVs.
|
||||||
|
- This research does not run Abaqus, compile Fortran, or test compiler/linker compatibility.
|
||||||
|
- The project harness currently assumes C++17/MSVC/CMake/CTest. Abaqus user subroutine development will likely require a new or extended validation path for Fortran/C/C++ source plus `abaqus job=... user=...` and/or `abaqus make`, guarded by environment detection.
|
||||||
|
- The NTNU examples are useful for repository layout and one/two-element workflows, but their README explicitly limits their verification/validation claims.
|
||||||
|
|
||||||
|
## Implications for This Project Harness
|
||||||
|
|
||||||
|
- The project should not simply rename the existing C++ solver harness. Abaqus user subroutine development has a different execution boundary: source is compiled and linked by the Abaqus execution procedure, not by CMake alone.
|
||||||
|
- A pragmatic architecture is to split each subroutine into:
|
||||||
|
- a thin Abaqus ABI wrapper matching the exact manual signature;
|
||||||
|
- a testable kernel for constitutive update, field update, element residual/tangent, or external database behavior;
|
||||||
|
- small Abaqus `.inp` reference models and approved CSV/log artifacts.
|
||||||
|
- The current TDD guard should be extended or complemented for Fortran/C/C++ Abaqus source. For production subroutine changes, require either:
|
||||||
|
- a kernel unit test, or
|
||||||
|
- an Abaqus artifact comparison test, or
|
||||||
|
- both for UMAT/VUMAT/UEL.
|
||||||
|
- Workspace validation should gain explicit modes:
|
||||||
|
- no-Abaqus mode: run Python harness tests and pure kernel tests only;
|
||||||
|
- Abaqus-available mode: run compile/link smoke tests and selected `abaqus job=... user=...` reference cases;
|
||||||
|
- artifact-comparison mode: compare stored solver output CSV/log artifacts without rerunning Abaqus.
|
||||||
|
- Reference artifact contracts should include `.inp`, user subroutine source version/hash, Abaqus version, compiler version, precision, command line, `.msg`/`.dat`/`.log` tail, extracted CSVs, and post-processing script provenance.
|
||||||
|
- For UMAT/VUMAT, the first implementation gate should focus on a simple elastic or J2 plastic single-element model before complex material laws.
|
||||||
|
- For UEL, the first implementation gate should focus on a two-node truss/bar element because it has analytical residual/stiffness checks and aligns with the existing FESA solver roadmap.
|
||||||
|
|
||||||
|
## Downstream Handoff
|
||||||
|
|
||||||
|
### Requirement Agent
|
||||||
|
- Decide the primary target: UMAT, VUMAT, UEL/VUEL, field subroutines, output subroutines, or external database routines.
|
||||||
|
- Record target Abaqus version, operating system, compiler/toolchain, and whether Abaqus is available for local validation.
|
||||||
|
- Define whether the project will develop Fortran-first subroutines, C/C++ subroutines, or Fortran ABI wrappers over C++ kernels.
|
||||||
|
|
||||||
|
### I/O Definition Agent
|
||||||
|
- Define supported Abaqus input keyword subset for each target subroutine family:
|
||||||
|
- UMAT/VUMAT: `*MATERIAL`, `*USER MATERIAL`, `*DEPVAR`, `*DENSITY`, output requests.
|
||||||
|
- UEL: `*USER ELEMENT`, `*UEL PROPERTY`, `*ELEMENT`, output requests.
|
||||||
|
- USDFLD/VUSDFLD: `*FIELD`, `*DEPVAR`, material field dependency contracts.
|
||||||
|
- Define CSV schemas for stress, strain, state variables, element residual/stiffness summaries, displacement, reaction, energy, and call-log/debug outputs.
|
||||||
|
|
||||||
|
### Reference Model Agent
|
||||||
|
- Start with one-element UMAT/VUMAT and two-node UEL truss models.
|
||||||
|
- Require metadata for Abaqus version, compiler version, precision, command, input deck, source hash, and extraction script.
|
||||||
|
- Treat all generated Abaqus outputs as read-only reference artifacts after approval.
|
||||||
|
|
||||||
|
### Implementation Planning Agent
|
||||||
|
- Plan RED tests around pure kernels first, then ABI wrapper compile smoke, then Abaqus artifact comparison if Abaqus is available.
|
||||||
|
- Require targeted tests for tensor component ordering, state variable allocation, material constant parsing, element deletion flags, and `DDSDDE` symmetry/unsymmetry policy.
|
||||||
|
- Preserve no-Abaqus validation path so the repository remains testable without commercial solver access.
|
||||||
|
|
||||||
|
### Numerical Review Agent
|
||||||
|
- For UMAT, review stress update algorithm, objective rates, state integration, consistent tangent, symmetry, and hybrid/incompressible assumptions.
|
||||||
|
- For VUMAT, review corotational frame assumptions, vectorization loop, stable explicit response, energy accounting, and deleted material point behavior.
|
||||||
|
- For UEL, review residual sign convention, tangent consistency, mass/damping/stiffness contributions, `LFLAGS` branching, and energy terms.
|
||||||
|
|
||||||
|
## Open Issues
|
||||||
|
|
||||||
|
- Target Abaqus version is not yet specified. The cited manuals are Abaqus 2016.
|
||||||
|
- Target implementation language is not yet specified. Abaqus supports Fortran, C, and C++, but most public examples and legacy workflows are Fortran-first.
|
||||||
|
- Windows compiler compatibility is not yet specified. Abaqus, Visual Studio, Intel Fortran/oneAPI, and MSVC versions must be aligned.
|
||||||
|
- It is not yet clear whether local Abaqus execution is available in this workspace. The current harness should keep a no-Abaqus path.
|
||||||
|
- The project needs a license policy for third-party example code before copying or adapting code from public repositories.
|
||||||
@@ -0,0 +1,417 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Harness Step Executor — phase 내 step을 순차 실행하고 자가 교정한다.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python scripts/execute.py <phase-dir> [--push]
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import contextlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import types
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def progress_indicator(label: str):
|
||||||
|
"""터미널 진행 표시기. with 문으로 사용하며 .elapsed 로 경과 시간을 읽는다."""
|
||||||
|
frames = "◐◓◑◒"
|
||||||
|
stop = threading.Event()
|
||||||
|
t0 = time.monotonic()
|
||||||
|
|
||||||
|
def _animate():
|
||||||
|
idx = 0
|
||||||
|
while not stop.wait(0.12):
|
||||||
|
sec = int(time.monotonic() - t0)
|
||||||
|
sys.stderr.write(f"\r{frames[idx % len(frames)]} {label} [{sec}s]")
|
||||||
|
sys.stderr.flush()
|
||||||
|
idx += 1
|
||||||
|
sys.stderr.write("\r" + " " * (len(label) + 20) + "\r")
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
th = threading.Thread(target=_animate, daemon=True)
|
||||||
|
th.start()
|
||||||
|
info = types.SimpleNamespace(elapsed=0.0)
|
||||||
|
try:
|
||||||
|
yield info
|
||||||
|
finally:
|
||||||
|
stop.set()
|
||||||
|
th.join()
|
||||||
|
info.elapsed = time.monotonic() - t0
|
||||||
|
|
||||||
|
|
||||||
|
class StepExecutor:
|
||||||
|
"""Phase 디렉토리 안의 step들을 순차 실행하는 하네스."""
|
||||||
|
|
||||||
|
MAX_RETRIES = 3
|
||||||
|
FEAT_MSG = "feat({phase}): step {num} — {name}"
|
||||||
|
CHORE_MSG = "chore({phase}): step {num} output"
|
||||||
|
TZ = timezone(timedelta(hours=9))
|
||||||
|
|
||||||
|
def __init__(self, phase_dir_name: str, *, auto_push: bool = False):
|
||||||
|
self._root = str(ROOT)
|
||||||
|
self._phases_dir = ROOT / "phases"
|
||||||
|
self._phase_dir = self._phases_dir / phase_dir_name
|
||||||
|
self._phase_dir_name = phase_dir_name
|
||||||
|
self._top_index_file = self._phases_dir / "index.json"
|
||||||
|
self._auto_push = auto_push
|
||||||
|
|
||||||
|
if not self._phase_dir.is_dir():
|
||||||
|
print(f"ERROR: {self._phase_dir} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
self._index_file = self._phase_dir / "index.json"
|
||||||
|
if not self._index_file.exists():
|
||||||
|
print(f"ERROR: {self._index_file} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
idx = self._read_json(self._index_file)
|
||||||
|
self._project = idx.get("project", "project")
|
||||||
|
self._phase_name = idx.get("phase", phase_dir_name)
|
||||||
|
self._total = len(idx["steps"])
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self._print_header()
|
||||||
|
self._check_blockers()
|
||||||
|
self._checkout_branch()
|
||||||
|
guardrails = self._load_guardrails()
|
||||||
|
self._ensure_created_at()
|
||||||
|
self._execute_all_steps(guardrails)
|
||||||
|
self._finalize()
|
||||||
|
|
||||||
|
# --- timestamps ---
|
||||||
|
|
||||||
|
def _stamp(self) -> str:
|
||||||
|
return datetime.now(self.TZ).strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||||
|
|
||||||
|
# --- JSON I/O ---
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _read_json(p: Path) -> dict:
|
||||||
|
return json.loads(p.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _write_json(p: Path, data: dict):
|
||||||
|
p.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||||
|
|
||||||
|
# --- git ---
|
||||||
|
|
||||||
|
def _run_git(self, *args) -> subprocess.CompletedProcess:
|
||||||
|
cmd = ["git"] + list(args)
|
||||||
|
return subprocess.run(cmd, cwd=self._root, capture_output=True, text=True)
|
||||||
|
|
||||||
|
def _checkout_branch(self):
|
||||||
|
branch = f"feat-{self._phase_name}"
|
||||||
|
|
||||||
|
r = self._run_git("rev-parse", "--abbrev-ref", "HEAD")
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(f" ERROR: git을 사용할 수 없거나 git repo가 아닙니다.")
|
||||||
|
print(f" {r.stderr.strip()}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if r.stdout.strip() == branch:
|
||||||
|
return
|
||||||
|
|
||||||
|
r = self._run_git("rev-parse", "--verify", branch)
|
||||||
|
r = self._run_git("checkout", branch) if r.returncode == 0 else self._run_git("checkout", "-b", branch)
|
||||||
|
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(f" ERROR: 브랜치 '{branch}' checkout 실패.")
|
||||||
|
print(f" {r.stderr.strip()}")
|
||||||
|
print(f" Hint: 변경사항을 stash하거나 commit한 후 다시 시도하세요.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f" Branch: {branch}")
|
||||||
|
|
||||||
|
def _commit_step(self, step_num: int, step_name: str):
|
||||||
|
output_rel = f"phases/{self._phase_dir_name}/step{step_num}-output.json"
|
||||||
|
index_rel = f"phases/{self._phase_dir_name}/index.json"
|
||||||
|
|
||||||
|
self._run_git("add", "-A")
|
||||||
|
self._run_git("reset", "HEAD", "--", output_rel)
|
||||||
|
self._run_git("reset", "HEAD", "--", index_rel)
|
||||||
|
|
||||||
|
if self._run_git("diff", "--cached", "--quiet").returncode != 0:
|
||||||
|
msg = self.FEAT_MSG.format(phase=self._phase_name, num=step_num, name=step_name)
|
||||||
|
r = self._run_git("commit", "-m", msg)
|
||||||
|
if r.returncode == 0:
|
||||||
|
print(f" Commit: {msg}")
|
||||||
|
else:
|
||||||
|
print(f" WARN: 코드 커밋 실패: {r.stderr.strip()}")
|
||||||
|
|
||||||
|
self._run_git("add", "-A")
|
||||||
|
if self._run_git("diff", "--cached", "--quiet").returncode != 0:
|
||||||
|
msg = self.CHORE_MSG.format(phase=self._phase_name, num=step_num)
|
||||||
|
r = self._run_git("commit", "-m", msg)
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(f" WARN: housekeeping 커밋 실패: {r.stderr.strip()}")
|
||||||
|
|
||||||
|
# --- top-level index ---
|
||||||
|
|
||||||
|
def _update_top_index(self, status: str):
|
||||||
|
if not self._top_index_file.exists():
|
||||||
|
return
|
||||||
|
top = self._read_json(self._top_index_file)
|
||||||
|
ts = self._stamp()
|
||||||
|
for phase in top.get("phases", []):
|
||||||
|
if phase.get("dir") == self._phase_dir_name:
|
||||||
|
phase["status"] = status
|
||||||
|
ts_key = {"completed": "completed_at", "error": "failed_at", "blocked": "blocked_at"}.get(status)
|
||||||
|
if ts_key:
|
||||||
|
phase[ts_key] = ts
|
||||||
|
break
|
||||||
|
self._write_json(self._top_index_file, top)
|
||||||
|
|
||||||
|
# --- guardrails & context ---
|
||||||
|
|
||||||
|
def _load_guardrails(self) -> str:
|
||||||
|
sections = []
|
||||||
|
agents_md = ROOT / "AGENTS.md"
|
||||||
|
if agents_md.exists():
|
||||||
|
sections.append(f"## 프로젝트 규칙 (AGENTS.md)\n\n{agents_md.read_text(encoding='utf-8')}")
|
||||||
|
docs_dir = ROOT / "docs"
|
||||||
|
if docs_dir.is_dir():
|
||||||
|
for doc in sorted(docs_dir.glob("*.md")):
|
||||||
|
sections.append(f"## {doc.stem}\n\n{doc.read_text(encoding='utf-8')}")
|
||||||
|
return "\n\n---\n\n".join(sections) if sections else ""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _build_step_context(index: dict) -> str:
|
||||||
|
lines = [
|
||||||
|
f"- Step {s['step']} ({s['name']}): {s['summary']}"
|
||||||
|
for s in index["steps"]
|
||||||
|
if s["status"] == "completed" and s.get("summary")
|
||||||
|
]
|
||||||
|
if not lines:
|
||||||
|
return ""
|
||||||
|
return "## 이전 Step 산출물\n\n" + "\n".join(lines) + "\n\n"
|
||||||
|
|
||||||
|
def _build_preamble(self, guardrails: str, step_context: str,
|
||||||
|
prev_error: Optional[str] = None) -> str:
|
||||||
|
commit_example = self.FEAT_MSG.format(
|
||||||
|
phase=self._phase_name, num="N", name="<step-name>"
|
||||||
|
)
|
||||||
|
retry_section = ""
|
||||||
|
if prev_error:
|
||||||
|
retry_section = (
|
||||||
|
f"\n## ⚠ 이전 시도 실패 — 아래 에러를 반드시 참고하여 수정하라\n\n"
|
||||||
|
f"{prev_error}\n\n---\n\n"
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
f"당신은 {self._project} 프로젝트의 개발자입니다. 아래 step을 수행하세요.\n\n"
|
||||||
|
f"{guardrails}\n\n---\n\n"
|
||||||
|
f"{step_context}{retry_section}"
|
||||||
|
f"## 작업 규칙\n\n"
|
||||||
|
f"1. 이전 step에서 작성된 코드를 확인하고 일관성을 유지하라.\n"
|
||||||
|
f"2. 이 step에 명시된 작업만 수행하라. 추가 기능이나 파일을 만들지 마라.\n"
|
||||||
|
f"3. 기존 테스트를 깨뜨리지 마라.\n"
|
||||||
|
f"4. AC(Acceptance Criteria) 검증을 직접 실행하라.\n"
|
||||||
|
f"5. /phases/{self._phase_dir_name}/index.json의 해당 step status를 업데이트하라:\n"
|
||||||
|
f" - AC 통과 → \"completed\" + \"summary\" 필드에 이 step의 산출물을 한 줄로 요약\n"
|
||||||
|
f" - {self.MAX_RETRIES}회 수정 시도 후에도 실패 → \"error\" + \"error_message\" 기록\n"
|
||||||
|
f" - 사용자 개입이 필요한 경우 (API 키, 인증, 수동 설정 등) → \"blocked\" + \"blocked_reason\" 기록 후 즉시 중단\n"
|
||||||
|
f"6. 모든 변경사항을 커밋하라:\n"
|
||||||
|
f" {commit_example}\n\n---\n\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Codex 호출 ---
|
||||||
|
|
||||||
|
def _invoke_codex(self, step: dict, preamble: str) -> dict:
|
||||||
|
step_num, step_name = step["step"], step["name"]
|
||||||
|
step_file = self._phase_dir / f"step{step_num}.md"
|
||||||
|
|
||||||
|
if not step_file.exists():
|
||||||
|
print(f" ERROR: {step_file} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
prompt = preamble + step_file.read_text(encoding="utf-8")
|
||||||
|
result = subprocess.run(
|
||||||
|
["codex", "exec", "--dangerously-bypass-approvals-and-sandbox", "--json", prompt],
|
||||||
|
cwd=self._root, capture_output=True, text=True, timeout=1800,
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"\n WARN: Codex가 비정상 종료됨 (code {result.returncode})")
|
||||||
|
if result.stderr:
|
||||||
|
print(f" stderr: {result.stderr[:500]}")
|
||||||
|
|
||||||
|
output = {
|
||||||
|
"step": step_num, "name": step_name,
|
||||||
|
"exitCode": result.returncode,
|
||||||
|
"stdout": result.stdout, "stderr": result.stderr,
|
||||||
|
}
|
||||||
|
out_path = self._phase_dir / f"step{step_num}-output.json"
|
||||||
|
with open(out_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(output, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
# --- 헤더 & 검증 ---
|
||||||
|
|
||||||
|
def _print_header(self):
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f" Harness Step Executor")
|
||||||
|
print(f" Phase: {self._phase_name} | Steps: {self._total}")
|
||||||
|
if self._auto_push:
|
||||||
|
print(f" Auto-push: enabled")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
def _check_blockers(self):
|
||||||
|
index = self._read_json(self._index_file)
|
||||||
|
for s in reversed(index["steps"]):
|
||||||
|
if s["status"] == "error":
|
||||||
|
print(f"\n ✗ Step {s['step']} ({s['name']}) failed.")
|
||||||
|
print(f" Error: {s.get('error_message', 'unknown')}")
|
||||||
|
print(f" Fix and reset status to 'pending' to retry.")
|
||||||
|
sys.exit(1)
|
||||||
|
if s["status"] == "blocked":
|
||||||
|
print(f"\n ⏸ Step {s['step']} ({s['name']}) blocked.")
|
||||||
|
print(f" Reason: {s.get('blocked_reason', 'unknown')}")
|
||||||
|
print(f" Resolve and reset status to 'pending' to retry.")
|
||||||
|
sys.exit(2)
|
||||||
|
if s["status"] != "pending":
|
||||||
|
break
|
||||||
|
|
||||||
|
def _ensure_created_at(self):
|
||||||
|
index = self._read_json(self._index_file)
|
||||||
|
if "created_at" not in index:
|
||||||
|
index["created_at"] = self._stamp()
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
|
||||||
|
# --- 실행 루프 ---
|
||||||
|
|
||||||
|
def _execute_single_step(self, step: dict, guardrails: str) -> bool:
|
||||||
|
"""단일 step 실행 (재시도 포함). 완료되면 True, 실패/차단이면 False."""
|
||||||
|
step_num, step_name = step["step"], step["name"]
|
||||||
|
done = sum(1 for s in self._read_json(self._index_file)["steps"] if s["status"] == "completed")
|
||||||
|
prev_error = None
|
||||||
|
|
||||||
|
for attempt in range(1, self.MAX_RETRIES + 1):
|
||||||
|
index = self._read_json(self._index_file)
|
||||||
|
step_context = self._build_step_context(index)
|
||||||
|
preamble = self._build_preamble(guardrails, step_context, prev_error)
|
||||||
|
|
||||||
|
tag = f"Step {step_num}/{self._total - 1} ({done} done): {step_name}"
|
||||||
|
if attempt > 1:
|
||||||
|
tag += f" [retry {attempt}/{self.MAX_RETRIES}]"
|
||||||
|
|
||||||
|
with progress_indicator(tag) as pi:
|
||||||
|
self._invoke_codex(step, preamble)
|
||||||
|
elapsed = int(pi.elapsed)
|
||||||
|
|
||||||
|
index = self._read_json(self._index_file)
|
||||||
|
status = next((s.get("status", "pending") for s in index["steps"] if s["step"] == step_num), "pending")
|
||||||
|
ts = self._stamp()
|
||||||
|
|
||||||
|
if status == "completed":
|
||||||
|
for s in index["steps"]:
|
||||||
|
if s["step"] == step_num:
|
||||||
|
s["completed_at"] = ts
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
self._commit_step(step_num, step_name)
|
||||||
|
print(f" ✓ Step {step_num}: {step_name} [{elapsed}s]")
|
||||||
|
return True
|
||||||
|
|
||||||
|
if status == "blocked":
|
||||||
|
for s in index["steps"]:
|
||||||
|
if s["step"] == step_num:
|
||||||
|
s["blocked_at"] = ts
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
reason = next((s.get("blocked_reason", "") for s in index["steps"] if s["step"] == step_num), "")
|
||||||
|
print(f" ⏸ Step {step_num}: {step_name} blocked [{elapsed}s]")
|
||||||
|
print(f" Reason: {reason}")
|
||||||
|
self._update_top_index("blocked")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
err_msg = next(
|
||||||
|
(s.get("error_message", "Step did not update status") for s in index["steps"] if s["step"] == step_num),
|
||||||
|
"Step did not update status",
|
||||||
|
)
|
||||||
|
|
||||||
|
if attempt < self.MAX_RETRIES:
|
||||||
|
for s in index["steps"]:
|
||||||
|
if s["step"] == step_num:
|
||||||
|
s["status"] = "pending"
|
||||||
|
s.pop("error_message", None)
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
prev_error = err_msg
|
||||||
|
print(f" ↻ Step {step_num}: retry {attempt}/{self.MAX_RETRIES} — {err_msg}")
|
||||||
|
else:
|
||||||
|
for s in index["steps"]:
|
||||||
|
if s["step"] == step_num:
|
||||||
|
s["status"] = "error"
|
||||||
|
s["error_message"] = f"[{self.MAX_RETRIES}회 시도 후 실패] {err_msg}"
|
||||||
|
s["failed_at"] = ts
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
self._commit_step(step_num, step_name)
|
||||||
|
print(f" ✗ Step {step_num}: {step_name} failed after {self.MAX_RETRIES} attempts [{elapsed}s]")
|
||||||
|
print(f" Error: {err_msg}")
|
||||||
|
self._update_top_index("error")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return False # unreachable
|
||||||
|
|
||||||
|
def _execute_all_steps(self, guardrails: str):
|
||||||
|
while True:
|
||||||
|
index = self._read_json(self._index_file)
|
||||||
|
pending = next((s for s in index["steps"] if s["status"] == "pending"), None)
|
||||||
|
if pending is None:
|
||||||
|
print("\n All steps completed!")
|
||||||
|
return
|
||||||
|
|
||||||
|
step_num = pending["step"]
|
||||||
|
for s in index["steps"]:
|
||||||
|
if s["step"] == step_num and "started_at" not in s:
|
||||||
|
s["started_at"] = self._stamp()
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
break
|
||||||
|
|
||||||
|
self._execute_single_step(pending, guardrails)
|
||||||
|
|
||||||
|
def _finalize(self):
|
||||||
|
index = self._read_json(self._index_file)
|
||||||
|
index["completed_at"] = self._stamp()
|
||||||
|
self._write_json(self._index_file, index)
|
||||||
|
self._update_top_index("completed")
|
||||||
|
|
||||||
|
self._run_git("add", "-A")
|
||||||
|
if self._run_git("diff", "--cached", "--quiet").returncode != 0:
|
||||||
|
msg = f"chore({self._phase_name}): mark phase completed"
|
||||||
|
r = self._run_git("commit", "-m", msg)
|
||||||
|
if r.returncode == 0:
|
||||||
|
print(f" ✓ {msg}")
|
||||||
|
|
||||||
|
if self._auto_push:
|
||||||
|
branch = f"feat-{self._phase_name}"
|
||||||
|
r = self._run_git("push", "-u", "origin", branch)
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(f"\n ERROR: git push 실패: {r.stderr.strip()}")
|
||||||
|
sys.exit(1)
|
||||||
|
print(f" ✓ Pushed to origin/{branch}")
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f" Phase '{self._phase_name}' completed!")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Harness Step Executor")
|
||||||
|
parser.add_argument("phase_dir", help="Phase directory name (e.g. 0-mvp)")
|
||||||
|
parser.add_argument("--push", action="store_true", help="Push branch after completion")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
StepExecutor(args.phase_dir, auto_push=args.push).run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Intel oneAPI Fortran discovery helpers for no-Abaqus validation."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
|
|
||||||
|
COMPILER_CANDIDATES = ("ifx", "ifort")
|
||||||
|
ONEAPI_VARS_CANDIDATES = [
|
||||||
|
Path(r"C:\Program Files (x86)\Intel\oneAPI\compiler\latest\env\vars.bat"),
|
||||||
|
Path(r"C:\Program Files\Intel\oneAPI\compiler\latest\env\vars.bat"),
|
||||||
|
Path(r"C:\Program Files (x86)\Intel\oneAPI\setvars.bat"),
|
||||||
|
Path(r"C:\Program Files\Intel\oneAPI\setvars.bat"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FortranToolchain:
|
||||||
|
def __init__(self, *, name: str, executable: str, env_script: Path | None):
|
||||||
|
self.name = name
|
||||||
|
self.executable = executable
|
||||||
|
self.env_script = env_script
|
||||||
|
|
||||||
|
|
||||||
|
def compiler_candidates(preference: str | None = None) -> list[str]:
|
||||||
|
preference = (preference or os.environ.get("HARNESS_FORTRAN_COMPILER") or "auto").lower()
|
||||||
|
if preference == "auto":
|
||||||
|
return list(COMPILER_CANDIDATES)
|
||||||
|
if preference not in COMPILER_CANDIDATES:
|
||||||
|
raise ValueError(f"Unsupported HARNESS_FORTRAN_COMPILER: {preference}")
|
||||||
|
return [preference]
|
||||||
|
|
||||||
|
|
||||||
|
def discover_oneapi_env_script(env: dict[str, str] | None = None) -> Path | None:
|
||||||
|
env = env or os.environ
|
||||||
|
configured = env.get("HARNESS_ONEAPI_VARS_BAT")
|
||||||
|
if configured:
|
||||||
|
path = Path(configured)
|
||||||
|
return path if path.exists() else None
|
||||||
|
|
||||||
|
for path in ONEAPI_VARS_CANDIDATES:
|
||||||
|
if path.exists():
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_toolchain(env: dict[str, str] | None = None) -> FortranToolchain | None:
|
||||||
|
env = env or os.environ
|
||||||
|
candidates = compiler_candidates(env.get("HARNESS_FORTRAN_COMPILER"))
|
||||||
|
for compiler in candidates:
|
||||||
|
resolved = shutil.which(compiler)
|
||||||
|
if resolved:
|
||||||
|
return FortranToolchain(name=compiler, executable=resolved, env_script=None)
|
||||||
|
|
||||||
|
env_script = discover_oneapi_env_script(env)
|
||||||
|
if env_script is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
compiler = candidates[0]
|
||||||
|
return FortranToolchain(name=compiler, executable=compiler, env_script=env_script)
|
||||||
|
|
||||||
|
|
||||||
|
def shell_join(args: Iterable[str | Path]) -> str:
|
||||||
|
return subprocess.list2cmdline([str(arg) for arg in args])
|
||||||
|
|
||||||
|
|
||||||
|
def quote_path(path: str | Path) -> str:
|
||||||
|
return shell_join([path])
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_command(toolchain: FortranToolchain, args: list[str | Path]) -> str:
|
||||||
|
command = shell_join(args)
|
||||||
|
if toolchain.env_script is None:
|
||||||
|
return command
|
||||||
|
|
||||||
|
env_script = quote_path(toolchain.env_script)
|
||||||
|
return f'cmd /d /s /c "call {env_script} intel64 >nul && {command}"'
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
import tomllib
|
||||||
|
except ModuleNotFoundError: # pragma: no cover
|
||||||
|
import tomli as tomllib
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
AGENTS_ROOT = ROOT / ".codex" / "agents"
|
||||||
|
SKILLS_ROOT = ROOT / ".codex" / "skills"
|
||||||
|
|
||||||
|
DESIGN_DOC = ROOT / "docs" / "ABAQUS_SUBROUTINE_AGENT_DESIGN.md"
|
||||||
|
|
||||||
|
COMMON_SKILL_SECTIONS = (
|
||||||
|
"## Inputs",
|
||||||
|
"## Workflow",
|
||||||
|
"## Output Contract",
|
||||||
|
"## Boundaries",
|
||||||
|
"## Quality Gate",
|
||||||
|
"## Handoff",
|
||||||
|
)
|
||||||
|
|
||||||
|
SKILLS = {
|
||||||
|
"abaqus-subroutine-requirements": (
|
||||||
|
"Subroutine requirements",
|
||||||
|
"ABAQUS-USUB-REQ-<FEATURE>-###",
|
||||||
|
"Requirement Verification Matrix",
|
||||||
|
"UMAT | VUMAT | UEL",
|
||||||
|
"Do not implement Fortran code.",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-research": (
|
||||||
|
"Research evidence",
|
||||||
|
"official Abaqus documentation",
|
||||||
|
"books, papers, and benchmark sources",
|
||||||
|
"Separate verified facts from inference.",
|
||||||
|
"Abaqus User Subroutines Reference Guide",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-formulation": (
|
||||||
|
"Finite element formulation",
|
||||||
|
"stress update",
|
||||||
|
"consistent tangent",
|
||||||
|
"state variables",
|
||||||
|
"Do not design Fortran source layout.",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-numerical-review": (
|
||||||
|
"Numerical review",
|
||||||
|
"finite-difference tangent check",
|
||||||
|
"state variable update",
|
||||||
|
"stability risks",
|
||||||
|
"pass-for-interface-definition",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-interface": (
|
||||||
|
"Abaqus ABI Contract",
|
||||||
|
"UMAT",
|
||||||
|
"VUMAT",
|
||||||
|
"UEL",
|
||||||
|
"DDSDDE",
|
||||||
|
"STATEV",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-test-models": (
|
||||||
|
"TDD test model",
|
||||||
|
"no-Abaqus",
|
||||||
|
"tests/fortran/manifest.json",
|
||||||
|
"references/<feature-id>/<model-id>/",
|
||||||
|
"source hash",
|
||||||
|
"msg/dat/log tail",
|
||||||
|
),
|
||||||
|
"abaqus-fortran-tdd": (
|
||||||
|
"Fortran TDD",
|
||||||
|
"RED -> GREEN -> VERIFY",
|
||||||
|
"python scripts/validate_fortran.py",
|
||||||
|
"Intel oneAPI",
|
||||||
|
"ifx",
|
||||||
|
"ifort",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-validation": (
|
||||||
|
"Subroutine validation",
|
||||||
|
"HARNESS_ABAQUS_VALIDATION=run",
|
||||||
|
"ready-for-comparison",
|
||||||
|
"source hash",
|
||||||
|
"msg/dat/log",
|
||||||
|
"Do not change tolerance policies.",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-physics-sanity": (
|
||||||
|
"Physics sanity",
|
||||||
|
"global equilibrium",
|
||||||
|
"reaction consistency",
|
||||||
|
"stress/strain",
|
||||||
|
"state variable",
|
||||||
|
"energy/residual",
|
||||||
|
),
|
||||||
|
"abaqus-subroutine-readiness": (
|
||||||
|
"Readiness audit",
|
||||||
|
"Gate Evidence Inventory",
|
||||||
|
"Known Limitations",
|
||||||
|
"Validation Evidence",
|
||||||
|
"Do not publish, deploy, package, tag, commit, or externally release anything unless the user explicitly asks.",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
AGENT_SKILL_REFERENCES = {
|
||||||
|
"coordinator-agent.toml": (
|
||||||
|
"abaqus-subroutine-requirements",
|
||||||
|
"abaqus-subroutine-test-models",
|
||||||
|
"abaqus-subroutine-readiness",
|
||||||
|
),
|
||||||
|
"requirement-agent.toml": ("abaqus-subroutine-requirements",),
|
||||||
|
"research-agent.toml": ("abaqus-subroutine-research", "fem-theory-query"),
|
||||||
|
"formulation-agent.toml": ("abaqus-subroutine-formulation", "fem-theory-query"),
|
||||||
|
"numerical-review-agent.toml": (
|
||||||
|
"abaqus-subroutine-numerical-review",
|
||||||
|
"fem-theory-query",
|
||||||
|
),
|
||||||
|
"io-definition-agent.toml": (
|
||||||
|
"abaqus-subroutine-interface",
|
||||||
|
"fem-theory-query",
|
||||||
|
),
|
||||||
|
"reference-model-agent.toml": (
|
||||||
|
"abaqus-subroutine-test-models",
|
||||||
|
"fem-theory-query",
|
||||||
|
),
|
||||||
|
"implementation-planning-agent.toml": (
|
||||||
|
"abaqus-subroutine-formulation",
|
||||||
|
"abaqus-subroutine-test-models",
|
||||||
|
"abaqus-fortran-tdd",
|
||||||
|
"fem-theory-query",
|
||||||
|
),
|
||||||
|
"implementation-agent.toml": ("abaqus-fortran-tdd",),
|
||||||
|
"build-test-executor-agent.toml": (
|
||||||
|
"abaqus-fortran-tdd",
|
||||||
|
"abaqus-subroutine-validation",
|
||||||
|
),
|
||||||
|
"correction-agent.toml": ("abaqus-fortran-tdd",),
|
||||||
|
"reference-verification-agent.toml": (
|
||||||
|
"abaqus-subroutine-validation",
|
||||||
|
"abaqus-subroutine-interface",
|
||||||
|
),
|
||||||
|
"physics-evaluation-agent.toml": (
|
||||||
|
"abaqus-subroutine-physics-sanity",
|
||||||
|
"fem-theory-query",
|
||||||
|
),
|
||||||
|
"release-agent.toml": ("abaqus-subroutine-readiness",),
|
||||||
|
}
|
||||||
|
|
||||||
|
AGENT_REQUIRED_TERMS = {
|
||||||
|
"coordinator-agent.toml": (
|
||||||
|
"1. Subroutine requirements analysis",
|
||||||
|
"2. Research evidence",
|
||||||
|
"3. Finite element formulation",
|
||||||
|
"4. Abaqus subroutine interface",
|
||||||
|
"5. TDD test models",
|
||||||
|
"6. Fortran implementation",
|
||||||
|
"7. Subroutine validation",
|
||||||
|
),
|
||||||
|
"requirement-agent.toml": ("Subroutine requirements analysis", "ABAQUS-USUB-REQ"),
|
||||||
|
"research-agent.toml": ("books, papers, official Abaqus manuals", "source reliability"),
|
||||||
|
"formulation-agent.toml": ("stress update", "consistent tangent", "state variables"),
|
||||||
|
"numerical-review-agent.toml": (
|
||||||
|
"finite-difference tangent check",
|
||||||
|
"algorithmic consistency",
|
||||||
|
),
|
||||||
|
"io-definition-agent.toml": ("Abaqus ABI Contract", "STRESS", "DDSDDE", "STATEV"),
|
||||||
|
"reference-model-agent.toml": (
|
||||||
|
"tests/fortran/manifest.json",
|
||||||
|
"references/<feature-id>/<model-id>/",
|
||||||
|
),
|
||||||
|
"implementation-planning-agent.toml": (
|
||||||
|
"Fortran source",
|
||||||
|
"no-Abaqus driver",
|
||||||
|
"RED -> GREEN -> VERIFY",
|
||||||
|
),
|
||||||
|
"implementation-agent.toml": ("Fortran source", "Intel oneAPI", "RED -> GREEN -> VERIFY"),
|
||||||
|
"build-test-executor-agent.toml": (
|
||||||
|
"python scripts/validate_fortran.py",
|
||||||
|
"HARNESS_ABAQUS_VALIDATION=run",
|
||||||
|
),
|
||||||
|
"correction-agent.toml": ("Fortran compile", "minimal correction"),
|
||||||
|
"reference-verification-agent.toml": (
|
||||||
|
"metadata.json",
|
||||||
|
"source hash",
|
||||||
|
"Abaqus version",
|
||||||
|
"compiler version",
|
||||||
|
),
|
||||||
|
"physics-evaluation-agent.toml": ("global equilibrium", "stress/strain", "state variable"),
|
||||||
|
"release-agent.toml": ("Gate Evidence Inventory", "Known Limitations"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_frontmatter(text):
|
||||||
|
lines = text.splitlines()
|
||||||
|
if not lines or lines[0] != "---":
|
||||||
|
raise AssertionError("SKILL.md must start with YAML frontmatter")
|
||||||
|
|
||||||
|
fields = {}
|
||||||
|
for line in lines[1:]:
|
||||||
|
if line == "---":
|
||||||
|
return fields
|
||||||
|
key, sep, value = line.partition(":")
|
||||||
|
if not sep:
|
||||||
|
raise AssertionError(f"Invalid frontmatter line: {line}")
|
||||||
|
fields[key.strip()] = value.strip()
|
||||||
|
|
||||||
|
raise AssertionError("SKILL.md frontmatter must be closed")
|
||||||
|
|
||||||
|
|
||||||
|
class AbaqusSubroutineCodexConfigTests(unittest.TestCase):
|
||||||
|
def test_abaqus_subroutine_skill_files_exist_with_metadata(self):
|
||||||
|
for skill_name, body_terms in SKILLS.items():
|
||||||
|
with self.subTest(skill=skill_name):
|
||||||
|
skill_path = SKILLS_ROOT / skill_name / "SKILL.md"
|
||||||
|
self.assertTrue(skill_path.exists(), f"{skill_name} SKILL.md is missing")
|
||||||
|
text = skill_path.read_text(encoding="utf-8")
|
||||||
|
fields = parse_frontmatter(text)
|
||||||
|
|
||||||
|
self.assertEqual(set(fields), {"name", "description"})
|
||||||
|
self.assertEqual(fields["name"], skill_name)
|
||||||
|
self.assertIn("Use when", fields["description"])
|
||||||
|
self.assertIn("Abaqus", fields["description"])
|
||||||
|
self.assertIn("User Subroutine", fields["description"])
|
||||||
|
for section in COMMON_SKILL_SECTIONS:
|
||||||
|
self.assertIn(section, text)
|
||||||
|
self.assertIn("AGENTS.md", text)
|
||||||
|
self.assertIn("docs/ABAQUS_SUBROUTINE_AGENT_DESIGN.md", text)
|
||||||
|
for term in body_terms:
|
||||||
|
self.assertIn(term, text)
|
||||||
|
|
||||||
|
def test_abaqus_subroutine_skills_have_ui_metadata(self):
|
||||||
|
for skill_name in SKILLS:
|
||||||
|
with self.subTest(skill=skill_name):
|
||||||
|
metadata = SKILLS_ROOT / skill_name / "agents" / "openai.yaml"
|
||||||
|
self.assertTrue(metadata.exists(), f"{skill_name} openai.yaml is missing")
|
||||||
|
text = metadata.read_text(encoding="utf-8")
|
||||||
|
self.assertIn("interface:", text)
|
||||||
|
self.assertIn("display_name:", text)
|
||||||
|
self.assertIn("short_description:", text)
|
||||||
|
self.assertIn("default_prompt:", text)
|
||||||
|
self.assertIn(f"${skill_name}", text)
|
||||||
|
|
||||||
|
def test_deprecated_fesa_skill_directories_are_removed(self):
|
||||||
|
deprecated = sorted(p.name for p in SKILLS_ROOT.iterdir() if p.name.startswith("fesa-"))
|
||||||
|
self.assertEqual([], deprecated)
|
||||||
|
|
||||||
|
def test_agents_reference_abaqus_subroutine_skills(self):
|
||||||
|
for agent_file, skill_names in AGENT_SKILL_REFERENCES.items():
|
||||||
|
with self.subTest(agent=agent_file):
|
||||||
|
text = (AGENTS_ROOT / agent_file).read_text(encoding="utf-8")
|
||||||
|
data = tomllib.loads(text)
|
||||||
|
self.assertEqual(data["name"], agent_file.removesuffix(".toml"))
|
||||||
|
self.assertEqual(data["model_reasoning_effort"], "extra high")
|
||||||
|
self.assertIn("Abaqus User Subroutine", data["description"])
|
||||||
|
instructions = data["developer_instructions"]
|
||||||
|
self.assertIn("Skill references:", instructions)
|
||||||
|
self.assertIn("Abaqus User Subroutine", instructions)
|
||||||
|
for skill_name in skill_names:
|
||||||
|
self.assertIn(f"${skill_name}", instructions)
|
||||||
|
for term in AGENT_REQUIRED_TERMS[agent_file]:
|
||||||
|
self.assertIn(term, instructions)
|
||||||
|
|
||||||
|
def test_agent_and_skill_text_no_longer_targets_fesa_cpp_solver_work(self):
|
||||||
|
checked_paths = list(AGENTS_ROOT.glob("*.toml"))
|
||||||
|
checked_paths += [SKILLS_ROOT / name / "SKILL.md" for name in SKILLS]
|
||||||
|
checked_paths += list((SKILLS_ROOT / "harness-workflow").glob("SKILL.md"))
|
||||||
|
checked_paths += list((SKILLS_ROOT / "harness-review").glob("SKILL.md"))
|
||||||
|
|
||||||
|
forbidden_terms = (
|
||||||
|
"FESA solver",
|
||||||
|
"FESA FEM",
|
||||||
|
"FESA C++",
|
||||||
|
"C++17/MSVC",
|
||||||
|
"C++/MSVC",
|
||||||
|
"CMake/CTest",
|
||||||
|
)
|
||||||
|
for path in checked_paths:
|
||||||
|
with self.subTest(path=path):
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
for forbidden in forbidden_terms:
|
||||||
|
self.assertNotIn(forbidden, text)
|
||||||
|
|
||||||
|
def test_harness_skills_target_fortran_subroutine_workflow(self):
|
||||||
|
for skill_name in ("harness-workflow", "harness-review"):
|
||||||
|
with self.subTest(skill=skill_name):
|
||||||
|
text = (SKILLS_ROOT / skill_name / "SKILL.md").read_text(encoding="utf-8")
|
||||||
|
for term in (
|
||||||
|
"Abaqus User Subroutine",
|
||||||
|
"Fortran",
|
||||||
|
"python scripts/validate_fortran.py",
|
||||||
|
"python scripts/validate_reference_artifacts.py",
|
||||||
|
"HARNESS_ABAQUS_VALIDATION=run",
|
||||||
|
):
|
||||||
|
self.assertIn(term, text)
|
||||||
|
|
||||||
|
def test_design_doc_captures_user_subroutine_process(self):
|
||||||
|
text = DESIGN_DOC.read_text(encoding="utf-8")
|
||||||
|
for term in (
|
||||||
|
"Abaqus User Subroutine development process",
|
||||||
|
"1. Subroutine requirements analysis",
|
||||||
|
"2. Books, papers, and research evidence",
|
||||||
|
"3. Finite element formulation for implementation",
|
||||||
|
"4. Subroutine input/output parameter definition",
|
||||||
|
"5. TDD test model design",
|
||||||
|
"6. Fortran code implementation",
|
||||||
|
"7. Subroutine validation",
|
||||||
|
):
|
||||||
|
self.assertIn(term, text)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import importlib.util
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
def load_fortran_toolchain():
|
||||||
|
module_path = Path(__file__).resolve().parent / "fortran_toolchain.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("fortran_toolchain", module_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class FortranToolchainTests(unittest.TestCase):
|
||||||
|
def test_auto_prefers_ifx_over_ifort_when_both_are_on_path(self):
|
||||||
|
fortran_toolchain = load_fortran_toolchain()
|
||||||
|
|
||||||
|
def fake_which(name):
|
||||||
|
return f"C:\\oneapi\\{name}.exe" if name in {"ifx", "ifort"} else None
|
||||||
|
|
||||||
|
with patch.object(fortran_toolchain.shutil, "which", side_effect=fake_which):
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
toolchain = fortran_toolchain.resolve_toolchain()
|
||||||
|
|
||||||
|
self.assertEqual(toolchain.name, "ifx")
|
||||||
|
self.assertEqual(toolchain.executable, "C:\\oneapi\\ifx.exe")
|
||||||
|
self.assertIsNone(toolchain.env_script)
|
||||||
|
|
||||||
|
def test_auto_uses_oneapi_env_script_when_compiler_is_not_on_path(self):
|
||||||
|
fortran_toolchain = load_fortran_toolchain()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
vars_bat = Path(tmp) / "setvars.bat"
|
||||||
|
vars_bat.write_text("@echo off\n", encoding="utf-8")
|
||||||
|
|
||||||
|
with patch.object(fortran_toolchain.shutil, "which", return_value=None):
|
||||||
|
with patch.object(fortran_toolchain, "ONEAPI_VARS_CANDIDATES", [vars_bat]):
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
toolchain = fortran_toolchain.resolve_toolchain()
|
||||||
|
|
||||||
|
self.assertEqual(toolchain.name, "ifx")
|
||||||
|
self.assertEqual(toolchain.executable, "ifx")
|
||||||
|
self.assertEqual(toolchain.env_script, vars_bat)
|
||||||
|
|
||||||
|
def test_explicit_compiler_preference_is_honored(self):
|
||||||
|
fortran_toolchain = load_fortran_toolchain()
|
||||||
|
|
||||||
|
def fake_which(name):
|
||||||
|
return f"C:\\oneapi\\{name}.exe"
|
||||||
|
|
||||||
|
with patch.object(fortran_toolchain.shutil, "which", side_effect=fake_which):
|
||||||
|
with patch.dict(os.environ, {"HARNESS_FORTRAN_COMPILER": "ifort"}, clear=True):
|
||||||
|
toolchain = fortran_toolchain.resolve_toolchain()
|
||||||
|
|
||||||
|
self.assertEqual(toolchain.name, "ifort")
|
||||||
|
self.assertEqual(toolchain.executable, "C:\\oneapi\\ifort.exe")
|
||||||
|
|
||||||
|
def test_wrap_command_calls_oneapi_env_before_compiler(self):
|
||||||
|
fortran_toolchain = load_fortran_toolchain()
|
||||||
|
toolchain = fortran_toolchain.FortranToolchain(
|
||||||
|
name="ifx",
|
||||||
|
executable="ifx",
|
||||||
|
env_script=Path(r"C:\Program Files (x86)\Intel\oneAPI\setvars.bat"),
|
||||||
|
)
|
||||||
|
|
||||||
|
command = fortran_toolchain.wrap_command(toolchain, ["ifx", "/nologo", "test.f90"])
|
||||||
|
|
||||||
|
self.assertIn("cmd /d /s /c", command)
|
||||||
|
self.assertIn('call "C:\\Program Files (x86)\\Intel\\oneAPI\\setvars.bat" intel64', command)
|
||||||
|
self.assertIn("ifx /nologo test.f90", command)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import importlib.util
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def load_pre_commit_checks():
|
||||||
|
module_path = Path(__file__).resolve().parent.parent / ".codex" / "hooks" / "pre_commit_checks.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("pre_commit_checks", module_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class PreCommitChecksTests(unittest.TestCase):
|
||||||
|
def test_git_commit_runs_python_self_tests_and_workspace_validation(self):
|
||||||
|
pre_commit_checks = load_pre_commit_checks()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
commands = pre_commit_checks._build_pre_commit_commands(root)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
commands,
|
||||||
|
[
|
||||||
|
[sys.executable, "-m", "unittest", "discover", "-s", "scripts", "-p", "test_*.py"],
|
||||||
|
[sys.executable, "scripts/validate_workspace.py"],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self.assertFalse(any("npm" in part.lower() for command in commands for part in command))
|
||||||
|
|
||||||
|
def test_only_git_commit_commands_trigger_checks(self):
|
||||||
|
pre_commit_checks = load_pre_commit_checks()
|
||||||
|
self.assertTrue(pre_commit_checks._is_git_commit('git commit -m "change"'))
|
||||||
|
self.assertTrue(pre_commit_checks._is_git_commit('git -c core.editor=true commit -m "change"'))
|
||||||
|
self.assertFalse(pre_commit_checks._is_git_commit("git status --short"))
|
||||||
|
self.assertFalse(pre_commit_checks._is_git_commit("echo git commit"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import importlib.util
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def load_tdd_guard():
|
||||||
|
module_path = Path(__file__).resolve().parent.parent / ".codex" / "hooks" / "tdd-guard.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("tdd_guard", module_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class CppTddGuardTests(unittest.TestCase):
|
||||||
|
def test_cpp_production_file_without_related_test_is_blocked(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
source = root / "include" / "fesa" / "Core" / "DofManager.hpp"
|
||||||
|
source.parent.mkdir(parents=True)
|
||||||
|
source.write_text("#pragma once\n", encoding="utf-8")
|
||||||
|
|
||||||
|
self.assertEqual(tdd_guard._guarded_paths([str(source)], root, root), ["DofManager"])
|
||||||
|
|
||||||
|
def test_cpp_production_file_with_module_test_is_allowed(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
source = root / "include" / "fesa" / "Core" / "DofManager.hpp"
|
||||||
|
source.parent.mkdir(parents=True)
|
||||||
|
source.write_text("#pragma once\n", encoding="utf-8")
|
||||||
|
tests_dir = root / "tests"
|
||||||
|
tests_dir.mkdir()
|
||||||
|
(tests_dir / "test_core_module_includes.cpp").write_text("int main() { return 0; }\n", encoding="utf-8")
|
||||||
|
|
||||||
|
self.assertEqual(tdd_guard._guarded_paths([str(source)], root, root), [])
|
||||||
|
|
||||||
|
def test_cpp_production_file_with_basename_test_in_same_patch_is_allowed(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
source = root / "src" / "Math" / "DenseMatrix.cpp"
|
||||||
|
source.parent.mkdir(parents=True)
|
||||||
|
source.write_text("void f() {}\n", encoding="utf-8")
|
||||||
|
test_path = root / "tests" / "test_dense_matrix.cpp"
|
||||||
|
|
||||||
|
self.assertEqual(tdd_guard._guarded_paths([str(source), str(test_path)], root, root), [])
|
||||||
|
|
||||||
|
def test_fortran_subroutine_without_related_test_is_blocked(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
source = root / "src" / "fortran" / "abaqus" / "UMAT.for"
|
||||||
|
source.parent.mkdir(parents=True)
|
||||||
|
source.write_text(" subroutine umat()\n end\n", encoding="utf-8")
|
||||||
|
|
||||||
|
self.assertEqual(tdd_guard._guarded_paths([str(source)], root, root), ["UMAT"])
|
||||||
|
|
||||||
|
def test_fortran_subroutine_with_related_driver_test_is_allowed(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
source = root / "src" / "fortran" / "abaqus" / "UMAT.for"
|
||||||
|
source.parent.mkdir(parents=True)
|
||||||
|
source.write_text(" subroutine umat()\n end\n", encoding="utf-8")
|
||||||
|
test_path = root / "tests" / "fortran" / "test_umat_linear_elastic.f90"
|
||||||
|
|
||||||
|
self.assertEqual(tdd_guard._guarded_paths([str(source), str(test_path)], root, root), [])
|
||||||
|
|
||||||
|
def test_reference_artifacts_are_exempt(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
self.assertEqual(
|
||||||
|
tdd_guard._guarded_paths(
|
||||||
|
[
|
||||||
|
"references/umat/single-element/model.inp",
|
||||||
|
"references/umat/single-element/stresses.csv",
|
||||||
|
"references/umat/single-element/job.msg.tail.txt",
|
||||||
|
"references/umat/single-element/job.dat.tail.txt",
|
||||||
|
"references/umat/single-element/job.log.tail.txt",
|
||||||
|
],
|
||||||
|
root,
|
||||||
|
root,
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_cmake_and_docs_are_exempt(self):
|
||||||
|
tdd_guard = load_tdd_guard()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
self.assertEqual(
|
||||||
|
tdd_guard._guarded_paths(["CMakeLists.txt", "docs/ARCHITECTURE.md", "cmake/toolchain.cmake"], root, root),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def load_validate_fortran():
|
||||||
|
module_path = Path(__file__).resolve().parent / "validate_fortran.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("validate_fortran", module_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class ValidateFortranTests(unittest.TestCase):
|
||||||
|
def test_auto_mode_has_no_commands_when_manifest_is_missing(self):
|
||||||
|
validate_fortran = load_validate_fortran()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
with unittest.mock.patch.dict(os.environ, {}, clear=True):
|
||||||
|
commands = validate_fortran.discover_commands(root)
|
||||||
|
|
||||||
|
self.assertEqual(commands, [])
|
||||||
|
|
||||||
|
def test_off_mode_skips_manifest(self):
|
||||||
|
validate_fortran = load_validate_fortran()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
manifest = root / "tests" / "fortran" / "manifest.json"
|
||||||
|
manifest.parent.mkdir(parents=True)
|
||||||
|
manifest.write_text(json.dumps({"tests": []}), encoding="utf-8")
|
||||||
|
with unittest.mock.patch.dict(os.environ, {"HARNESS_FORTRAN_VALIDATION": "off"}, clear=True):
|
||||||
|
commands = validate_fortran.discover_commands(root)
|
||||||
|
|
||||||
|
self.assertEqual(commands, [])
|
||||||
|
|
||||||
|
def test_manifest_requires_available_compiler(self):
|
||||||
|
validate_fortran = load_validate_fortran()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
manifest = root / "tests" / "fortran" / "manifest.json"
|
||||||
|
manifest.parent.mkdir(parents=True)
|
||||||
|
manifest.write_text(json.dumps({"tests": [{"name": "case", "sources": ["a.f90"]}]}), encoding="utf-8")
|
||||||
|
with unittest.mock.patch.dict(os.environ, {}, clear=True):
|
||||||
|
with unittest.mock.patch.object(validate_fortran, "resolve_toolchain", return_value=None):
|
||||||
|
with self.assertRaises(validate_fortran.FortranValidationError):
|
||||||
|
validate_fortran.discover_commands(root)
|
||||||
|
|
||||||
|
def test_manifest_generates_compile_and_run_commands(self):
|
||||||
|
validate_fortran = load_validate_fortran()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
manifest = root / "tests" / "fortran" / "manifest.json"
|
||||||
|
manifest.parent.mkdir(parents=True)
|
||||||
|
manifest.write_text(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"name": "umat_linear_elastic_kernel",
|
||||||
|
"sources": [
|
||||||
|
"src/fortran/kernels/linear_elastic.f90",
|
||||||
|
"tests/fortran/test_umat_linear_elastic.f90",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
toolchain = validate_fortran.FortranToolchain(name="ifx", executable="ifx", env_script=None)
|
||||||
|
with unittest.mock.patch.dict(os.environ, {}, clear=True):
|
||||||
|
with unittest.mock.patch.object(validate_fortran, "resolve_toolchain", return_value=toolchain):
|
||||||
|
commands = validate_fortran.discover_commands(root)
|
||||||
|
|
||||||
|
self.assertEqual(len(commands), 2)
|
||||||
|
self.assertIn("ifx /nologo", commands[0])
|
||||||
|
self.assertIn("src\\fortran\\kernels\\linear_elastic.f90", commands[0])
|
||||||
|
self.assertIn("/exe:", commands[0])
|
||||||
|
self.assertTrue(commands[1].endswith("umat_linear_elastic_kernel.exe"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import hashlib
|
||||||
|
import importlib.util
|
||||||
|
import json
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def load_validate_reference_artifacts():
|
||||||
|
module_path = Path(__file__).resolve().parent / "validate_reference_artifacts.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("validate_reference_artifacts", module_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
def write_json(path: Path, payload: dict):
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
class ValidateReferenceArtifactsTests(unittest.TestCase):
|
||||||
|
def test_missing_references_directory_is_valid(self):
|
||||||
|
validator = load_validate_reference_artifacts()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
self.assertEqual(validator.validate_root(Path(tmp)), [])
|
||||||
|
|
||||||
|
def test_draft_metadata_with_minimal_provenance_is_valid(self):
|
||||||
|
validator = load_validate_reference_artifacts()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
write_json(
|
||||||
|
root / "references" / "umat" / "single-element" / "metadata.json",
|
||||||
|
{
|
||||||
|
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||||
|
"feature_id": "umat",
|
||||||
|
"model_id": "single-element",
|
||||||
|
"artifact_status": "draft",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(validator.validate_root(root), [])
|
||||||
|
|
||||||
|
def test_ready_for_comparison_requires_declared_files(self):
|
||||||
|
validator = load_validate_reference_artifacts()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
write_json(
|
||||||
|
root / "references" / "umat" / "single-element" / "metadata.json",
|
||||||
|
{
|
||||||
|
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||||
|
"feature_id": "umat",
|
||||||
|
"model_id": "single-element",
|
||||||
|
"artifact_status": "ready-for-comparison",
|
||||||
|
"abaqus": {"version": "2024", "precision": "double", "command": "abaqus job=case user=UMAT.for"},
|
||||||
|
"compiler": {"vendor": "Intel oneAPI", "name": "ifx", "version": "2024"},
|
||||||
|
"subroutine": {
|
||||||
|
"entry_points": ["UMAT"],
|
||||||
|
"source_files": [{"path": "src/fortran/abaqus/UMAT.for", "language": "Fortran", "sha256": "abc"}],
|
||||||
|
},
|
||||||
|
"input_file": "model.inp",
|
||||||
|
"outputs": {
|
||||||
|
"tails": {"msg": "job.msg.tail.txt", "dat": "job.dat.tail.txt", "log": "job.log.tail.txt"},
|
||||||
|
"csv": {"stresses": "stresses.csv"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
errors = validator.validate_root(root)
|
||||||
|
|
||||||
|
self.assertTrue(any("missing input_file" in error for error in errors))
|
||||||
|
self.assertTrue(any("missing output tail" in error for error in errors))
|
||||||
|
self.assertTrue(any("missing csv output" in error for error in errors))
|
||||||
|
self.assertTrue(any("missing source file" in error for error in errors))
|
||||||
|
|
||||||
|
def test_ready_for_comparison_checks_source_sha256(self):
|
||||||
|
validator = load_validate_reference_artifacts()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
source = root / "src" / "fortran" / "abaqus" / "UMAT.for"
|
||||||
|
source.parent.mkdir(parents=True)
|
||||||
|
source.write_text(" subroutine umat()\n end\n", encoding="utf-8")
|
||||||
|
source_hash = hashlib.sha256(source.read_bytes()).hexdigest()
|
||||||
|
model_dir = root / "references" / "umat" / "single-element"
|
||||||
|
for name in ["model.inp", "job.msg.tail.txt", "job.dat.tail.txt", "job.log.tail.txt", "stresses.csv"]:
|
||||||
|
(model_dir / name).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
(model_dir / name).write_text("ok\n", encoding="utf-8")
|
||||||
|
write_json(
|
||||||
|
model_dir / "metadata.json",
|
||||||
|
{
|
||||||
|
"schema_version": "abaqus-user-subroutine-artifact-v1",
|
||||||
|
"feature_id": "umat",
|
||||||
|
"model_id": "single-element",
|
||||||
|
"artifact_status": "ready-for-comparison",
|
||||||
|
"abaqus": {"version": "2024", "precision": "double", "command": "abaqus job=case user=UMAT.for"},
|
||||||
|
"compiler": {"vendor": "Intel oneAPI", "name": "ifx", "version": "2024"},
|
||||||
|
"subroutine": {
|
||||||
|
"entry_points": ["UMAT"],
|
||||||
|
"source_files": [
|
||||||
|
{
|
||||||
|
"path": "src/fortran/abaqus/UMAT.for",
|
||||||
|
"language": "Fortran",
|
||||||
|
"sha256": "0" * len(source_hash),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"input_file": "model.inp",
|
||||||
|
"outputs": {
|
||||||
|
"tails": {"msg": "job.msg.tail.txt", "dat": "job.dat.tail.txt", "log": "job.log.tail.txt"},
|
||||||
|
"csv": {"stresses": "stresses.csv"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
errors = validator.validate_root(root)
|
||||||
|
|
||||||
|
self.assertTrue(any("sha256 mismatch" in error for error in errors))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
import importlib.util
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from contextlib import redirect_stderr, redirect_stdout
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
def load_validate_workspace():
|
||||||
|
module_path = Path(__file__).resolve().parent / "validate_workspace.py"
|
||||||
|
spec = importlib.util.spec_from_file_location("validate_workspace", module_path)
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
|
class ValidateWorkspaceTests(unittest.TestCase):
|
||||||
|
def _script_command(self, validate_workspace, script_name: str) -> str:
|
||||||
|
return validate_workspace.python_script_command(script_name)
|
||||||
|
|
||||||
|
def test_env_commands_override_cmake_detection(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
(root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8")
|
||||||
|
with patch.dict(os.environ, {"HARNESS_VALIDATION_COMMANDS": "echo first\n echo second \n"}, clear=True):
|
||||||
|
self.assertEqual(validate_workspace.discover_commands(root), ["echo first", "echo second"])
|
||||||
|
|
||||||
|
def test_env_commands_override_abaqus_validation_config_in_main(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
env = {
|
||||||
|
"HARNESS_VALIDATION_COMMANDS": "echo override",
|
||||||
|
"HARNESS_ABAQUS_VALIDATION": "run",
|
||||||
|
}
|
||||||
|
with patch.dict(os.environ, env, clear=True):
|
||||||
|
with patch.object(
|
||||||
|
validate_workspace,
|
||||||
|
"run_command",
|
||||||
|
return_value=subprocess.CompletedProcess("echo override", 0, "", ""),
|
||||||
|
):
|
||||||
|
with redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()):
|
||||||
|
self.assertEqual(validate_workspace.main(), 0)
|
||||||
|
|
||||||
|
def test_msvc_debug_cmake_commands_are_default_for_cmake_project(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
(root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8")
|
||||||
|
build_dir = root / "build" / "msvc-debug"
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
self.assertEqual(
|
||||||
|
validate_workspace.discover_commands(root),
|
||||||
|
[
|
||||||
|
self._script_command(validate_workspace, "validate_reference_artifacts.py"),
|
||||||
|
self._script_command(validate_workspace, "validate_fortran.py"),
|
||||||
|
f'cmake -S "{root}" -B "{build_dir}" -G "Visual Studio 17 2022" -A x64',
|
||||||
|
f'cmake --build "{build_dir}" --config Debug',
|
||||||
|
f'ctest --test-dir "{build_dir}" --output-on-failure -C Debug',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_msvc_debug_configure_preset_is_preferred_when_present(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
(root / "CMakeLists.txt").write_text("cmake_minimum_required(VERSION 3.20)\n", encoding="utf-8")
|
||||||
|
(root / "CMakePresets.json").write_text(
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "msvc-debug",
|
||||||
|
"generator": "Visual Studio 17 2022",
|
||||||
|
"binaryDir": "${sourceDir}/out/msvc-debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
self.assertEqual(
|
||||||
|
validate_workspace.discover_commands(root),
|
||||||
|
[
|
||||||
|
self._script_command(validate_workspace, "validate_reference_artifacts.py"),
|
||||||
|
self._script_command(validate_workspace, "validate_fortran.py"),
|
||||||
|
"cmake --preset msvc-debug",
|
||||||
|
f'cmake --build "{root / "out" / "msvc-debug"}" --config Debug',
|
||||||
|
f'ctest --test-dir "{root / "out" / "msvc-debug"}" --output-on-failure -C Debug',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_no_cmake_project_has_no_validation_commands(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
root = Path(tmp)
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
self.assertEqual(
|
||||||
|
validate_workspace.discover_commands(root),
|
||||||
|
[
|
||||||
|
self._script_command(validate_workspace, "validate_reference_artifacts.py"),
|
||||||
|
self._script_command(validate_workspace, "validate_fortran.py"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_abaqus_detect_mode_reports_without_running_jobs(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with patch.dict(os.environ, {"HARNESS_ABAQUS_VALIDATION": "detect"}, clear=True):
|
||||||
|
validation = validate_workspace.discover_abaqus_validation(which=lambda _name: None)
|
||||||
|
|
||||||
|
self.assertEqual(validation.mode, "detect")
|
||||||
|
self.assertEqual(validation.commands, [])
|
||||||
|
self.assertFalse(validation.required)
|
||||||
|
|
||||||
|
def test_abaqus_run_mode_requires_executable_and_commands(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with patch.dict(os.environ, {"HARNESS_ABAQUS_VALIDATION": "run"}, clear=True):
|
||||||
|
with self.assertRaises(validate_workspace.ValidationConfigError):
|
||||||
|
validate_workspace.discover_abaqus_validation(which=lambda _name: None)
|
||||||
|
|
||||||
|
def test_abaqus_run_mode_replaces_abaqus_token(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
env = {
|
||||||
|
"HARNESS_ABAQUS_VALIDATION": "run",
|
||||||
|
"HARNESS_ABAQUS_VALIDATION_COMMANDS": "{abaqus} job=case user=UMAT.for",
|
||||||
|
"HARNESS_ABAQUS_USE_ONEAPI_ENV": "off",
|
||||||
|
}
|
||||||
|
with patch.dict(os.environ, env, clear=True):
|
||||||
|
validation = validate_workspace.discover_abaqus_validation(which=lambda _name: r"C:\SIMULIA\abaqus.bat")
|
||||||
|
|
||||||
|
self.assertTrue(validation.required)
|
||||||
|
self.assertEqual(validation.commands, [r"C:\SIMULIA\abaqus.bat job=case user=UMAT.for"])
|
||||||
|
|
||||||
|
def test_common_cmake_install_path_is_prepended_when_cmake_is_not_on_path(self):
|
||||||
|
validate_workspace = load_validate_workspace()
|
||||||
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
|
common_bin = Path(tmp) / "CMake" / "bin"
|
||||||
|
common_bin.mkdir(parents=True)
|
||||||
|
(common_bin / "cmake.exe").write_text("", encoding="utf-8")
|
||||||
|
(common_bin / "ctest.exe").write_text("", encoding="utf-8")
|
||||||
|
with patch.object(validate_workspace, "COMMON_CMAKE_BIN", common_bin):
|
||||||
|
with patch.object(validate_workspace.shutil, "which", return_value=None):
|
||||||
|
env = validate_workspace.validation_environment({"PATH": "C:\\Windows\\System32"})
|
||||||
|
|
||||||
|
self.assertTrue(env["PATH"].startswith(str(common_bin)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run no-Abaqus Intel Fortran manifest tests."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
from fortran_toolchain import FortranToolchain, resolve_toolchain, wrap_command
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from scripts.fortran_toolchain import FortranToolchain, resolve_toolchain, wrap_command
|
||||||
|
|
||||||
|
|
||||||
|
MANIFEST_PATH = Path("tests/fortran/manifest.json")
|
||||||
|
BUILD_ROOT = Path("build/fortran-tests")
|
||||||
|
VALIDATION_MODES = {"off", "detect", "auto", "compile"}
|
||||||
|
|
||||||
|
|
||||||
|
class FortranValidationError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def validation_mode(env: dict[str, str] | None = None) -> str:
|
||||||
|
env = env or os.environ
|
||||||
|
mode = env.get("HARNESS_FORTRAN_VALIDATION", "auto").lower()
|
||||||
|
if mode not in VALIDATION_MODES:
|
||||||
|
raise FortranValidationError(f"Unsupported HARNESS_FORTRAN_VALIDATION: {mode}")
|
||||||
|
return mode
|
||||||
|
|
||||||
|
|
||||||
|
def load_manifest(root: Path) -> dict | None:
|
||||||
|
manifest = root / MANIFEST_PATH
|
||||||
|
if not manifest.exists():
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
payload = json.loads(manifest.read_text(encoding="utf-8"))
|
||||||
|
except json.JSONDecodeError as exc:
|
||||||
|
raise FortranValidationError(f"Invalid Fortran manifest JSON: {manifest}: {exc}") from exc
|
||||||
|
if not isinstance(payload, dict) or not isinstance(payload.get("tests", []), list):
|
||||||
|
raise FortranValidationError(f"Fortran manifest must contain a tests array: {manifest}")
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_test_record(record: dict) -> tuple[str, list[str]]:
|
||||||
|
if not isinstance(record, dict):
|
||||||
|
raise FortranValidationError("Fortran manifest test record must be an object.")
|
||||||
|
name = record.get("name")
|
||||||
|
sources = record.get("sources")
|
||||||
|
if not isinstance(name, str) or not name:
|
||||||
|
raise FortranValidationError("Fortran manifest test record is missing name.")
|
||||||
|
if not isinstance(sources, list) or not all(isinstance(source, str) and source for source in sources):
|
||||||
|
raise FortranValidationError(f"Fortran manifest test {name} must define source paths.")
|
||||||
|
return name, sources
|
||||||
|
|
||||||
|
|
||||||
|
def build_test_commands(root: Path, manifest: dict, toolchain: FortranToolchain) -> list[str]:
|
||||||
|
commands: list[str] = []
|
||||||
|
for record in manifest.get("tests", []):
|
||||||
|
name, sources = _validate_test_record(record)
|
||||||
|
build_dir = root / BUILD_ROOT / name
|
||||||
|
exe_path = build_dir / f"{name}.exe"
|
||||||
|
source_paths = [root / source for source in sources]
|
||||||
|
compile_args: list[str | Path] = [
|
||||||
|
toolchain.executable,
|
||||||
|
"/nologo",
|
||||||
|
*source_paths,
|
||||||
|
f"/exe:{exe_path}",
|
||||||
|
]
|
||||||
|
commands.append(wrap_command(toolchain, compile_args))
|
||||||
|
commands.append(str(exe_path))
|
||||||
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
def discover_commands(root: Path, env: dict[str, str] | None = None) -> list[str]:
|
||||||
|
env = env or os.environ
|
||||||
|
mode = validation_mode(env)
|
||||||
|
if mode == "off":
|
||||||
|
return []
|
||||||
|
|
||||||
|
manifest = load_manifest(root)
|
||||||
|
if manifest is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
toolchain = resolve_toolchain(env)
|
||||||
|
if toolchain is None:
|
||||||
|
raise FortranValidationError("Fortran validation manifest exists, but no Intel oneAPI Fortran compiler was found.")
|
||||||
|
|
||||||
|
if mode == "detect":
|
||||||
|
return []
|
||||||
|
return build_test_commands(root, manifest, toolchain)
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command: str, root: Path) -> subprocess.CompletedProcess:
|
||||||
|
return subprocess.run(command, cwd=root, shell=True, capture_output=True, text=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
root = Path(__file__).resolve().parent.parent
|
||||||
|
try:
|
||||||
|
commands = discover_commands(root)
|
||||||
|
except FortranValidationError as exc:
|
||||||
|
print(f"Fortran validation failed: {exc}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
if not commands:
|
||||||
|
print("No Fortran validation commands configured.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
for command in commands:
|
||||||
|
print(f"$ {command}")
|
||||||
|
result = run_command(command, root)
|
||||||
|
if result.stdout.strip():
|
||||||
|
print("[stdout]")
|
||||||
|
print(result.stdout.strip())
|
||||||
|
if result.stderr.strip():
|
||||||
|
print("[stderr]", file=sys.stderr)
|
||||||
|
print(result.stderr.strip(), file=sys.stderr)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"Fortran validation failed: {command}", file=sys.stderr)
|
||||||
|
return result.returncode
|
||||||
|
|
||||||
|
print("Fortran validation succeeded.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Validate stored Abaqus user-subroutine reference artifact metadata."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
SCHEMA_VERSION = "abaqus-user-subroutine-artifact-v1"
|
||||||
|
VALID_STATUSES = {"draft", "needs-reference-artifacts", "ready-for-comparison", "blocked"}
|
||||||
|
READY_STATUS = "ready-for-comparison"
|
||||||
|
|
||||||
|
|
||||||
|
def sha256_file(path: Path) -> str:
|
||||||
|
digest = hashlib.sha256()
|
||||||
|
with path.open("rb") as handle:
|
||||||
|
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
||||||
|
digest.update(chunk)
|
||||||
|
return digest.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def _nested(payload: dict, *keys: str):
|
||||||
|
current = payload
|
||||||
|
for key in keys:
|
||||||
|
if not isinstance(current, dict) or key not in current:
|
||||||
|
return None
|
||||||
|
current = current[key]
|
||||||
|
return current
|
||||||
|
|
||||||
|
|
||||||
|
def _load_metadata(path: Path) -> tuple[dict | None, list[str]]:
|
||||||
|
try:
|
||||||
|
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
except json.JSONDecodeError as exc:
|
||||||
|
return None, [f"{path}: invalid JSON: {exc}"]
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
return None, [f"{path}: metadata must be a JSON object"]
|
||||||
|
return payload, []
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_basic(path: Path, payload: dict) -> list[str]:
|
||||||
|
errors: list[str] = []
|
||||||
|
for key in ("schema_version", "feature_id", "model_id", "artifact_status"):
|
||||||
|
if not payload.get(key):
|
||||||
|
errors.append(f"{path}: missing required key {key}")
|
||||||
|
|
||||||
|
if payload.get("schema_version") and payload.get("schema_version") != SCHEMA_VERSION:
|
||||||
|
errors.append(f"{path}: unsupported schema_version {payload.get('schema_version')}")
|
||||||
|
|
||||||
|
status = payload.get("artifact_status")
|
||||||
|
if status and status not in VALID_STATUSES:
|
||||||
|
errors.append(f"{path}: unsupported artifact_status {status}")
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def _require_ready_key(path: Path, payload: dict, *keys: str) -> list[str]:
|
||||||
|
value = _nested(payload, *keys)
|
||||||
|
dotted = ".".join(keys)
|
||||||
|
if value is None or value == "":
|
||||||
|
return [f"{path}: missing ready-for-comparison key {dotted}"]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_ready_files(path: Path, root: Path, payload: dict) -> list[str]:
|
||||||
|
errors: list[str] = []
|
||||||
|
model_dir = path.parent
|
||||||
|
|
||||||
|
for keys in (
|
||||||
|
("abaqus", "version"),
|
||||||
|
("abaqus", "precision"),
|
||||||
|
("abaqus", "command"),
|
||||||
|
("compiler", "vendor"),
|
||||||
|
("compiler", "name"),
|
||||||
|
("compiler", "version"),
|
||||||
|
("subroutine", "entry_points"),
|
||||||
|
("subroutine", "source_files"),
|
||||||
|
("input_file",),
|
||||||
|
("outputs", "tails"),
|
||||||
|
("outputs", "csv"),
|
||||||
|
):
|
||||||
|
errors.extend(_require_ready_key(path, payload, *keys))
|
||||||
|
|
||||||
|
input_file = payload.get("input_file")
|
||||||
|
if isinstance(input_file, str) and not (model_dir / input_file).exists():
|
||||||
|
errors.append(f"{path}: missing input_file {input_file}")
|
||||||
|
|
||||||
|
tails = _nested(payload, "outputs", "tails")
|
||||||
|
if isinstance(tails, dict):
|
||||||
|
for key in ("msg", "dat", "log"):
|
||||||
|
tail_path = tails.get(key)
|
||||||
|
if not isinstance(tail_path, str) or not tail_path:
|
||||||
|
errors.append(f"{path}: missing output tail {key}")
|
||||||
|
elif not (model_dir / tail_path).exists():
|
||||||
|
errors.append(f"{path}: missing output tail {key}: {tail_path}")
|
||||||
|
|
||||||
|
csv_outputs = _nested(payload, "outputs", "csv")
|
||||||
|
if isinstance(csv_outputs, dict):
|
||||||
|
if not csv_outputs:
|
||||||
|
errors.append(f"{path}: missing csv output declaration")
|
||||||
|
for key, csv_path in csv_outputs.items():
|
||||||
|
if not isinstance(csv_path, str) or not csv_path:
|
||||||
|
errors.append(f"{path}: missing csv output {key}")
|
||||||
|
elif not (model_dir / csv_path).exists():
|
||||||
|
errors.append(f"{path}: missing csv output {key}: {csv_path}")
|
||||||
|
|
||||||
|
source_files = _nested(payload, "subroutine", "source_files")
|
||||||
|
if isinstance(source_files, list):
|
||||||
|
if not source_files:
|
||||||
|
errors.append(f"{path}: missing source file declaration")
|
||||||
|
for item in source_files:
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
errors.append(f"{path}: source_files entries must be objects")
|
||||||
|
continue
|
||||||
|
source_path_text = item.get("path")
|
||||||
|
expected_hash = item.get("sha256")
|
||||||
|
if not isinstance(source_path_text, str) or not source_path_text:
|
||||||
|
errors.append(f"{path}: missing source file path")
|
||||||
|
continue
|
||||||
|
source_path = Path(source_path_text)
|
||||||
|
if not source_path.is_absolute():
|
||||||
|
source_path = root / source_path
|
||||||
|
if not source_path.exists():
|
||||||
|
errors.append(f"{path}: missing source file {source_path_text}")
|
||||||
|
continue
|
||||||
|
actual_hash = sha256_file(source_path)
|
||||||
|
if expected_hash != actual_hash:
|
||||||
|
errors.append(f"{path}: sha256 mismatch for {source_path_text}")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_metadata(path: Path, root: Path) -> list[str]:
|
||||||
|
payload, errors = _load_metadata(path)
|
||||||
|
if payload is None:
|
||||||
|
return errors
|
||||||
|
|
||||||
|
errors.extend(_validate_basic(path, payload))
|
||||||
|
if errors:
|
||||||
|
return errors
|
||||||
|
|
||||||
|
if payload.get("artifact_status") == READY_STATUS:
|
||||||
|
errors.extend(_validate_ready_files(path, root, payload))
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def validate_root(root: Path) -> list[str]:
|
||||||
|
references_dir = root / "references"
|
||||||
|
if not references_dir.exists():
|
||||||
|
return []
|
||||||
|
|
||||||
|
errors: list[str] = []
|
||||||
|
for metadata in sorted(references_dir.rglob("metadata.json")):
|
||||||
|
errors.extend(validate_metadata(metadata, root))
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
root = Path(__file__).resolve().parent.parent
|
||||||
|
errors = validate_root(root)
|
||||||
|
if not errors:
|
||||||
|
print("Reference artifact metadata validation succeeded.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
print("Reference artifact metadata validation failed:", file=sys.stderr)
|
||||||
|
for error in errors:
|
||||||
|
print(f"- {error}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run C++/MSVC Harness validation commands."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_GENERATOR = "Visual Studio 17 2022"
|
||||||
|
DEFAULT_PLATFORM = "x64"
|
||||||
|
DEFAULT_CONFIG = "Debug"
|
||||||
|
DEFAULT_BUILD_DIR = "build/msvc-debug"
|
||||||
|
PRESET_NAME = "msvc-debug"
|
||||||
|
COMMON_CMAKE_BIN = Path(r"C:\Program Files\CMake\bin")
|
||||||
|
ABAQUS_VALIDATION_MODES = {"off", "detect", "run"}
|
||||||
|
|
||||||
|
|
||||||
|
class ValidationConfigError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AbaqusValidation:
|
||||||
|
def __init__(self, *, mode: str, executable: str | None, commands: list[str], required: bool):
|
||||||
|
self.mode = mode
|
||||||
|
self.executable = executable
|
||||||
|
self.commands = commands
|
||||||
|
self.required = required
|
||||||
|
|
||||||
|
|
||||||
|
def load_env_commands() -> list[str]:
|
||||||
|
raw = os.environ.get("HARNESS_VALIDATION_COMMANDS", "")
|
||||||
|
return [line.strip() for line in raw.splitlines() if line.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def _load_multiline_env(name: str) -> list[str]:
|
||||||
|
raw = os.environ.get(name, "")
|
||||||
|
return [line.strip() for line in raw.splitlines() if line.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def python_script_command(script_name: str) -> str:
|
||||||
|
return subprocess.list2cmdline([sys.executable, str(Path("scripts") / script_name)])
|
||||||
|
|
||||||
|
|
||||||
|
def _cmake_config() -> tuple[str, str, str, Path]:
|
||||||
|
generator = os.environ.get("HARNESS_CMAKE_GENERATOR", DEFAULT_GENERATOR)
|
||||||
|
platform = os.environ.get("HARNESS_CMAKE_PLATFORM", DEFAULT_PLATFORM)
|
||||||
|
config = os.environ.get("HARNESS_CMAKE_CONFIG", DEFAULT_CONFIG)
|
||||||
|
build_dir = Path(os.environ.get("HARNESS_BUILD_DIR", DEFAULT_BUILD_DIR))
|
||||||
|
return generator, platform, config, build_dir
|
||||||
|
|
||||||
|
|
||||||
|
def _read_presets(root: Path) -> dict:
|
||||||
|
presets_file = root / "CMakePresets.json"
|
||||||
|
if not presets_file.exists():
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
return json.loads(presets_file.read_text(encoding="utf-8"))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def _preset_binary_dir(root: Path, preset: dict) -> Path:
|
||||||
|
binary_dir = str(preset.get("binaryDir") or DEFAULT_BUILD_DIR)
|
||||||
|
binary_dir = binary_dir.replace("${sourceDir}", str(root))
|
||||||
|
binary_dir = binary_dir.replace("$sourceDir", str(root))
|
||||||
|
path = Path(binary_dir)
|
||||||
|
return path if path.is_absolute() else root / path
|
||||||
|
|
||||||
|
|
||||||
|
def load_preset_commands(root: Path) -> list[str]:
|
||||||
|
payload = _read_presets(root)
|
||||||
|
config = os.environ.get("HARNESS_CMAKE_CONFIG", DEFAULT_CONFIG)
|
||||||
|
for preset in payload.get("configurePresets", []):
|
||||||
|
if isinstance(preset, dict) and preset.get("name") == PRESET_NAME:
|
||||||
|
build_dir = _preset_binary_dir(root, preset)
|
||||||
|
return [
|
||||||
|
f"cmake --preset {PRESET_NAME}",
|
||||||
|
f'cmake --build "{build_dir}" --config {config}',
|
||||||
|
f'ctest --test-dir "{build_dir}" --output-on-failure -C {config}',
|
||||||
|
]
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def load_cmake_commands(root: Path) -> list[str]:
|
||||||
|
if not (root / "CMakeLists.txt").exists():
|
||||||
|
return []
|
||||||
|
|
||||||
|
generator, platform, config, build_dir = _cmake_config()
|
||||||
|
if not build_dir.is_absolute():
|
||||||
|
build_dir = root / build_dir
|
||||||
|
return [
|
||||||
|
f'cmake -S "{root}" -B "{build_dir}" -G "{generator}" -A {platform}',
|
||||||
|
f'cmake --build "{build_dir}" --config {config}',
|
||||||
|
f'ctest --test-dir "{build_dir}" --output-on-failure -C {config}',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def load_harness_commands(root: Path) -> list[str]:
|
||||||
|
return [
|
||||||
|
python_script_command("validate_reference_artifacts.py"),
|
||||||
|
python_script_command("validate_fortran.py"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _quote(value: str | Path) -> str:
|
||||||
|
return subprocess.list2cmdline([str(value)])
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_executable(command: str, which=shutil.which) -> str | None:
|
||||||
|
path = Path(command)
|
||||||
|
if path.exists():
|
||||||
|
return str(path)
|
||||||
|
return which(command)
|
||||||
|
|
||||||
|
|
||||||
|
def _discover_oneapi_env_script() -> Path | None:
|
||||||
|
configured = os.environ.get("HARNESS_ONEAPI_VARS_BAT")
|
||||||
|
if configured:
|
||||||
|
path = Path(configured)
|
||||||
|
return path if path.exists() else None
|
||||||
|
for candidate in (
|
||||||
|
Path(r"C:\Program Files (x86)\Intel\oneAPI\compiler\latest\env\vars.bat"),
|
||||||
|
Path(r"C:\Program Files\Intel\oneAPI\compiler\latest\env\vars.bat"),
|
||||||
|
Path(r"C:\Program Files (x86)\Intel\oneAPI\setvars.bat"),
|
||||||
|
Path(r"C:\Program Files\Intel\oneAPI\setvars.bat"),
|
||||||
|
):
|
||||||
|
if candidate.exists():
|
||||||
|
return candidate
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _maybe_wrap_oneapi(command: str) -> str:
|
||||||
|
mode = os.environ.get("HARNESS_ABAQUS_USE_ONEAPI_ENV", "auto").lower()
|
||||||
|
if mode not in {"auto", "on", "off"}:
|
||||||
|
raise ValidationConfigError(f"Unsupported HARNESS_ABAQUS_USE_ONEAPI_ENV: {mode}")
|
||||||
|
if mode == "off":
|
||||||
|
return command
|
||||||
|
|
||||||
|
env_script = _discover_oneapi_env_script()
|
||||||
|
if env_script is None:
|
||||||
|
if mode == "on":
|
||||||
|
raise ValidationConfigError("HARNESS_ABAQUS_USE_ONEAPI_ENV=on but no oneAPI vars.bat was found.")
|
||||||
|
return command
|
||||||
|
|
||||||
|
return f'cmd /d /s /c "call {_quote(env_script)} intel64 >nul && {command}"'
|
||||||
|
|
||||||
|
|
||||||
|
def discover_abaqus_validation(which=shutil.which) -> AbaqusValidation:
|
||||||
|
mode = os.environ.get("HARNESS_ABAQUS_VALIDATION", "off").lower()
|
||||||
|
if mode not in ABAQUS_VALIDATION_MODES:
|
||||||
|
raise ValidationConfigError(f"Unsupported HARNESS_ABAQUS_VALIDATION: {mode}")
|
||||||
|
if mode == "off":
|
||||||
|
return AbaqusValidation(mode=mode, executable=None, commands=[], required=False)
|
||||||
|
|
||||||
|
command_name = os.environ.get("HARNESS_ABAQUS_COMMAND", "abaqus")
|
||||||
|
executable = _resolve_executable(command_name, which=which)
|
||||||
|
if mode == "detect":
|
||||||
|
return AbaqusValidation(mode=mode, executable=executable, commands=[], required=False)
|
||||||
|
|
||||||
|
if executable is None:
|
||||||
|
raise ValidationConfigError(f"Abaqus executable not found: {command_name}")
|
||||||
|
|
||||||
|
commands = _load_multiline_env("HARNESS_ABAQUS_VALIDATION_COMMANDS")
|
||||||
|
if not commands:
|
||||||
|
raise ValidationConfigError("HARNESS_ABAQUS_VALIDATION=run requires HARNESS_ABAQUS_VALIDATION_COMMANDS.")
|
||||||
|
|
||||||
|
quoted_executable = _quote(executable)
|
||||||
|
resolved_commands = [_maybe_wrap_oneapi(command.replace("{abaqus}", quoted_executable)) for command in commands]
|
||||||
|
return AbaqusValidation(mode=mode, executable=executable, commands=resolved_commands, required=True)
|
||||||
|
|
||||||
|
|
||||||
|
def discover_commands(root: Path) -> list[str]:
|
||||||
|
env_commands = load_env_commands()
|
||||||
|
if env_commands:
|
||||||
|
return env_commands
|
||||||
|
|
||||||
|
commands = load_harness_commands(root)
|
||||||
|
preset_commands = load_preset_commands(root)
|
||||||
|
if preset_commands:
|
||||||
|
commands.extend(preset_commands)
|
||||||
|
else:
|
||||||
|
commands.extend(load_cmake_commands(root))
|
||||||
|
|
||||||
|
commands.extend(discover_abaqus_validation().commands)
|
||||||
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command: str, root: Path) -> subprocess.CompletedProcess:
|
||||||
|
return subprocess.run(
|
||||||
|
command,
|
||||||
|
cwd=root,
|
||||||
|
shell=True,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
env=validation_environment(os.environ),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validation_environment(base_env: os._Environ | dict[str, str]) -> dict[str, str]:
|
||||||
|
env = dict(base_env)
|
||||||
|
if shutil.which("cmake") is not None:
|
||||||
|
return env
|
||||||
|
cmake_exe = COMMON_CMAKE_BIN / "cmake.exe"
|
||||||
|
if not cmake_exe.exists():
|
||||||
|
return env
|
||||||
|
|
||||||
|
current_path = env.get("PATH", "")
|
||||||
|
paths = [part for part in current_path.split(os.pathsep) if part]
|
||||||
|
common_bin_text = str(COMMON_CMAKE_BIN)
|
||||||
|
if not any(part.lower() == common_bin_text.lower() for part in paths):
|
||||||
|
env["PATH"] = common_bin_text + (os.pathsep + current_path if current_path else "")
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def emit_stream(prefix: str, content: str, *, stream) -> None:
|
||||||
|
text = (content or "").strip()
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
print(prefix, file=stream)
|
||||||
|
print(text, file=stream)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
root = Path(__file__).resolve().parent.parent
|
||||||
|
try:
|
||||||
|
commands = discover_commands(root)
|
||||||
|
abaqus_validation = (
|
||||||
|
AbaqusValidation(mode="off", executable=None, commands=[], required=False)
|
||||||
|
if load_env_commands()
|
||||||
|
else discover_abaqus_validation()
|
||||||
|
)
|
||||||
|
except ValidationConfigError as exc:
|
||||||
|
print(f"Validation configuration failed: {exc}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
if abaqus_validation.mode == "detect":
|
||||||
|
if abaqus_validation.executable:
|
||||||
|
print(f"Abaqus executable detected: {abaqus_validation.executable}")
|
||||||
|
else:
|
||||||
|
print("Abaqus executable not detected.")
|
||||||
|
|
||||||
|
if not commands:
|
||||||
|
print("No validation commands configured.")
|
||||||
|
print("Add CMakeLists.txt or set HARNESS_VALIDATION_COMMANDS.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
for command in commands:
|
||||||
|
print(f"$ {command}")
|
||||||
|
result = run_command(command, root)
|
||||||
|
emit_stream("[stdout]", result.stdout, stream=sys.stdout)
|
||||||
|
emit_stream("[stderr]", result.stderr, stream=sys.stderr)
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"Validation failed: {command}", file=sys.stderr)
|
||||||
|
return result.returncode
|
||||||
|
|
||||||
|
print("Validation succeeded.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user