14 KiB
G-151 punk::args annotated success render (received-args landing report)
Status: achieved 2026-08-05 Scope: src/modules/punk/args-999999.0a1.0.tm (parse-result presentation); src/tests/modules/punk/args/testsuites/args/ Goal: punk::args can render a SUCCESSFUL parse the way arg_error renders a failed one - the usage table (or a compact per-argument report) annotated with where each received word landed: options consumed, values attributed to the argument that took them, received distinguished from defaulted - so dry-run consumers (make.tcl help today; completion/hinting later) present authoritative landing information instead of hand-assembled summaries. Acceptance: given a successful parse result (or the words plus definition id), a punk::args surface renders per-argument received-vs-default annotation covering leaders, opts and values including -multiple aggregation - the canonical demonstration being a flag-like word consumed as a VALUE (the 'punk91 -confirm 0'-as-three-values class) visibly attributed to its consuming argument; failure-side rendering is unchanged (existing arg_error pins pass); the behaviour is pinned in the args testsuite. make.tcl retiring its interim one-line 'dry-run: line accepted ...' report in favour of this render is recorded as consumer follow-through after a bootsupport promotion, not part of this acceptance.
Context
From the G-143 dry-run help sessions (2026-08-01/02 - archived detail file): the failure side has arg_error's annotated tables, but a successful dry-run had nothing showing where the supplied words landed, so make.tcl grew an interim one-line report built from the parse result's 'received' key ('dry-run: line accepted (form build) - action = build | -test = 0 | toolname = punkzip'; before bake kitnames became choice-restricted, the value-swallow clue read 'kitname = punk91 -confirm 0'). The parse result already carries received/leaders/opts/values/multis - this goal is a presentation surface over existing data, at punk::args level where every consumer (and the repl) can share it.
Notes
- Related: G-050 (proposed) - synopsis argument-validity marking; the nearest sibling (status-aware marking over the same argument rows).
- Related: G-044 (proposed) - punk::args-driven completion; landing attribution is the same data completion hints from.
- Related: G-170 (proposed) - consumer: its launcher help dry-run arm renders this goal's landing report for accepted lines (back-pointer added 2026-08-05 with G-170's cross-link; sequencing lean recorded there).
- Related: G-149 (achieved 2026-08-05 - goals/archive/G-149-punkargs-formhint-labels.md) - configurable form-hint labels; sibling punk::args render-surface goal drafted the same session. Its landed shape (caller option on arg_error/usage + @cmd definition key, caller > definition > default precedence) is the plumbing precedent for adding a render option to the same surfaces.
- Overlap survey 2026-08-02: goals_xref paths src/modules/punk/args-999999.0a1.0.tm - the punkargs family as recorded in G-149's survey; G-050 (named above) is the closest surface, the remainder are parser/spec mechanisms.
- Activation survey 2026-08-05 (goals_xref score G-151, per the activation-freshness
rule) - relationships not previously recorded:
- Related: G-166 (proposed) - top unlinked hit: cmdinfo/cmdhelp advisory-parse presentation on the punk::ns side; a sibling presentation surface over parse outcomes and a possible later consumer of this goal's landing report (cmdhelp advisory parses of argument tails).
- Related: G-084 (proposed) - -parsekey completeness. The parse result dict this goal renders from folds aliased optionset keys to their last |-member and -parsekey renames storage keys; the landing report's value-in-effect lookup bridges that fold at display level (see Progress) - G-084 is where the storage-key model itself gets rationalized.
- Related: G-167 (proposed) - back-pointer (G-167 already references this goal): version-delta availability marking renders over the same argument-row surfaces.
- Design leans (user-agreed 2026-08-05, ahead of activation):
- Shape: a COMPACT LANDING TABLE - a separate small arg_error-styled bordered table (Argument | Source | Value) stacked under the usage render in dry-run contexts, NOT annotation of the usage table itself (the help column already dominates width and values are the one input authors cannot bound). The existing -parsedargs row marking and goodchoice word marking stay as-is and compose with it. No per-value/per-arg subtables (the -choices subtables earn their borders as static grouped documentation; received values are transient echo) - the report itself is the one bordered block; if G-088's footer mechanism lands later the same content could dock into the usage table's footer without redesign. Arg-oriented rows in declaration-section order (leaders/opts/values); a word-oriented inverse view (word -> argument) is a possible later -return variant, not the primary.
- Width: deterministic caps, never console-queried (piped contexts + the emit-then-query flush trap of G-007 (achieved - goals/archive/G-007-console-location-transparency.md); pinned tests want deterministic output). Value column capped ~48 for a ~80 total by default; configurable via the G-149 plumbing precedent (caller option > @cmd definition key > default). Machine-facing returns (-return dict) never truncate - elision is display-only.
- Elision is type-aware and always marked (display-hint honesty): strings are single-line-ized (newlines/tabs as visible escapes) then char-capped with trailing '...' plus '(len N)'; lists and -multiple aggregations are element-capped with '(+N more)'; dicts pair-capped with '(+N pairs)'. Pre-elide at data-prep level rather than relying on the textblock table class's per-column -maxwidth (recorded header-truncation TODOs there; and pre-elided strings make the plain twin and test pins trivial).
- The ANSI/grapheme-safe char-level truncate primitive lives in punk::ansi::ansistring (beside trim/RANGE/VIEW, per the ANSI-surgery domain rule); punk::args layers only the element/pair-count elision on top. Precondition (user direction 2026-08-05): before modifying ansistring, survey its test coverage against codebase usage and add missing characterization pins so the modification has a safety net. Survey DONE 2026-08-05 (usage-weighted: VIEW ~250 sites incl 124 '-lf 1'; VIEWSTYLE/VIEWCODES/NEW ~40 interactive sites; RANGE 8): 8 pins added to ansistring.test, green 71/71 on tclsh90+tcl87. Findings the implementation must respect: RANGE re-emits MERGED code stacks (not byte-identical round-trip) and DROPS codes trailing the last grapheme (source TODO) - a truncate building on RANGE must fetch trailing state separately (INDEXCODE end+1 works) if it matters; VIEW -lf 1 is the proven single-line-ization primitive; VIEW silently tolerates unknown option pairs (overtype's '-nul 1' sites depend on this - NUL substitution is actually always-on); VIEWCODES/VIEWSTYLE are broken headless (bare 'a+'/'a' interactive-alias dependency, known-deficiency pinned) - do not route the truncate through the class view paths.
- Serving the failure-side value-truncation todo recorded in the engine ("truncate/summarize values in error messages", args-999999.0a1.0.tm arg_error region) with the same helper is a FOLLOW-ON, not part of this goal's acceptance.
- Row policy: rows only for arguments holding a value post-parse (received, or default-in-effect - the Source column carries the received/default distinction and is the plain-mode-safe twin of the colour marking); absent optionals get no row.
Progress
Achieved 2026-08-05 in one session (user-directed activation and implementation same day; punk::args 0.18.0 + punk::ansi 0.2.0). All six design leans enacted as recorded above.
Mechanism landed:
- New
punk::args::parse_report- the landing report render. Entry forms per the acceptance: a punk::args::parse result dict (its id key resolved via real_id/get_spec; the result's form key selects the displayed form), or<arglist> withid <id>(the parse is performed first; a rejected line raises the same validation error punk::args::parse raises - errorcode parity pinned). Hand-rolled argument processing in the parse/parse_status style (self-parse against the registered two-form definition only on the unhappy path, so a report render never recurses through a second live parse); the registered definition (forms 'parsed'/'withid') follows parse_status's shared-block structure - per-form @leaders first, then the shared @opts, then per-form @values (a shared-then-narrow @leaders ordering is rejected by the resolver: leaders must precede options per form). - Row data rides the existing G-049 machinery: private::parse_status_build -ok 1 -parsedargs supplies per-argument class/received/positions/ hasvalue/value in declaration-section order (leaders, opts, values) - G-151 adds no second status assembler. Display-level bridging recovers the value-in-effect where the build's direct ARG_INFO-name lookup misses the parse result's storage-key folds (-parsekey renames; aliased optionsets stored under their last |-member) so received aliased/parsekey'd arguments keep their row (G-084 owns the storage-key model itself; pinned via the -f|-file fixture).
- Returns: table (arg_error-styled bordered textblock block, title default 'Received', columns Argument | Source | Value; colour bootstrap shares arg_error's CLR base + scheme-override + colour-flip reload pattern), tableobject, string (plain 'name (source) = value' lines; also the degraded no-textblock path), dict (machine form id/form/rows - never elided). Source column: received / received xN / default (CLR(check) / CLR(parsekey_hint) colouring; words stay the plain-mode distinction).
- Elision (lean 3): strings single-line-ized via ansistring VIEW -lf 1 -vt 1 -sp 0 (controls AND embedded ANSI render visibly, so a value cannot disturb the table; real spaces stay real) then grapheme-capped via the new ansistring TRUNCATE with '...' + ' (len N)' (N = raw string length); -multiple/-type list values element-capped with '(+N more)' (whole list-quoted elements while they fit, first element char-capped if it alone overflows); -type dict values pair-capped with '(+N pairs)'; plain-string fallbacks when punk::ansi is unavailable. Width cascade (lean 2, G-149 plumbing precedent): caller -valuewidth > new @cmd directive key -reportvaluewidth (documented in define -help) > built-in 48; 0 = no cap; never console-derived.
- The truncate primitive (lean 4):
ansistring TRUNCATE ?-ellipsis marker? string maxgraphemesin punk::ansi 0.2.0 - fits => byte-identical passthrough (trailing/non-SGR codes included); truncation => RANGE- extracted prefix (merged SGR re-application per the 0.1.4-documented contract) + marker totalling exactly maxgraphemes, with an SGR reset appended before the marker when the prefix carries codes (RANGE re-applies stacks with no trailing reset - the survey finding); marker charged against the budget and itself truncated when it alone meets/exceeds it; grapheme-count based (CJK counts 1/each; column-aware variant recorded as a follow-on). Strict option handling (deliberately unlike VIEW's pinned silent tolerance). Ensemble export + argdoc + doctools added.
Verification evidence:
- New suite src/tests/modules/punk/args/testsuites/args/parsereport.test (13 tests) - the acceptance's canonical demonstration pinned exactly (fixture parse of {build punk95 -confirm 0}: the flag-like word -confirm and its 0 land as VALUES attributed 'args (received x2) = -confirm 0' beside 'kitname (received) = punk95' and '-test (default) = 0'); entry parity, dict shape/row order/row policy, solo+multi multiplicity, elision markers by type, dict-never-elided, width cascade, single-line-ization, alias bridging, bordered/tableobject renders, failure parity, bad-call errors, own-definition render.
- ansistring.test +2 TRUNCATE pins (budget/passthrough/errors; ANSI-reset + CJK + combining-cluster safety).
- Full modules/punk/args subtree 331 passed / 3 pre-existing skips / 0 failed, and modules/punk/ansi subtree 73/73, each on BOTH native tclsh90 (Tcl 9.0.3) and tclsh87 - failure-side rendering unchanged per acceptance (all existing arg_error/usage/synopsis/marking pins pass untouched).
- Minted modules/punk/args-0.18.0.tm + modules/punk/ansi-0.2.0.tm via make.tcl modules.
- make.tcl's interim one-line report (bootsupport punk::args) is untouched until a bootsupport promotion carries 0.18.0 - recorded consumer follow-through below, per the acceptance.
Follow-ons
Follow-on: make.tcl retires its interim one-line 'dry-run: line accepted ...' report in favour of parse_report (stacked under the usage render per lean 1) after a bootsupport promotion carrying punk::args 0.18.0- and punk::ansi 0.2.0- => open Follow-on: serve arg_error's failure-side value-truncation todo ('truncate/summarize values in error messages', args-999999.0a1.0.tm arg_error region) with the same report_display_value/TRUNCATE helpers (lean 5 - explicitly excluded from this goal's acceptance) => landed 2026-08-09 (punk::args 0.26.0 private::error_display_value - all received-word message sites incl unexpected-option words; '@cmd -reportvaluewidth' cascade; raw -badarg/-badval retained; validation.test pins) Follow-on: engine-level rationalization of parse-result storage keys vs definition argument names (aliased optionset last-|-member fold, -parsekey renames) so value-in-effect lookups need no display-level bridging => goal G-084 Follow-on: column-aware (display-width) TRUNCATE variant for CJK-heavy values (the grapheme-count cap under-counts double-wide content; noted in the TRUNCATE argdoc) => open Follow-on: word-oriented inverse view (word -> consuming argument, e.g a -return words variant) as completion/hinting-facing data - lean 1 records it as a possible later variant, not the primary => open