This commit is contained in:
김경종
2026-06-10 10:03:11 +09:00
parent 87529c811a
commit 0912ee6f3b
174 changed files with 414 additions and 8544 deletions
@@ -30,7 +30,7 @@ class BuildTestExecutorAgentConfigTests(unittest.TestCase):
"Do not edit tests.",
"Do not edit CMake.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
):
self.assertIn(required_text, instructions)
+1 -1
View File
@@ -32,7 +32,7 @@ class CoordinatorAgentConfigTests(unittest.TestCase):
"Do not edit CMake.",
"Do not run build/test validation.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not automatically spawn subagents.",
"Do not approve release readiness independently.",
):
+1 -1
View File
@@ -32,7 +32,7 @@ class CorrectionAgentConfigTests(unittest.TestCase):
"Do not change reference artifacts",
"Do not change tolerance policies",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
):
self.assertIn(required_text, instructions)
+6 -6
View File
@@ -96,14 +96,14 @@ SKILLS = {
"Use when",
"FESA solver",
"Abaqus .inp",
"HDF5 result/reference schemas",
"CSV schemas",
"I/O",
),
"body_terms": (
"docs/io-definitions/<feature-id>-io.md",
"Abaqus Input Scope",
"Internal Model Contract",
"HDF5 Result and Reference Schemas",
"Output and CSV Schemas",
"*NODE",
"*ELEMENT",
"*MATERIAL",
@@ -130,7 +130,7 @@ SKILLS = {
"element_forces.csv",
"stresses.csv",
"Coverage Matrix",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
),
},
"fesa-cpp-msvc-tdd": {
@@ -155,7 +155,7 @@ SKILLS = {
"description_terms": (
"Use when",
"FESA solver",
"HDF5 reference",
"reference CSV",
"tolerance",
"comparison",
),
@@ -256,8 +256,8 @@ class FesaSolverSkillTests(unittest.TestCase):
for section in COMMON_SECTIONS:
self.assertIn(section, body)
self.assertIn("AGENTS.md", body)
self.assertIn("docs/AGENT_RULES.md", body)
self.assertNotIn("docs/project-plan/SOLVER_SKILL_DESIGN.md", body)
self.assertIn("docs/SOLVER_AGENT_DESIGN.md", body)
self.assertNotIn("docs/SOLVER_SKILL_DESIGN.md", body)
def test_solver_skills_define_skill_specific_contracts(self):
for skill_name, spec in SKILLS.items():
+2 -2
View File
@@ -29,9 +29,9 @@ class FormulationAgentConfigTests(unittest.TestCase):
"Do not implement code.",
"Do not design C++ APIs",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
"docs/AGENT_RULES.md",
"docs/SOLVER_AGENT_DESIGN.md",
"docs/requirements/<feature-id>.md",
"docs/research/<feature-id>-research.md",
):
+1 -1
View File
@@ -41,7 +41,7 @@ class ImplementationAgentConfigTests(unittest.TestCase):
for required_text in (
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
"Do not change requirements",
"Do not change formulations",
@@ -31,7 +31,7 @@ class ImplementationPlanningAgentConfigTests(unittest.TestCase):
"Do not edit CMake.",
"Do not run CMake/CTest.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not compare solver results.",
"Do not approve release readiness.",
):
+4 -4
View File
@@ -29,7 +29,7 @@ class IoDefinitionAgentConfigTests(unittest.TestCase):
"Do not implement parsers.",
"Do not design C++ APIs",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
"Do not claim full Abaqus compatibility",
):
@@ -43,7 +43,7 @@ class IoDefinitionAgentConfigTests(unittest.TestCase):
"Abaqus input files use keyword lines, data lines, and comment lines.",
"Model data and history data",
"supported Abaqus keyword subset",
"HDF5 result/reference schemas",
"comparison CSV schemas",
):
self.assertIn(required_text, instructions)
@@ -56,7 +56,7 @@ class IoDefinitionAgentConfigTests(unittest.TestCase):
"Model Data Mapping",
"History Data Mapping",
"Internal Model Contract",
"HDF5 Result and Reference Schemas",
"Output and CSV Schemas",
"Validation Rules",
"Downstream Handoff",
):
@@ -86,7 +86,7 @@ class IoDefinitionAgentConfigTests(unittest.TestCase):
"Model Data Mapping",
"History Data Mapping",
"Internal Model Contract",
"HDF5 Result and Reference Schemas",
"Output and CSV Schemas",
"Validation Rules",
"Downstream Handoff",
"FESA 솔버의 입력 파일은 Abaqus input file이다.",
@@ -30,9 +30,9 @@ class NumericalReviewAgentConfigTests(unittest.TestCase):
"Do not edit formulations directly.",
"Do not design C++ APIs",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
"docs/AGENT_RULES.md",
"docs/SOLVER_AGENT_DESIGN.md",
"docs/formulations/<feature-id>-formulation.md",
):
self.assertIn(required_text, instructions)
@@ -30,7 +30,7 @@ class PhysicsEvaluationAgentConfigTests(unittest.TestCase):
"Do not edit tests.",
"Do not edit CMake.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not change tolerances.",
"Do not approve release readiness.",
):
+7 -6
View File
@@ -30,7 +30,7 @@ class ReferenceModelAgentConfigTests(unittest.TestCase):
"Do not implement parsers.",
"Do not design C++ APIs",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not compare solver results.",
"Do not approve release readiness.",
):
@@ -44,7 +44,10 @@ class ReferenceModelAgentConfigTests(unittest.TestCase):
"references/<feature-id>/<model-id>/",
"model.inp",
"metadata.json",
"results.h5",
"displacements.csv",
"reactions.csv",
"element_forces.csv",
"stresses.csv",
):
self.assertIn(required_text, instructions)
@@ -57,8 +60,7 @@ class ReferenceModelAgentConfigTests(unittest.TestCase):
"Abaqus Input Requirements",
"Artifact Bundle Contract",
"Metadata JSON Contract",
"Reference HDF5 Requirements",
"Optional CSV Export Requirements",
"Reference CSV Requirements",
"Coverage Matrix",
"Downstream Handoff",
):
@@ -73,8 +75,7 @@ class ReferenceModelAgentConfigTests(unittest.TestCase):
"Abaqus Input Requirements",
"Artifact Bundle Contract",
"Metadata JSON Contract",
"Reference HDF5 Requirements",
"Optional CSV Export Requirements",
"Reference CSV Requirements",
"Coverage Matrix",
"Downstream Handoff",
"references/<feature-id>/<model-id>/",
@@ -17,7 +17,7 @@ class ReferenceVerificationAgentConfigTests(unittest.TestCase):
data = tomllib.loads(AGENT_PATH.read_text(encoding="utf-8"))
self.assertEqual(data["name"], "reference-verification-agent")
self.assertIn("stored Abaqus reference HDF5 artifacts", data["description"])
self.assertIn("stored Abaqus reference CSV artifacts", data["description"])
self.assertEqual(data["sandbox_mode"], "workspace-write")
self.assertEqual(data["model_reasoning_effort"], "extra high")
self.assertIn("developer_instructions", data)
@@ -30,7 +30,7 @@ class ReferenceVerificationAgentConfigTests(unittest.TestCase):
"Do not edit tests.",
"Do not edit CMake.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not approve release readiness.",
"Do not change tolerance policies.",
):
@@ -40,7 +40,10 @@ class ReferenceVerificationAgentConfigTests(unittest.TestCase):
instructions = AGENT_PATH.read_text(encoding="utf-8")
for required_text in (
"results.h5",
"displacements.csv",
"reactions.csv",
"element_forces.csv",
"stresses.csv",
"metadata.json",
"references/<feature-id>/<model-id>/",
):
+1 -1
View File
@@ -36,7 +36,7 @@ class ReleaseAgentConfigTests(unittest.TestCase):
"Do not change reference artifacts",
"Do not change tolerance policies",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"Do not generate reference CSVs.",
"Do not override failed or missing upstream gates.",
):
self.assertIn(required_text, instructions)
+2 -2
View File
@@ -29,9 +29,9 @@ class RequirementAgentConfigTests(unittest.TestCase):
"Do not implement code.",
"Do not write finite element formulations.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not create reference HDF5 artifacts or reference CSV outputs.",
"Do not create reference CSV outputs.",
"Requirement Verification Matrix",
"docs/AGENT_RULES.md",
"docs/SOLVER_AGENT_DESIGN.md",
"references/<feature>",
):
self.assertIn(required_text, instructions)
+2 -2
View File
@@ -29,8 +29,8 @@ class ResearchAgentConfigTests(unittest.TestCase):
"Do not implement code.",
"Do not finalize FEM formulations.",
"Do not run Abaqus, Nastran, or any reference solver.",
"Do not generate reference HDF5 artifacts or reference CSVs.",
"docs/AGENT_RULES.md",
"Do not generate reference CSVs.",
"docs/SOLVER_AGENT_DESIGN.md",
"docs/requirements/<feature-id>.md",
"Separate verified facts from inference.",
):
+1 -56
View File
@@ -87,62 +87,7 @@ class ValidateWorkspaceTests(unittest.TestCase):
with patch.object(validate_workspace.shutil, "which", return_value=None):
env = validate_workspace.validation_environment({"PATH": "C:\\Windows\\System32"})
path_key = "Path" if os.name == "nt" else "PATH"
self.assertTrue(env[path_key].startswith(str(common_bin)))
def test_common_cmake_install_path_updates_existing_windows_path_key(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")
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.assertIn("Path", env)
self.assertNotIn("PATH", env)
self.assertTrue(env["Path"].startswith(str(common_bin)))
def test_common_cmake_install_path_normalizes_uppercase_path_on_windows(self):
if os.name != "nt":
self.skipTest("Windows-specific subprocess environment behavior")
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")
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.assertIn("Path", env)
self.assertNotIn("PATH", env)
self.assertTrue(env["Path"].startswith(str(common_bin)))
def test_common_cmake_executable_is_used_when_command_tool_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")
with patch.object(validate_workspace, "COMMON_CMAKE_BIN", common_bin):
with patch.object(validate_workspace.shutil, "which", return_value=None):
command = validate_workspace.resolve_validation_command("cmake --version")
self.assertEqual(command, f'"{common_bin / "cmake.exe"}" --version')
def test_common_ctest_executable_is_used_when_command_tool_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 / "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):
command = validate_workspace.resolve_validation_command("ctest --version")
self.assertEqual(command, f'"{common_bin / "ctest.exe"}" --version')
self.assertTrue(env["PATH"].startswith(str(common_bin)))
if __name__ == "__main__":
+3 -31
View File
@@ -88,27 +88,7 @@ def discover_commands(root: Path) -> list[str]:
return load_cmake_commands(root)
def resolve_validation_command(command: str) -> str:
parts = command.split(maxsplit=1)
if not parts:
return command
tool = parts[0].lower()
if tool not in {"cmake", "ctest"}:
return command
if shutil.which(tool) is not None:
return command
exe = COMMON_CMAKE_BIN / f"{tool}.exe"
if not exe.exists():
return command
suffix = f" {parts[1]}" if len(parts) > 1 else ""
return f'"{exe}"{suffix}'
def run_command(command: str, root: Path) -> subprocess.CompletedProcess:
command = resolve_validation_command(command)
return subprocess.run(
command,
cwd=root,
@@ -123,25 +103,17 @@ def run_command(command: str, root: Path) -> subprocess.CompletedProcess:
def validation_environment(base_env: os._Environ | dict[str, str]) -> dict[str, str]:
env = dict(base_env)
path_key = "Path" if os.name == "nt" else "PATH"
path_values = []
for key in list(env):
if key.lower() == "path":
path_values.append(env.pop(key))
current_path = os.pathsep.join(part for part in path_values if part)
env[path_key] = current_path
if shutil.which("cmake", path=current_path) is not None:
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_key] = common_bin_text + (os.pathsep + current_path if current_path else "")
env["PATH"] = common_bin_text + (os.pathsep + current_path if current_path else "")
return env