Skip to content

[Master]-Post Inventory Cost to G/L fails when concatenated dimension text exceeds 250 characters - #11144

Open
Fixes4BC (neeleshsinghal) wants to merge 8 commits into
mainfrom
bugs/Bug-649310-Post-Inventory-Cost-to-GL-fails-dimension-text-exceed
Open

[Master]-Post Inventory Cost to G/L fails when concatenated dimension text exceeds 250 characters#11144
Fixes4BC (neeleshsinghal) wants to merge 8 commits into
mainfrom
bugs/Bug-649310-Post-Inventory-Cost-to-GL-fails-dimension-text-exceed

Conversation

@neeleshsinghal

@neeleshsinghal Fixes4BC (neeleshsinghal) commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixes AB#649310

@neeleshsinghal
Fixes4BC (neeleshsinghal) requested a review from a team September 7, 2026 13:04
@neeleshsinghal
Fixes4BC (neeleshsinghal) requested a review from a team as a code owner September 7, 2026 13:04
@github-actions github-actions Bot added the Team: SCM GitHub request for SCM area label Sep 7, 2026
@github-actions github-actions Bot added this to the Version 30.0 milestone Sep 7, 2026
Comment thread src/Layers/W1/BaseApp/Inventory/Costing/PostInventoryCosttoGL.Report.al Outdated
Comment thread src/Layers/W1/Tests/SCM/SCMInventoryReportsI.Codeunit.al
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 1

Recommendation: Request Changes

What this PR does

This change builds the next dimension-text candidate before assigning it to the report field, so the report can stop before the value exceeds 250 characters. The logic matches the reported failure and the added test covers the posting-report preview path, but the changed assignment still introduces a new analyzer warning that fails validation.

Problem-solution fit

Fit: Strong

The bug is clear: a complete dimension pair can make the concatenated text too long. The fix targets that exact boundary and keeps the last complete value that fits.

Suggestions

S1 (🔴 High): Make the bounded assignment analyzer-safe
The current validation fails with AA0139 because OldDimText is unbounded Text and DimText is Text[250]. Keep the length guard, then assign with CopyStr(OldDimText, 1, MaxStrLen(DimText)) so the analyzer can prove the value is safe.

Risk assessment and necessity

Risk: This is a posting report path, so a bad fix can block inventory-cost posting review output. The change is narrow and does not change posting amounts, events, or public signatures, but the current validation failure blocks safe merge.

Necessity: The change is required because valid dimension data can exceed the report field limit. The added regression test exercises the important path and confirms the report keeps complete dimension pairs only.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11144 round=1 by=alexei-dobriansky at=2026-09-07T18:16:56Z lastSha=84207c07825c8d93765b0fd0623ed91759241aa8 reviewKey=03464e141dfa2ef49b687daa86dca11481c54fd9ff356268b6f770f0ee03edd5 suggestions=S1@27b15d6a

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

$\textbf{🟡\ Medium\ Severity\ —\ Error\ Handling}$

