feat(linear-static-3d-euler-beam): step 12 - inp-domain-mapping-review-fix

This commit is contained in:
KOKO\Mimi
2026-08-09 16:34:48 +09:00
parent 9502ef56b4
commit b1e78bc4cc
3 changed files with 97 additions and 13 deletions
@@ -326,3 +326,36 @@
- Focused re-review returned Critical 0 and Important 0. Its sole remaining - Focused re-review returned Critical 0 and Important 0. Its sole remaining
minor requested an explicit negative transverse-shear context assertion; minor requested an explicit negative transverse-shear context assertion;
that table case was added and passes without a production change. that table case was added and passes without a production change.
### Step 12 Root Review Fix Round 1 — same-token target ambiguity
- finding: `resolveNodeTarget` returned one matching node set before computing
the direct numeric source-label candidates. A token such as `1` therefore
silently selected `NSET=1` even when node source label `1` was also a valid
interpretation.
- regression_scope: `RejectsUnsupportedAndInvalidPortfolio` now constructs an
`NSET` named `1` containing node `2` while node label `1` also exists, and
exercises the same token independently through both `*BOUNDARY` and
`*CLOAD`. It requires input-category `unresolved-reference` with exact
keyword, entity identity `1`, and original data-row file/line location.
- RED-build: `cmake --build .harness/build --config Debug --target fesa_tests`
exited 0 after registering the two regression paths.
- RED-test: `ctest --test-dir .harness/build -C Debug -R "InpDomainMapping.RejectsUnsupportedAndInvalidPortfolio" --output-on-failure`
exited 8. The test failed at `same-token-boundary`
because `result.hasValue()` was true instead of the required structured
failure.
- fix: target resolution computes both name-matched node sets and numeric
direct-node candidates before returning either. Multiple candidates within
an interpretation or one valid candidate from each interpretation use the
existing input/`unresolved-reference` ambiguity contract; unique set-only
and direct-only paths remain unchanged.
- GREEN: the targeted build exited 0 and `ctest --test-dir .harness/build -C Debug -R InpDomainMapping --output-on-failure`
exited 0 with 5/5 passed.
- VERIFY: approved explicit-dependency MSVC x64 configure and full Debug build
exited 0; discovery found 19 tests including all five mapper names; full
CTest passed 19/19. Backend/upward/core-upward/distributed-load/unapproved
`nu` scans were 0, exactly five mapper tests remained, `git diff --check`
exited 0, and reference diff/status were clean.
- deferred_scope: the separate known-but-misplaced keyword diagnostic Minor was
deliberately not changed in this fix round. No phase-index change and no
commit were made.
+29 -13
View File
@@ -2026,19 +2026,10 @@ private:
matchingSets.push_back(&set); matchingSets.push_back(&set);
} }
} }
if (matchingSets.size() == 1U) {
return matchingSets.front()->nodeIndices;
}
if (matchingSets.size() > 1U) {
inputFailure(
"unresolved-reference", location, keyword, target,
"The node-set target is ambiguous across identity instances.");
return std::nullopt;
}
std::vector<EntityIndex> matchingNodes;
std::int64_t label = 0; std::int64_t label = 0;
if (tryPositiveInteger(target, label)) { if (tryPositiveInteger(target, label)) {
std::vector<EntityIndex> matchingNodes;
for (std::size_t index = 0U; for (std::size_t index = 0U;
index < definition_.nodes.size(); index < definition_.nodes.size();
++index) { ++index) {
@@ -2046,9 +2037,34 @@ private:
matchingNodes.push_back(static_cast<EntityIndex>(index)); matchingNodes.push_back(static_cast<EntityIndex>(index));
} }
} }
if (matchingNodes.size() == 1U) { }
return matchingNodes;
} // A token is resolved only after both approved interpretations have
// been considered; declaration order never gives a node set priority
// over an equally valid direct source-label target.
if (matchingSets.size() > 1U) {
inputFailure(
"unresolved-reference", location, keyword, target,
"The node-set target is ambiguous across identity instances.");
return std::nullopt;
}
if (matchingNodes.size() > 1U) {
inputFailure(
"unresolved-reference", location, keyword, target,
"The direct node-label target is ambiguous across identity instances.");
return std::nullopt;
}
if (matchingSets.size() == 1U && matchingNodes.size() == 1U) {
inputFailure(
"unresolved-reference", location, keyword, target,
"The target is ambiguous between a node-set name and a direct node label.");
return std::nullopt;
}
if (matchingSets.size() == 1U) {
return matchingSets.front()->nodeIndices;
}
if (matchingNodes.size() == 1U) {
return matchingNodes;
} }
inputFailure( inputFailure(
"unresolved-reference", location, keyword, target, "unresolved-reference", location, keyword, target,
@@ -573,6 +573,41 @@ TEST(InpDomainMapping, RejectsUnsupportedAndInvalidPortfolio) {
EXPECT_FALSE(diagnostic->location.file.empty()); EXPECT_FALSE(diagnostic->location.file.empty());
EXPECT_GT(diagnostic->location.line, 0U); EXPECT_GT(diagnostic->location.line, 0U);
} }
struct SameTokenAmbiguityCase {
std::string name;
std::string deck;
std::string expectedKeyword;
std::size_t expectedLine;
};
const std::string sameTokenBase = replaceOnce(
base,
"*Elset, elset=BeamSet",
"*Nset, nset=1\n2\n*Elset, elset=BeamSet");
const std::vector<SameTokenAmbiguityCase> sameTokenCases{
{"boundary", replaceOnce(sameTokenBase, "Root, 1, 6", "1, 1, 6"),
"BOUNDARY", 27U},
{"cload", replaceOnce(sameTokenBase, "Tip, 2, -1.", "1, 2, -1."),
"CLOAD", 32U}};
for (const auto& testCase : sameTokenCases) {
SCOPED_TRACE("same-token-" + testCase.name);
auto result = mapText("same-token-" + testCase.name, testCase.deck);
ASSERT_FALSE(result.hasValue());
EXPECT_EQ(
result.status().failureCategory(),
fesa::FailureCategory::input);
const auto* diagnostic =
findDiagnostic(result.status(), "unresolved-reference");
ASSERT_NE(diagnostic, nullptr);
EXPECT_EQ(diagnostic->severity, fesa::Severity::error);
EXPECT_EQ(diagnostic->keyword, testCase.expectedKeyword);
EXPECT_EQ(diagnostic->entityIdentity, "1");
EXPECT_EQ(diagnostic->location.line, testCase.expectedLine);
EXPECT_EQ(
diagnostic->location.file.filename().string(),
"fesa-domain-mapper-same-token-" + testCase.name + ".inp");
}
} }
TEST(InpDomainMapping, RejectsDloadWithoutDistributedLoadObject) { TEST(InpDomainMapping, RejectsDloadWithoutDistributedLoadObject) {