Skip to content

[data] fix: preserve GLM historical answer loss - #5633

Merged
yaoyu-33 merged 2 commits into
mainfrom
bug-hunter/glm-history-mask-20260818
Aug 20, 2026
Merged

yaoyu-33 merged 2 commits into
mainfrom
bug-hunter/glm-history-mask-20260818

Conversation

@yaoyu-33

Copy link
Copy Markdown
Contributor

Summary

GLM multi-turn SFT with enable_thinking=true and truncate_history_thinking=true could silently exclude a historical assistant answer from the loss mask. The official template clears historical reasoning in the full render but retains it in the per-turn prefix render, so the common-prefix boundary can land inside the assistant turn.

This is a follow-up to the runtime surface introduced in #5541.

Root cause and fix

For assistant turns without an explicit terminator, the mask builder treated the common-prefix mismatch as the end of the turn. The mismatch may instead be caused by history-dependent template rendering.

The fix teaches the GLM boundary configuration its official role markers and ends a nonterminal assistant span at the next rendered role marker. It fails closed to the tokenizer-native assistant mask when role markers cannot be trusted or found. No public API, dependency, CI, or Megatron-Core changes are included.

Validation

Fail-before, with the regression test applied to unmodified production code:

uv run --active --no-sync python -m pytest tests/unit_tests/models/test_glm52_kimi_k3_minimax_m3_chat.py::test_glm_history_thinking_truncation_preserves_historical_answer_loss -q --tb=short
# 1 failed: actual [13, 13, 35, 14, 34], expected [13, 14, 31, 13, 35, 14, 34]

Pass-after:

uv run --active --no-sync python -m pytest tests/unit_tests/models/test_glm52_kimi_k3_minimax_m3_chat.py::test_glm_history_thinking_truncation_preserves_historical_answer_loss -q --tb=short
# 1 passed

Adjacent coverage:

uv run --active --no-sync python -m pytest tests/unit_tests/models/test_glm52_kimi_k3_minimax_m3_chat.py tests/unit_tests/data/test_conversation_processing.py -q --tb=short
# 125 passed

uv run --active --no-sync pre-commit run --all-files
# all hooks passed

git diff --check
# passed

Scope

This patch is limited to no-terminator GLM assistant-mask boundaries and their regression coverage. It does not claim full-suite, convergence, model-quality, or performance validation.

Signed-off-by: Yu Yao <yaoyu.094@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@yaoyu-33 yaoyu-33 added area:data Dataset builders, preprocessing, and samplers bug Something isn't working needs-review PR is ready for code review and waiting on a reviewer labels Aug 18, 2026
@yaoyu-33

Copy link
Copy Markdown
Contributor Author

/ok to test 1968bea

@claude

claude Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Light review — LGTM.

The fix is correct and well-scoped. A few notes:

  • The three-way handling of _conversation_contains_boundary_tokens (returns bool | None) via is not False correctly fails closed on both True (payload contains markers) and None (undeterminable), only proceeding on an explicit False. Good defensive design.
  • Failing closed when next_role_start < 0 (next role marker not mapped or not found in the render) correctly reverts to the tokenizer-native mask rather than guessing a boundary.
  • The new branch also fires for the existing tools/thinking four-way cases (nonterminal tool-call assistant turn -> next role tool), so those tests already cover the next-role-start path; the reported 125 passing is consistent with no regression there.
  • Test markers added for <|system|>/<|user|>/<|observation|> line up with the role_start_markers mapping in infer_assistant_mask_boundary_config.

Minor observations (non-blocking):

  • _conversation_contains_boundary_tokens is recomputed once per nonterminal loss turn inside the loop; it is invariant across turns and could be hoisted for long conversations. Not a correctness issue.
  • Coverage gap: the regression test covers thinking-without-tools with truncate_history_thinking=True, but there is no explicit case for tools + truncate_history_thinking=True, which combines the tool-call boundary with history truncation.

Suggested test cases:

  • test_glm_history_thinking_truncation_preserves_historical_answer_loss (added; confirm it fails on unmodified prod code as claimed)
  • A GLM tools + truncate_history_thinking=True variant asserting the historical tool-call assistant answer stays in the loss mask
  • A GLM case where an assistant payload legitimately contains a role-start marker token, asserting fail-closed to the tokenizer-native mask (exercises the is not False path)
  • No perf tests impacted.

@yaoyu-33

Copy link
Copy Markdown
Contributor Author

/ok to test 1968bea

@yaoyu-33

Copy link
Copy Markdown
Contributor Author

/ok to test 7e4721d

@yaoyu-33
yaoyu-33 merged commit 2d3733e into main Aug 20, 2026
86 checks passed
@yaoyu-33
yaoyu-33 deleted the bug-hunter/glm-history-mask-20260818 branch August 20, 2026 00:40

This branch was previously deployed

2 inactive deployments
public — 7e4721df Deployed Aug 19, 2026 by copy-pr-bot[bot] via release / finalize / publish-docs #4730
test — 7e4721df Deployed Aug 18, 2026 by copy-pr-bot[bot] via cicd-wait-in-queue #20705
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:data Dataset builders, preprocessing, and samplers bug Something isn't working needs-review PR is ready for code review and waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant