Skip to content

Name the contexts a change cannot survive - #24

Open
phucnht wants to merge 1 commit into
developfrom
feat/context-diagnostics
Open

Name the contexts a change cannot survive#24
phucnht wants to merge 1 commit into
developfrom
feat/context-diagnostics

Conversation

@phucnht

@phucnht phucnht commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Second slice of the roadmap's "Robust and accessible authoring" group, following #23. Measured with 26 probe documents rather than inferred, and two of the measurements changed what the work should be.

What was actually broken

Four constructs aborted compilation with an error from TeX or xcolor that never named this package:

Inside a change Error the user saw Same thing in \textbf Verdict
\verb Argument of \XC@col@rlet has an extra } fails, but says \verb illegal in argument inherited LaTeX limit, worse message
verbatim environment Not allowed in LR mode File ended while scanning use of \@xverbatim inherited, both cryptic
spans an & tab Missing } inserted Argument of \check@nocorr@ has an extra } inherited, both cryptic
\footnote Argument of \XC@col@rlet has an extra } works texchanges-specific

The \textbf column is what decides fault. Three are properties of LaTeX, so the guards name them rather than pretending to fix them.

Two findings that changed the plan

The roadmap item's premise was wrong. It read "unsupported citation contexts", but \cite inside a change compiles, and so do \index, \ref, and a change within a single table cell. Nothing needed fixing there; the roadmap wording is corrected instead.

The README was stale. It still told users to avoid headings, floats and math at a larger boundary, which #23 had already made work. Left alone it would steer people away from working features. Rewritten against the probe results.

The footnote case, traced rather than assumed

Not a regression: the pre-#23 package fails identically. Root cause is \addtocontents carrying a footnote in the report line, reproduced with zero texchanges involved:

\addtocontents{x}{\protect\cmd{text\footnote{n}}}

Writing the text unexpanded does not help, and a report entry has no sensible footnote of its own, so it is diagnosed rather than fixed. The suggested workaround, putting the footnote immediately after the change, was compiled and confirmed to work.

How it is implemented

A local redefinition inside the change's own group intercepts \verb and the verbatim-like environments, so the redefinitions vanish with the group. Feasibility was proven with a standalone probe first, since these failures happen while xparse reads the argument and interception could have been impossible.

Alignment tabs are found by scanning for category code 4 using the same \tl_analysis_map_inline:nn technique \tx_report_text:n already uses. Matching on catcode rather than the character means an escaped \& in ordinary prose does not trip it, which is verified by a probe.

Tests

case_error_fixtures gains a helper asserting a fixture fails and that the log carries the expected message. Asserting only failure would pass even if the old cryptic error returned, since these documents always stopped compilation. The helper joins the log before matching, because TeX wraps at 79 columns and a line-based grep silently misses any message long enough to be useful — which it did on the first attempt.

Verification

Each guard disabled in turn makes its own fixture's assertion fail and no other; restoring passes:

  • no verb guard → verb-in-change assertion fails
  • no alignment scan → alignment-in-change assertion fails
  • no footnote check → footnote-in-change assertion fails

Across the 26 probes from this slice and #23: 21 compile clean, 4 stop with the new diagnostics, 0 broke unexpectedly. \cite, \index, \ref and in-cell changes still compile, so the guards do not over-fire. Full suite green at 23 cases, shellcheck clean, website build green.

Four constructs inside a change aborted compilation with an error from
TeX or xcolor that never mentioned this package, so a user had no way to
tell which construct offended or what to do instead:

  \verb                  Argument of \XC@col@rlet has an extra }
  verbatim environment   Not allowed in LR mode
  spanning an & tab      Missing } inserted
  \footnote              Argument of \XC@col@rlet has an extra }

Each now stops with a message naming the construct and the way around
it. A local redefinition inside the change's own group intercepts \verb
and the verbatim-like environments, so the redefinitions vanish with the
group. Alignment tabs are found by scanning the argument for category
code 4, which is the same \tl_analysis_map_inline:nn technique the
report text already uses; matching on catcode rather than on the
character means an escaped \& in ordinary prose does not trip it.

The first three fail identically inside plain \textbf, so they are
properties of LaTeX rather than defects here, and the guards name them
rather than pretending to fix them.

The footnote case is different and was traced rather than assumed. It is
not a regression: the pre-PR-23 package fails the same way. The cause is
\addtocontents carrying a footnote in the change report line, reproduced
with no part of this package involved:

  \addtocontents{x}{\protect\cmd{text\footnote{n}}}

Writing the text unexpanded does not help, and a report entry has no
sensible footnote of its own, so this is diagnosed rather than fixed.
The suggested workaround, placing the footnote immediately after the
change, was compiled and verified.

Citations were the premise of the roadmap item and turned out not to be
broken at all: \cite, \index, \ref, and a change inside a single table
cell all compile. The roadmap wording is corrected accordingly, and the
README's Limitations section, which still steered users away from
headings, floats and math after PR #23 made those work, is rewritten
against what the probes actually show.

case_error_fixtures gains a helper that asserts a fixture fails *and*
that the log carries the expected message. Asserting only failure would
pass even if the old cryptic error came back, since these documents
always stopped compilation; the message is what distinguishes a
diagnosed context from a crash. The helper joins the log before matching
because TeX wraps it at 79 columns and a line-based grep misses any
message long enough to be useful.

Verified each guard is not vacuous by disabling it in turn: without the
verb guard the verb fixture's assertion fails, without the alignment
scan the alignment fixture's does, without the footnote check the
footnote fixture's does, and no guard's removal disturbs another.
Restoring each passes. Across the 26 probe documents kept from this and
the previous slice, 21 compile clean, 4 stop with the new diagnostics,
and none broke unexpectedly. Full suite green at 23 cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant