Skip to content

Fix Agent Tasks Executed count broken by locale thousands separator (ADO 633444)#8472

Open
Groenbech96 wants to merge 1 commit into
microsoft:mainfrom
Groenbech96:fix/ado-633444-agent-task-count-locale-split
Open

Fix Agent Tasks Executed count broken by locale thousands separator (ADO 633444)#8472
Groenbech96 wants to merge 1 commit into
microsoft:mainfrom
Groenbech96:fix/ado-633444-agent-task-count-locale-split

Conversation

@Groenbech96
Copy link
Copy Markdown
Contributor

Summary

Fix the Agent Tasks Executed counter (and the drill-down filter) on the AI Test Toolkit pages, which over-counts by a factor of ~2-3 on locales that render thousands separators (en-US default).

Repro from ADO 633444: running the full RT-ACCUR suite (184 distinct Agent Tasks) shows Agent Tasks Executed = 369 on the AIT Test Suite page. After this fix, the counter shows 184.

Resolves ADO 633444.

Root cause

Codeunit 149049 "Agent Test Context Impl." aggregates the Agent Task IDs touched during a test run via a comma-separated text round-trip:

  1. ProducerGetCommaSeparatedAgentTaskIDs formats each BigInteger ID into text and joins with ", ":
    TaskIDTextList.Add(Format(AgentTestTaskLog."Agent Task ID"));     // <-- offender
    ...
    exit(ConcatenateList(TaskIDTextList, ', '));
  2. Consumer Fix CICD #1GetAgentTaskCount counts elements after Split(','):
    TaskIDList := CommaSeparatedTaskIDs.Split(',');
    exit(TaskIDList.Count);
  3. Consumer Updated AL-Go System Files #2ConvertCommaSeparatedToFilter turns the text into a SetFilter expression by replacing , with |.

