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
|
- 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.
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user