GetDimText builds the next concatenated dimension-text value into OldDimText: Text[250], which has the exact same maximum length as DimText. In the new PostInventoryCostToGLWithDimensionTextLongerThan250Characters test scenario, the sixth appended pair grows the candidate from 223 to 268 characters. Because the candidate is assigned to OldDimText (also Text[250]) before the length check runs, the assignment itself either truncates or errors on the identically-sized target exactly as the pre-PR code did when assigning directly into DimText — so StrLen(OldDimText) > MaxStrLen(DimText) can never observe the true, pre-truncation candidate length. Swapping which same-sized variable receives the raw candidate does not change the overflow-handling behavior versus the code this PR is meant to fix. The candidate should be built in an intermediate variable strictly larger than DimText (e.g. an unbounded Text or Text[500]), with the length check performed against that untruncated value before ever copying into the fixed-length DimText. Severity is capped at minor per agent-finding rules, but if this reasoning is correct the actual impact is that the report crash/data-corruption bug this PR claims to fix (scenario 649269) is not actually fixed, and the new test may not validate what it claims to.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

    local procedure GetDimText(var DimSetEntry: Record "Dimension Set Entry")
    var
        CandidateDimText: Text;
    begin
        DimText := '';

        if DimSetEntry.FindSet() then
            repeat
                if DimText = '' then
                    CandidateDimText := StrSubstNo('%1 - %2', DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code")
                else
                    CandidateDimText :=
                      StrSubstNo(
                        '%1; %2 - %3', DimText, DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
                if StrLen(CandidateDimText) > MaxStrLen(DimText) then
                    exit;
                DimText := CandidateDimText;
            until DimSetEntry.Next() = 0;
    end;

Line mapping was unavailable, so this was posted as an issue comment.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.39.6

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

$\textbf{🟡\ Medium\ Severity\ —\ Style}$

In GetDimText, OldDimText now holds the newly computed candidate string while DimText holds the previously accepted value. The reversed names make the length-check logic unnecessarily hard to read and verify; rename the local variable to something like CandidateDimText so the code matches its actual data flow.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

        CandidateDimText: Text[250];
    begin
        DimText := '';

        if DimSetEntry.FindSet() then
            repeat
                if DimText = '' then
                    CandidateDimText := StrSubstNo('%1 - %2', DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code")
                else
                    CandidateDimText :=
                      StrSubstNo(
                        '%1; %2 - %3', DimText, DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
                if StrLen(CandidateDimText) > MaxStrLen(DimText) then
                    exit;
                DimText := CandidateDimText;
            until DimSetEntry.Next() = 0;

Line mapping was unavailable, so this was posted as an issue comment.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.39.6

Comment thread src/Layers/W1/Tests/SCM/SCMInventoryReportsI.Codeunit.al
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 2

Recommendation: Request Changes

What this PR does

This change tries to keep the last complete dimension text that fits in Text[250] and adds a regression test for the report preview path. The new round changes the candidate variable to Text[250], but that means the long candidate is still put into a bounded variable before the length check runs, so the reported failure is not safely fixed.

Status of previous suggestions
ID Title Status Author response
S1 Make the bounded assignment analyzer-safe Not addressed The code was changed, but it still does not make a safe bounded assignment after the guard.
New observations (commits since round 1)

S1 (🔴 High): Keep the candidate text unbounded
The latest change stores the next 268-character candidate in OldDimText: Text[250] before the length check. That can fail or truncate before StrLen can stop it, so the report can still break in the reported case. Keep the candidate as unbounded Text, check its length, then assign to DimText with CopyStr.

Risk assessment and necessity

Risk: This is an inventory cost posting report path. If the fix merges as-is, the same long-dimension preview scenario can still fail instead of showing the report. The change does not affect posting amounts, events, or public signatures.

Necessity: The fix is required because valid dimension data can exceed the report field limit. The scope is right, but the candidate text must stay unbounded until after the length guard.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11144 round=2 by=alexei-dobriansky at=2026-09-08T06:03:53Z lastSha=7062c8151b6c35aad9967c18a29d9110af32d100 reviewKey=32945d73536e65eee43035389825d699277d411349361dd4d9050587bf0aa53c suggestions=S1@35b01342:notaddressed parentRound=1

Comment thread src/Layers/W1/Tests/SCM/SCMInventoryReportsI.Codeunit.al
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 3

Recommendation: Request Changes

What this PR does

This update tries to prevent the dimension text overflow by truncating each candidate with CopyStr before assigning it to DimText. That still does not meet the reported behavior: the full sixth-pair candidate is 268 characters, but the code cuts it to 250 before the guard runs, so the guard cannot keep the previous complete 223-character value.

Status of previous suggestions
ID Title Status Author response
S1 Keep the candidate text unbounded Not addressed The latest change truncates the candidate before the length check, so the full candidate is still not checked before assigning DimText.
New observations (commits since round 2)

None - the latest commit only attempts to address the previous suggestion, but the blocker remains open.

Risk assessment and necessity

Risk: This is an inventory cost posting report preview path. The change does not affect posting amounts, events, or public signatures, but it can still show a partial dimension pair instead of the last complete valid text.

Necessity: The fix is required because valid dimension data can exceed the report field limit. The scope is right, but the candidate must stay unbounded until after the length guard.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11144 round=3 by=alexei-dobriansky at=2026-09-08T12:03:37Z lastSha=e58eaf3a7449c7286d48547badb893ccfd2cc3b6 reviewKey=9ae972e4db183dec8b0bf0d0673418a0553ca4644920d3acfdfc7bfbc99a25bd suggestions=S1@35b01342:notaddressed parentRound=2

DimText := OldDimText;
OldDimText :=
StrSubstNo('%1; %2 - %3', DimText, DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
DimText := CopyStr(OldDimText, 1, MaxStrLen(DimText));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Agent}$

In the rewritten GetDimText, DimText := CopyStr(OldDimText, 1, MaxStrLen(DimText)) runs unconditionally, before the overflow check if StrLen(OldDimText) > MaxStrLen(DimText) then exit. When the newly built OldDimText overflows (e.g. the 6th dimension pair pushes it to 268 characters against a 250-char limit), CopyStr still commits a truncated value into DimText that contains the first 223 correct characters plus a partial, mid-pair fragment of the 6th dimension pair (chars 224-250) — not the clean 5-pair value the new test (PostInventoryCostToGLWithDimensionTextLongerThan250Characters) expects via ExpectedDimText. The exit then leaves this corrupted/truncated value in DimText instead of the last cleanly-fitting value. Reorder so the overflow check runs before the assignment (or restore the prior DimText value on overflow, as the old code did via DimText := OldDimText), so a partially-cut dimension pair is never committed to the report output.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

                if StrLen(OldDimText) > MaxStrLen(DimText) then
                    exit;
                DimText := CopyStr(OldDimText, 1, MaxStrLen(DimText));

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

OldDimText := DimText;
if DimText = '' then
DimText := StrSubstNo('%1 - %2', DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code")
OldDimText :=

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Error\ Handling}$

GetDimText now builds the next dimension string directly into OldDimText: Text[250]. In the new test scenario, the sixth StrSubstNo(...) result is 268 characters long, so assigning it with := can raise AL's runtime "string too long" error before CopyStr(...) or the subsequent length check ever runs, because OldDimText has the exact same fixed length (250) as DimText. Build into an unbounded Text temporary (or truncate before assigning to a fixed-length variable) so the report can safely stop after the last fitting pair instead of risking a runtime overflow error.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

QuantityErr: Label 'Quantity Must Be %1 for %2 Document No. %3';
NothingToPostTxt: Label 'There is nothing to post to the general ledger.';
ValueEntriesWerePostedTxt: Label 'value entries have been posted to the general ledger.';
QuantityErr: Label 'Quantity Must Be %1 for %2 Document No. %3';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Style}$

SetupBlockedErr has a Comment, but it still groups %2-%5 together as "posting groups" instead of naming each placeholder individually. This label is only used with two caption/value pairs, so translators need separate descriptions for each ordinal to localize the sentence correctly.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

        SetupBlockedErr: Label 'Setup is blocked in %1 for %2 %3 and %4 %5.', Comment = '%1 = Setup table caption, %2 = Gen. Bus. Posting Group caption, %3 = Gen. Bus. Posting Group value, %4 = Gen. Prod. Posting Group caption, %5 = Gen. Prod. Posting Group value.';

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

$\textbf{🟡\ Medium\ Severity\ —\ Accessibility}$

This report enforces the request-page journal fields only in OnPreReport(). If Journal Template Name or Journal Batch Name is left blank, the request page closes and then errors, so the user loses the entered options instead of correcting them in place. Add the same validation to requestpage.OnQueryClosePage() behind 'if CloseAction = Action::OK then', keep the OnPreReport() check for non-interactive runs, and mark the visible required controls with ShowMandatory.

Knowledge:

Line mapping was unavailable, so this was posted as an issue comment.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

'%1; %2 - %3', DimText, DimSetEntry."Dimension Code", DimSetEntry."Dimension Value Code");
if StrLen(DimText) > MaxStrLen(OldDimText) then begin
DimText := OldDimText;
OldDimText :=

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Error\ Handling}$

This change still leaves GetDimText vulnerable to the same unhandled runtime overflow it is trying to avoid. OldDimText is declared as Text[250], but on the sixth 20-character dimension pair the expression StrSubstNo('%1; %2 - %3', DimText, ...) can reach 268 characters (223 already accumulated in DimText after five pairs, plus 45 more), so assigning it to OldDimText raises the AL string-length runtime error ('The length of the string is X, but it must be less than or equal to Y characters') before CopyStr(...) or the following length check can run. The fix relocates the overflow from DimText to OldDimText without removing it, since both are bounded Text[250] variables. Use an unbounded temporary Text value for the computed candidate string, then CopyStr into DimText and exit when the unbounded value's length exceeds MaxStrLen(DimText). Note: this is a concrete, high-impact defect (the report would still error/crash on dimension text over ~250-268 chars) but is capped to 'minor' severity here per the agent-finding contract because no BCQuality knowledge file backs it directly; it should be verified against a live BC runtime and, if confirmed, treated as blocking for merge.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

DimensionValue: Record "Dimension Value";
DimensionCode: Code[20];
DimensionValueCode: Code[20];
i: Integer;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Testing}$