The default overload Format(BigInteger) honors the current culture. On en-US (the runtime locale for these tests, per AgentRuntimeTests' .resources), a 6-digit Agent Task ID such as 1234567 renders as "1,234,567" — three fragments after Split(',').

So for N distinct Agent Task IDs with c average internal commas, the counter returns roughly N × (c + 1) instead of N. With BC's current Agent Task IDs in the 6-7 digit range, c ≈ 1, giving the observed ~2 × N + 1 = 369 for N = 184.

The drill-down filter built by ConvertCommaSeparatedToFilter (used to navigate from the counter to the Agent Task List) was silently broken in the same way: 1,234,567 became the filter 1|234|567, three unrelated IDs.

Scope of impact (all fixed transitively by the one-line change)

Surface Field Source
AIT Test Suite Agent Tasks Executed (totals row) AgentTestSuite.PageExt.al calls GetAgentTaskCount
AIT Run History — by Version Agent Tasks Executed AgentRunHistory.PageExt.al
AIT Run History — by Tag Agent Tasks Executed AgentRunHistory.PageExt.al
AIT Test Method Lines Agent Tasks Executed per line AgentTestMethodLines.PageExt.al
AITLogEntry API page agentTasksExecuted API field
Agent Task List drill-down filter values ConvertCommaSeparatedToFilter

Fix

Format(value, 0, 9) — Format type 9 is the XML / invariant culture format and emits the integer as a plain digit run with no group separators. This is the canonical "give me machine-parseable text for a number" pattern in BC AL and is already used elsewhere in the same submodule (e.g. LibraryAgentImpl.Codeunit.al).

The change is one line plus a code comment explaining why the locale-sensitive overload must not be reintroduced here:

-                    TaskIDTextList.Add(Format(AgentTestTaskLog."Agent Task ID"));
+                    // Format using XML/invariant culture (format 9) to avoid locale thousands
+                    // separators that would otherwise be split as extra IDs by the comma-based
+                    // serialization used in GetAgentTaskCount and ConvertCommaSeparatedToFilter.
+                    TaskIDTextList.Add(Format(AgentTestTaskLog."Agent Task ID", 0, 9));

No other producers were found — rg -n "Format\(.*Agent Task ID.*\)" over src/Tools/AI Test Toolkit returns exactly one hit. Fixing the producer fixes all consumers.

Why not change the delimiter instead?

You could also defend against this by switching from "," to a delimiter that can't appear in a culture-formatted number (e.g. ";" or "|"), but that would require touching the producer and both consumers and would change a string the AIT API page surfaces. The locale-safe Format(value, 0, 9) at the single producer is strictly smaller, strictly safer, and brings the toolkit in line with the BC convention for round-tripping numeric IDs through text.

Math check

Observed: 184 distinct Agent Tasks → counter shows 369.
After fix: counter shows 184.
Pre-fix arithmetic for 6-digit IDs (1,234,567 → 3 fragments per ID, plus the inter-ID separator): 184 × 2 + 1 = 369. ✅

Test notes

No new unit test is added in this change. The existing AIT regression run (RT-ACCUR) is the repro — its Agent Tasks Executed totals now equal the number of distinct rows in the underlying Agent Task Log cursor.

If desired, a targeted regression test for GetCommaSeparatedAgentTaskIDs could be added that seeds Agent Task IDs >= 1000 and asserts both GetAgentTaskCount and ConvertCommaSeparatedToFilter produce the expected values regardless of GLOBALLANGUAGE. Happy to add this in a follow-up if maintainers want it in-tree.

The Agent Test Context aggregated Agent Task IDs through a comma-separated
text round-trip. The IDs were rendered with the default Format(BigInteger)
which honors the current culture and inserts thousands separators on
locales like en-US (e.g. 1,234,567). The downstream count and filter
helpers split that text on , and treated each fragment as an ID, so for
typical 6-7 digit Agent Task IDs the Agent Tasks Executed value on
- AIT Test Suite,
- AIT Run History (by version and by tag),
- AIT Test Method Lines,
- AITLogEntry API page,
inflated to roughly 2-4 times the real number of distinct Agent Tasks
(repro: full RT-ACCUR run with 184 tasks shows 369). The same defect made
the drill-down filter built by ConvertCommaSeparatedToFilter point at
unrelated Agent Tasks.

Fix: serialize Agent Task IDs with Format(value, 0, 9) (XML/invariant
culture) so the comma separators in the joined string are unambiguous.

Resolves ADO 633444.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added AL: Tools From Fork Pull request is coming from a fork labels Jun 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

Could not find linked issues in the pull request description. Please make sure the pull request description contains a line that contains 'Fixes #' followed by the issue number being fixed. Use that pattern for every issue you want to link.

@Groenbech96 Groenbech96 marked this pull request as ready for review June 4, 2026 07:15
@Groenbech96 Groenbech96 requested a review from a team as a code owner June 4, 2026 07:15
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

$\textbf{🟡\ Medium\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

Same locale Format bug unfixed for VersionNumber

GetAgentTaskIDs converts VersionNumber to filter text using Format(VersionNumber) — the same locale-sensitive call that this PR fixes for Agent Task IDs. For BC version numbers ≥ 1,000 (e.g. build 24000), en-US locale renders this as "24,000", which SetFilter parses as the expression "24 OR 000", silently returning wrong results instead of filtering to the intended version.

Recommendation:

  • Apply the same invariant-culture format specifier used in the fix: Format(VersionNumber, 0, 9). This ensures the version number is serialized without thousands separators before being passed as a filter string.
            VersionFilterText := Format(VersionNumber, 0, 9);

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

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

$\textbf{🟡\ Medium\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

Same locale Format bug unfixed in GetCopilotCredits

GetCopilotCredits(…, VersionNumber: Integer, …) has the identical locale-sensitive Format(VersionNumber) call. For version numbers ≥ 1,000 the generated filter string will be malformed, causing the Copilot Credits calculation to include entries from unintended versions or return zero.

Recommendation:

  • Use Format(VersionNumber, 0, 9) to produce an invariant-culture integer string, consistent with the fix applied to Agent Task ID serialization in this same commit.
            VersionFilterText := Format(VersionNumber, 0, 9);

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

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

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

Labels

AL: Tools From Fork Pull request is coming from a fork

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants