Browse Source

tclcore/G-055: correct the parse-field tstr finding - expansion happens in the argdoc defspace, not never

The 0.3.0 record claimed tstr placeholders in non-display fields are not
expanded for plain PUNKARGS definitions. Controlled probes show all
authoring styles (direct define, registered PUNKARGS, argdoc-subns
variable) DO expand parse-field placeholders - the ::after attempt
failed because update_definitions resolves registered definitions in
the argdoc subnamespace whenever one exists, while the harvest variable
had landed in the parent namespace, and an unresolvable param is left
silently literal. Module comment, buildversion changelog line and the
G-055 workflow note corrected; the silent-literal fallback noted in
G-055 as a diagnostic gap (a literal placeholder reaching a parse field
is always an authoring error and could warn).

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 3 days ago
parent
commit
a3d3088b03
  1. 17
      goals/G-055-tclcore-regen-workflow.md
  2. 12
      src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm
  3. 2
      src/modules/punk/args/moduledoc/tclcore-buildversion.txt

17
goals/G-055-tclcore-regen-workflow.md

@ -149,11 +149,18 @@ other commands including the multi-form ::after.
G-074 sanction then covers exactly that id-shaped witness rather than the G-074 sanction then covers exactly that id-shaped witness rather than the
whole form pair. APPLIED 2026-07-13 (tclcore moduledoc 0.3.0, user-directed): whole form pair. APPLIED 2026-07-13 (tclcore moduledoc 0.3.0, user-directed):
both ids typed stringstartswith(<harvested prefix>) via a build-time both ids typed stringstartswith(<harvested prefix>) via a build-time
%AFTERIDPREFIX% string map (note for the workflow: tstr ${...} in %AFTERIDPREFIX% string map. CORRECTED note for the workflow (the first
non-display fields is NOT expanded for plain PUNKARGS definitions - G-046 record of this wrinkle misattributed it): parse-field tstr ${...} IS
defers display fields only; parse-field interpolation needs the explicit expanded for plain registered PUNKARGS definitions - but in the DEFSPACE,
tstr wrap, as ::tcl::string::is does, or a string-map token); parity pins which is the argdoc subnamespace whenever one exists, even when the
in tclcoreparity.test including the accepted dead-id divergence. PUNKARGS list lives in the parent namespace (update_definitions evalns
rule); a variable set in the parent is unresolvable there and the param is
left SILENTLY literal (diagnostic gap - a literal ${...} reaching a parse
field is always an authoring error and could warn). Load-time-computed
values are safest via build-time substitution (explicit tstr wrap as
::tcl::string::is, or a string-map token as ::after) or by setting the
variable in the argdoc namespace. Parity pins in tclcoreparity.test
including the accepted dead-id divergence.
- TIP 746 (user-flagged 2026-07-12, - TIP 746 (user-flagged 2026-07-12,
https://core.tcl-lang.org/tips/doc/trunk/tip/746.md) removes the expr https://core.tcl-lang.org/tips/doc/trunk/tip/746.md) removes the expr
behaviour from lseq operands in Tcl 9.1: the lseq model's number|expr operand behaviour from lseq operands in Tcl 9.1: the lseq model's number|expr operand

12
src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm

@ -4542,10 +4542,14 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
set after_id_prefix $_aip_prefix set after_id_prefix $_aip_prefix
} }
} }
#the %AFTERIDPREFIX% token below is substituted at build time (string map) because #the %AFTERIDPREFIX% token below is substituted at build time (string map; the
#tstr ${...} in non-display fields is not expanded for plain PUNKARGS definitions #%TYPECHOICES% pattern in punk::args' own argdocs is the precedent). A tstr
#(G-046 defers display fields only; the %TYPECHOICES% pattern in punk::args' own #${$after_id_prefix} in the -type field would also work, BUT only if the variable
#argdocs is the precedent) #lives in the DEFSPACE the definition resolves in - for registered PUNKARGS
#definitions that is the argdoc subnamespace whenever one exists (even when the
#PUNKARGS list itself is in the parent, as here), and an unresolvable param is
#left silently literal. Build-time substitution avoids the defspace subtlety
#entirely for load-time-computed values like this harvest.
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
lappend PUNKARGS [list [string map [list %AFTERIDPREFIX% $after_id_prefix] { lappend PUNKARGS [list [string map [list %AFTERIDPREFIX% $after_id_prefix] {
#test of @form #test of @form

2
src/modules/punk/args/moduledoc/tclcore-buildversion.txt

@ -1,5 +1,5 @@
0.3.0 0.3.0
#First line must be a semantic version number #First line must be a semantic version number
#all other lines are ignored. #all other lines are ignored.
#0.3.0 - ::after cancel-id discrimination (user-directed 2026-07-13): the cancelid and info forms' id argument is typed stringstartswith(<prefix>) with the prefix harvested from the RUNNING interpreter at define time (safe create+cancel probe 'after 999999 {}' / 'after cancel $id' - G-054 technique; prefix is after# on 8.6.11 and 9.0.3, hardcoded after#%d in tclTimer.c), substituted into the definition via a build-time %AFTERIDPREFIX% string map (tstr ${...} in non-display fields is not expanded for plain PUNKARGS definitions - G-046 defers display fields only). -typesynopsis id keeps the synopsis rendering as the man page's 'id'. Effect under G-041 form candidacy: 'after cancel <non-id-shaped-word>' resolves cleanly to the cancelscript form matching real semantics (real 'after cancel' with a non-id is a silent script-match no-op), and 'after info <non-id>' is model-rejected where real errors at runtime (parity-true); an id-SHAPED word after cancel remains truthfully ambiguous (cancelid+cancelscript) - real Tcl resolves that junction by id liveness at runtime, which no static type expresses; dead-id over-acceptance on 'after info' recorded as the accepted runtime-liveness boundary. Both ids gain man-page-derived -help text. Parity pins added in tclcoreparity.test (id-shape harvest agreement, cancel discrimination incl the liveness ambiguity, info error-vs-ok parity + accepted dead-id divergence). #0.3.0 - ::after cancel-id discrimination (user-directed 2026-07-13): the cancelid and info forms' id argument is typed stringstartswith(<prefix>) with the prefix harvested from the RUNNING interpreter at define time (safe create+cancel probe 'after 999999 {}' / 'after cancel $id' - G-054 technique; prefix is after# on 8.6.11 and 9.0.3, hardcoded after#%d in tclTimer.c), substituted into the definition via a build-time %AFTERIDPREFIX% string map (CORRECTED finding: parse-field tstr IS expanded for registered PUNKARGS definitions, but in the argdoc subnamespace when one exists - a variable set in the parent namespace is unresolvable there and the param is left silently literal; build-time substitution sidesteps the defspace subtlety). -typesynopsis id keeps the synopsis rendering as the man page's 'id'. Effect under G-041 form candidacy: 'after cancel <non-id-shaped-word>' resolves cleanly to the cancelscript form matching real semantics (real 'after cancel' with a non-id is a silent script-match no-op), and 'after info <non-id>' is model-rejected where real errors at runtime (parity-true); an id-SHAPED word after cancel remains truthfully ambiguous (cancelid+cancelscript) - real Tcl resolves that junction by id liveness at runtime, which no static type expresses; dead-id over-acceptance on 'after info' recorded as the accepted runtime-liveness boundary. Both ids gain man-page-derived -help text. Parity pins added in tclcoreparity.test (id-shape harvest agreement, cancel discrimination incl the liveness ambiguity, info error-vs-ok parity + accepted dead-id divergence).
#0.2.0 - G-054: 'string is' class choices (and the generated per-class virtual docids) are harvested from the RUNNING interpreter at define time instead of a hand-maintained list - a deliberately invalid probe of the builtin yields the authoritative class set from its error message (8.6: 21 classes, no dict; unreleased 8.7: +dict +unicode; 9.0: +dict, unicode removed), fixing accept/reject drift such as the doc wrongly accepting 'string is dict' under 8.6. Hand-written man-page descriptions apply only to classes the runtime accepts (generic label for unrecognized future classes); static version notes on dict (not in 8.6) and unicode (unreleased 8.7 only). Parity pinned by tclcoreparity.test with expectations derived from the live interpreter (green on 8.6.13, 8.7a6, 9.0.3) #0.2.0 - G-054: 'string is' class choices (and the generated per-class virtual docids) are harvested from the RUNNING interpreter at define time instead of a hand-maintained list - a deliberately invalid probe of the builtin yields the authoritative class set from its error message (8.6: 21 classes, no dict; unreleased 8.7: +dict +unicode; 9.0: +dict, unicode removed), fixing accept/reject drift such as the doc wrongly accepting 'string is dict' under 8.6. Hand-written man-page descriptions apply only to classes the runtime accepts (generic label for unrecognized future classes); static version notes on dict (not in 8.6) and unicode (unreleased 8.7 only). Parity pinned by tclcoreparity.test with expectations derived from the live interpreter (green on 8.6.13, 8.7a6, 9.0.3)

Loading…
Cancel
Save