The new fixture helper CreateMaxLengthDimensionSet hand-rolls Dimension records with Init/Validate/Insert(true) and invented primary keys instead of using the test library. That is the anti-pattern this rule calls out: the helper now owns record-shape details that the Library codeunits already maintain, which makes the test more fragile across schema changes and increases the risk of data/setup failures unrelated to the behavior under test.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6


// [THEN] The report contains the five complete pairs that fit and omits the sixth pair.
LibraryReportDataset.LoadDataSetFile();
LibraryReportDataset.AssertElementWithValueExists('DimText', ExpectedDimText);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Testing}$

With the fixed six 20-character dimension codes and values created by this test, ExpectedDimText is built from only the first five pairs (223 characters), while the test's [THEN] step comments describe the sixth pair as merely 'omitted'. Given the arithmetic in GetDimText, the sixth pair's StrSubstNo result is 268 characters, which (per the related error-handling finding) triggers an AL runtime length error on assignment to OldDimText (Text[250]) rather than being cleanly excluded. If that error-handling defect is real, this test would fail with a runtime error rather than passing with a clean 5-pair DimText, so the assertion does not actually validate the intended 'no failure' scenario end-to-end. Recommend adding an assertion or handler that also verifies the report completes without an unhandled error, and confirming the exact truncation boundary against a live BC runtime before relying on this test as proof of the fix.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 4

