\input regression-test.tex
\documentclass{article}
\usepackage[palette=muted,startdate=01.07.2026,
  mode=dark,date-format=english,columnsep=3mm,
  columns={Queue,Work,Done}]{kanban-board}
\makeatletter
\edef\kb@packagedateformat{\kanban@dateformat}
\makeatother
% Exercise rejected definitions and selections before log capture.
\kbdefinepalette{empty}{}
\kbdefinepalette{ custom }{red,blue}
\kbset{palette={ custom },mode=LIGHT,date-format=german,
  startdate=2026-07-15,columnsep=1mm}
\kbset{palette=missing}
\kbset{startdate=31.02.2026}
\kbset{columns={}}
\kbset{columnsep=-1mm}
% Redefining the selected palette must update the default for later boards.
\kbdefinepalette{ custom }{green,purple,orange}
\ExplSyntaxOn
\NewDocumentCommand \kbcheckglobalpalette { }
  {
    \int_compare:nNnTF {\clist_count:N \g__kanban_palette_clist} = {3}
      {
        \str_if_eq:eeTF
          {\clist_item:Nn \g__kanban_palette_clist {1}} {green}
          {\TYPE{KANBAN~SELECTED~PALETTE~REFRESHED~OK}}
          {\TYPE{KANBAN~SELECTED~PALETTE~REFRESHED~FAILED}}
      }
      {\TYPE{KANBAN~SELECTED~PALETTE~REFRESHED~FAILED}}
  }
\NewDocumentCommand \kbcheckpackagecolumns { }
  {
    \str_if_eq:eeTF
      {\clist_use:Nn \g__kanban_columns_clist {,}}
      {QUEUE,WORK,DONE}
      {\TYPE{KANBAN~PACKAGE~COLUMNS~OK}}
      {\TYPE{KANBAN~PACKAGE~COLUMNS~FAILED}}
  }
\NewDocumentCommand \kbcheckboardpalette { }
  {
    \int_compare:nNnTF
      {\clist_count:N \l__kanban_board_palette_clist} = {8}
      {\TYPE{KANBAN~BOARD~PALETTE~OVERRIDE~OK}}
      {\TYPE{KANBAN~BOARD~PALETTE~OVERRIDE~FAILED}}
  }
\ExplSyntaxOff
\begin{document}
\sbox0{\scriptsize $x$}% Load math font sizes outside captured output.
\START
\makeatletter
\ifdefstring{\kb@packagedateformat}{english}
  {\TYPE{KANBAN PACKAGE DATE FORMAT OK}}
  {\TYPE{KANBAN PACKAGE DATE FORMAT FAILED}}
\ifdefstring{\kanban@mode}{light}
  {\TYPE{KANBAN SETUP MODE OK}}
  {\TYPE{KANBAN SETUP MODE FAILED}}
\ifdefstring{\kanban@startdate}{2026-07-15}
  {\TYPE{KANBAN SETUP STARTDATE OK}}
  {\TYPE{KANBAN SETUP STARTDATE FAILED}}
\ifdefstring{\kanban@dateformat}{german}
  {\TYPE{KANBAN SETUP DATE FORMAT OK}}
  {\TYPE{KANBAN SETUP DATE FORMAT FAILED}}
\ifdim\kanban@columnsep=1mm
  \TYPE{KANBAN SETUP GAP OK}
\else
  \TYPE{KANBAN SETUP GAP FAILED}
