feat(linear-static-3d-euler-beam): step 12 - inp-domain-mapping-review-fix
This commit is contained in:
@@ -326,3 +326,36 @@
|
||||
- Focused re-review returned Critical 0 and Important 0. Its sole remaining
|
||||
minor requested an explicit negative transverse-shear context assertion;
|
||||
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.
|
||||
|
||||
@@ -2026,19 +2026,10 @@ private:
|
||||
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;
|
||||
if (tryPositiveInteger(target, label)) {
|
||||
std::vector<EntityIndex> matchingNodes;
|
||||
for (std::size_t index = 0U;
|
||||
index < definition_.nodes.size();
|
||||
++index) {
|
||||
@@ -2046,9 +2037,34 @@ private:
|
||||
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(
|
||||
"unresolved-reference", location, keyword, target,
|
||||
|
||||
@@ -573,6 +573,41 @@ TEST(InpDomainMapping, RejectsUnsupportedAndInvalidPortfolio) {
|
||||
EXPECT_FALSE(diagnostic->location.file.empty());
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user