Recommendation: Request Changes

What this PR does

This update now builds the next dimension-text candidate, copies it into the report field, and then checks whether the candidate is too long. The reported scenario is still not safely fixed: the candidate variable is still bounded to 250 characters, and DimText is assigned before the guard. When the sixth pair makes the candidate exceed the field length, the code can still fail before the guard or leave a partial sixth pair instead of keeping the previous complete value.

Status of previous suggestions
ID Title Status Author response
S1 Keep the candidate text unbounded Not addressed The latest change still keeps the candidate in Text[250] and writes DimText before the length check.
New observations (commits since round 3)

None - the latest commit only attempts to address the previous suggestion, but the blocker remains open.

Risk assessment and necessity

Risk: This is an inventory cost posting report preview path. It does not change posting amounts, public signatures, or events, but it can still fail before the guard or show a partial dimension pair instead of the last complete valid text.

Necessity: The fix is required because valid dimension data can exceed the report field limit. The scope is right, but the candidate must stay unbounded until after the length guard passes.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11144 round=4 by=alexei-dobriansky at=2026-09-08T18:29:46Z lastSha=7dffd0144f95496905b1086bd492015f2337df72 reviewKey=6a6e4094c392133675c14c1d6d3ef786ed9c90011cc573f652ab9b9d44247b14 suggestions=S1@35b01342:notaddressed parentRound=3