\fi
\makeatother
\kbcheckpackagecolumns
\kbcheckglobalpalette
\begingroup
  % Unknown options and rejected values are reported through named
  % messages. Capture them semantically and keep the key name unexpanded,
  % so a literal variable name in place of the key would be visible.
  \ExplSyntaxOn
  \cs_set_protected:Npn \msg_warning:nn #1#2
    {\TYPE{KANBAN~WARNING:~#2}}
  \cs_set_protected:Npn \msg_warning:nnnn #1#2#3#4
    {\TYPE{KANBAN~WARNING:~#2~#3~'\exp_not:n{#4}'}}
  \ExplSyntaxOff
  \kbset{colour=red}
  \kbset{labels={urgent=NOW}}
  \kbset{palette=missing}
  \kbset{columns={}}
  \kbset{mode=blue}
  \kbset{mode=\emph{dark}}
\endgroup
\begingroup
  % Package options are applied while kanban-board.sty is read. Their
  % diagnostics must name the package options instead of a line inside the
  % package.
  \makeatletter
  \ExplSyntaxOn
  \cs_set_protected:Npn \msg_warning:nnnn #1#2#3#4
    {\TYPE{KANBAN~WARNING:~#2~#3~'#4'~\msg_line_context:}}
  \tl_gset:Nn \g__kanban_package_options_tl {startdate=31.02.2026}
  \kanban@applypackageoptions
  \ExplSyntaxOff
  \makeatother
\endgroup
\makeatletter
\ifdefstring{\kanban@startdate}{2026-07-15}
  {\TYPE{KANBAN PACKAGE OPTION CONTEXT PRESERVES VALUE OK}}
  {\TYPE{KANBAN PACKAGE OPTION CONTEXT PRESERVES VALUE FAILED}}
\makeatother
\begin{kanban}[columns={Todo},palette=default,mode=DaRk,dateformat=iso,
    startdate=01.08.2026,columnsep=4mm]
  \makeatletter
  \ifdefstring{\kanban@boardmode}{dark}
    {\TYPE{KANBAN BOARD MODE OVERRIDE OK}}
    {\TYPE{KANBAN BOARD MODE OVERRIDE FAILED}}
  \ifdefstring{\kanban@thestart}{2026-08-01}
    {\TYPE{KANBAN BOARD STARTDATE OVERRIDE OK}}
    {\TYPE{KANBAN BOARD STARTDATE OVERRIDE FAILED}}
  \ifdefstring{\kanban@boarddateformat}{iso}
    {\TYPE{KANBAN BOARD DATE FORMAT OVERRIDE OK}}
    {\TYPE{KANBAN BOARD DATE FORMAT OVERRIDE FAILED}}
  \ifdim\kanban@boardcolumnsep=4mm
    \TYPE{KANBAN BOARD GAP OVERRIDE OK}
  \else
    \TYPE{KANBAN BOARD GAP OVERRIDE FAILED}
  \fi
  \makeatother
  \kbcheckboardpalette
  \kanbantask{Todo}{Exercise board-local settings}
  \begingroup
    \ExplSyntaxOn
    \cs_set_protected:Npn \msg_warning:nnn #1#2#3
      {\TYPE{KANBAN~WARNING:~#2~'#3'}}
    \ExplSyntaxOff
    \kanbantask[prio=urgent]{Todo}{Exercise priority validation}
  \endgroup
\end{kanban}
\begingroup
  \ExplSyntaxOn
  \cs_set_protected:Npn \msg_warning:nnnn #1#2#3#4
    {\TYPE{KANBAN~WARNING:~#2~#3~'\exp_not:n{#4}'}}
  \ExplSyntaxOff
  \begin{kanban}[columns={Todo},colour=red,labels={urgent=NOW},
      palette=missing,mode=blue]
    \kanbantask[colour=red]{Todo}{Exercise unknown option warnings}
  \end{kanban}
\endgroup
\kbdefinepalette{pair}{red,blue}
\begin{kanban}[columns={One,Two,Three},palette=pair]
  \makeatletter
  \ifcsstring{kanban@color@3}{red}
    {\TYPE{KANBAN PALETTE CYCLING OK}}
    {\TYPE{KANBAN PALETTE CYCLING FAILED}}
  \makeatother
  \kanbantask{Three}{Exercise palette cycling}
\end{kanban}
\makeatletter
\ifdefstring{\kanban@mode}{light}
  {\TYPE{KANBAN BOARD MODE SCOPE OK}}
  {\TYPE{KANBAN BOARD MODE SCOPE FAILED}}
\ifdefstring{\kanban@startdate}{2026-07-15}
  {\TYPE{KANBAN BOARD STARTDATE SCOPE OK}}
  {\TYPE{KANBAN BOARD STARTDATE SCOPE FAILED}}
\ifdefstring{\kanban@dateformat}{german}
  {\TYPE{KANBAN BOARD DATE FORMAT SCOPE OK}}
  {\TYPE{KANBAN BOARD DATE FORMAT SCOPE FAILED}}
\makeatother
\kbcheckglobalpalette
\begingroup
  \makeatletter
  \ExplSyntaxOn
  % Capture the diagnostic semantically: the kernel's l3msg console rendering
  % (wrap point, continuation padding) varies across TeX Live releases.
  \cs_set_protected:Npn \kanban@dimensionwarning #1#2
    {\TYPE{KANBAN~WARNING:~invalid~#1~value~'#2'}}
  \ExplSyntaxOff
  \makeatother
  \begin{kanban}[columns={Todo},columnsep=-2mm]
    \makeatletter
    \ifdim\kanban@boardcolumnsep=1mm
      \TYPE{KANBAN NEGATIVE BOARD GAP PRESERVED OK}
    \else
      \TYPE{KANBAN NEGATIVE BOARD GAP PRESERVED FAILED}
    \fi
    \makeatother
    \kanbantask{Todo}{Exercise rejected board gap}
  \end{kanban}
\endgroup
\begingroup
  \makeatletter
  \ExplSyntaxOn
  \cs_set_protected:Npn \kanban@dimensionwarning #1#2
    {\TYPE{KANBAN~WARNING:~invalid~#1~value~'#2'}}
  \ExplSyntaxOff
  \makeatother
  \begin{kanban}[columns={Todo},columnsep=not-a-length]
    \makeatletter
    \ifdim\kanban@boardcolumnsep=1mm
      \TYPE{KANBAN MALFORMED BOARD GAP PRESERVED OK}
    \else
      \TYPE{KANBAN MALFORMED BOARD GAP PRESERVED FAILED}
    \fi
    \makeatother
    \kanbantask{Todo}{Exercise malformed board gap validation}
  \end{kanban}
\endgroup
\begingroup
  \makeatletter
  \def\PackageError#1#2#3{\TYPE{KANBAN ERROR: #2}}\def\MessageBreak{}
  \makeatother
  \begin{kanban}[columns={One,Two},columnsep=\linewidth]
    \makeatletter
    \ifdim\kanban@boardcolumnsep=0pt
      \TYPE{KANBAN IMPOSSIBLE TOTAL GAP FALLBACK OK}
    \else
      \TYPE{KANBAN IMPOSSIBLE TOTAL GAP FALLBACK FAILED}
    \fi
    \makeatother
    \kanbantask{One}{Exercise impossible total gap validation}
  \end{kanban}
\endgroup
\begin{kanban}[columns={Todo},startdate={}]
  \makeatletter
  \ifdefempty{\kanban@thestart}
    {\TYPE{KANBAN BOARD EMPTY STARTDATE CLEARS LOCAL VALUE OK}}
    {\TYPE{KANBAN BOARD EMPTY STARTDATE CLEARS LOCAL VALUE FAILED}}
  \makeatother
\end{kanban}
\makeatletter
\ifdefstring{\kanban@startdate}{2026-07-15}
  {\TYPE{KANBAN BOARD EMPTY STARTDATE PRESERVES DEFAULT OK}}
  {\TYPE{KANBAN BOARD EMPTY STARTDATE PRESERVES DEFAULT FAILED}}
\makeatother
\kbset{startdate={}}
\makeatletter
\ifdefempty{\kanban@startdate}
  {\TYPE{KANBAN SETUP EMPTY STARTDATE CLEARS DEFAULT OK}}
  {\TYPE{KANBAN SETUP EMPTY STARTDATE CLEARS DEFAULT FAILED}}
\makeatother
\END
\end{document}