if DimSetEntry.FindSet() then
repeat
OldDimText := DimText;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Testing}$

GetDimText in PostInventoryCosttoGL.Report.al (lines ~857-867) has a logic bug introduced by this PR's refactor: on the first loop iteration (DimText = ''), the if-branch correctly computes the no-separator format '%1 - %2' into OldDimText, but the code then unconditionally falls through (outside the if/else) to recompute OldDimText using the separator format '%1; %2 - %3' with DimText still ''. This overwrites the correct value and produces a spurious leading '; ' before the first dimension pair (e.g. '; DIM1 - VAL1' instead of 'DIM1 - VAL1'). This corrupts the DimText report column for every posting that has at least one dimension. It also means the new test added in this same PR (PostInventoryCostToGLWithDimensionTextLongerThan250Characters / CreateMaxLengthDimensionSet), which builds ExpectedDimText using the no-separator format for the first pair, will not match the actual report output and either fails or was validated against incorrect output.

Recommendation:

  • only perform the unconditional StrSubstNo('%1; %2 - %3', ...) + CopyStr assignment in the non-empty-DimText branch; in the DimText = '' branch, assign DimText from the already-computed OldDimText (bounded via CopyStr) instead of recomputing it with the wrong format.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 5

Recommendation: Accept

What this PR does

This update changes the dimension text builder so it checks the next complete dimension pair before assigning it to the bounded report text. The reported scenario is now handled: when the next pair would exceed 250 characters, the report keeps the previous complete value and exits without adding a partial pair.

Status of previous suggestions
ID Title Status Author response
S1 Keep the candidate text unbounded Addressed The latest change checks the full next candidate before assigning it to the bounded variable, so the previous complete text is preserved.
New observations (commits since round 4)

None - the latest commits address the previous blocker without adding a new issue.

Risk assessment and necessity

Risk: This is limited to dimension text rendering in the Post Inventory Cost to G/L report. It does not change posting amounts, ledger entries, public signatures, or events, and shorter dimension sets keep the same output.

Necessity: The change is needed because valid dimension data can exceed the report field limit. The scope is now right because it stops only when the next complete pair would exceed the limit.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11144 round=5 by=alexei-dobriansky at=2026-09-09T12:21:48Z lastSha=7bb2cd923e19eaff83d94928f46f920ed4fde7a7 reviewKey=9dadd467c65bab0f16e579766b28e785bf4cb62ba7f45ca2e30404e6787e70ab suggestions=S1@35b01342:addressed parentRound=4

@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 6

Recommendation: Accept

What this PR does

This update builds the next dimension-text candidate in an unbounded variable before copying it into the 250-character report field. The reported long-dimension scenario is handled because the report now keeps the last complete dimension text and exits before assigning an overlong value to the bounded field.

Status of previous suggestions
ID Title Status Author response
S1 Keep the candidate text unbounded Addressed The latest change makes the candidate text variable unbounded, so the overflow check runs before the value is copied into DimText.
New observations (commits since round 5)

None - the latest commit addresses the previous blocker without adding a new issue.

Risk assessment and necessity

Risk: This is limited to dimension text rendering in the Post Inventory Cost to G/L report. It does not change posting amounts, ledger entries, public signatures, or events; shorter dimension sets keep the same output, and overlong sets now stop at the last complete pair that fits.

Necessity: The change is needed because valid dimension data can produce display text longer than the report field. The scope is right because it changes only the local text-building path and the added regression test covers the long-dimension case.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11144 round=6 by=alexei-dobriansky at=2026-09-09T18:16:11Z lastSha=0dc54a9c95837cd94ca03ad33f93d7245b802d39 reviewKey=e0c90d0ed68d70713926304ae5045b57e8317465db306be1e84eb58e600383ad suggestions=S1@35b01342:addressed parentRound=5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Team: SCM GitHub request for SCM area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants