Browse Source

punk/ns tests: 8.6/8.7 leg conditioning (feature probes + divergence pins)

The six 8.6/8.7 failures in nslist.test/nsprimitives.test were
never-green pins (authored 2026-07-14/19, before native-8.6 runner
support existed), not regressions. Three causes, conditioned without
module changes since both module behaviours are documented intent:
- 'info vars' in a namespace context includes globals on pre-TIP-278
  cores: nseval_ifexists_weird pattern-narrowed to 'info vars m*'.
- nstree_raw weird-children recursion: the composed :🅰️::odd string
  form is unresolvable as a fresh string on ALL cores (probed
  8.6.18/8.7a6/9.0.5); the 9 leg passes only because 'namespace
  children' values carry a resolved internal rep that survives the
  recursion. New capability probe weirdns_children_recursable gates the
  literal-listing pin, with a portable plain-tree test and an
  inverse-gated recursion-failure pin.
- get_ns_dicts classification needs ::tcl::info::cmdtype (8.7+): the
  8.6 fallback deliberately returns na for renamed aliases, coroutines
  and native builtins. have_infocmdtype gates the four dependent tests
  (cor tag split out so the other five tag pins keep the 8.6 render
  path covered) and nslist_classification_no_cmdtype_fallback pins the
  divergence.
Verified green: 8.6/8.7/9.0 x -jobs/singleproc, ns subtree 131 total
0 fail (8.6: 5 skip, 8.7/9.0: 2 skip, all by constraint design);
testbody_lint clean.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 day ago
parent
commit
c2938e2dcf
  1. 52
      src/tests/modules/punk/ns/testsuites/ns/nslist.test
  2. 69
      src/tests/modules/punk/ns/testsuites/ns/nsprimitives.test

52
src/tests/modules/punk/ns/testsuites/ns/nslist.test

@ -34,6 +34,14 @@ package require punk::ansi ;#ansistrip in nslist_types_default
namespace eval ::testspace {
namespace import ::tcltest::*
#added 2026-08-09 (agent) - classification depends on ::tcl::info::cmdtype (Tcl 8.7+;
#the same probe punk::ns::cmdtype uses). The pre-8.7 fallback deliberately proves only
#what it can (procs, ensembles, oo, registry-visible aliases, imports) and returns na
#rather than guess ('it is not desirable to do a partial cmdtype support here' - module
#comment), so renamed aliases, coroutines and native builtins are unbucketable there -
#divergence pinned by nslist_classification_no_cmdtype_fallback.
testConstraint have_infocmdtype [expr {[llength [info commands ::tcl::info::cmdtype]] > 0}]
proc mock_console {} {
if {[llength [info commands ::punk::console::get_tabstops]]} {
rename ::punk::console::get_tabstops ::testspace::__orig_get_tabstops
@ -125,6 +133,7 @@ namespace eval ::testspace {
#Tier A ------------------------------------------------------------------
test nslist_classification_buckets {get_ns_dicts classifies each element into its bucket (machine contract for display reworks)}\
-constraints have_infocmdtype\
-setup $fsetup -body {
set d [lindex [punk::ns::get_ns_dicts ::navfix::*] 0]
lappend result [dict get $d location]
@ -161,6 +170,7 @@ namespace eval ::testspace {
]
test nslist_classification_alias_edge_cases {alias overwritten by same-name proc classifies as proc only; alias renamed in-namespace stays a plain als entry}\
-constraints have_infocmdtype\
-setup $fsetup -body {
set d [lindex [punk::ns::get_ns_dicts ::navfix::*] 0]
#maskme: alias registration invisible once a proc took the name
@ -214,6 +224,7 @@ namespace eval ::testspace {
]
test nslist_classification_native_builtin_ns {native bucket populates for a builtin namespace (fixture cannot contain native commands)}\
-constraints have_infocmdtype\
-setup {
set result ""
}\
@ -226,6 +237,30 @@ namespace eval ::testspace {
1
]
#added 2026-08-09 (agent) - the pre-8.7 no-cmdtype fallback's documented divergence
#(see the have_infocmdtype constraint note): what cmdtype cannot prove classifies na -
#present in commands, absent from the specific buckets. Also retains 8.6-leg coverage
#of the maskme pin from the gated alias_edge_cases test (that part is not cmdtype
#dependent). Flip these pins if an 8.6-capable detection ever lands.
test nslist_classification_no_cmdtype_fallback {without info cmdtype (pre-8.7): renamed alias, coroutine and native commands stay unbucketed but remain in commands; proc-masked alias still classifies as proc only}\
-constraints !have_infocmdtype\
-setup $fsetup -body {
set d [lindex [punk::ns::get_ns_dicts ::navfix::*] 0]
lappend result [expr {"nowalias" in [dict get $d commands]}]
lappend result [expr {"nowalias" in [dict get $d aliases]}]
lappend result [expr {"coro" in [dict get $d commands]}]
lappend result [expr {"coro" in [dict get $d coroutines]}]
lappend result [expr {"maskme" in [dict get $d procs]}]
lappend result [expr {"maskme" in [dict get $d aliases]}]
set d2 [lindex [punk::ns::get_ns_dicts ::tcl::mathop::*] 0]
lappend result [expr {"+" in [dict get $d2 commands]}]
lappend result [expr {"+" in [dict get $d2 native]}]
}\
-cleanup $fcleanup\
-result [list\
1 0 1 0 1 0 1 0
]
#Tier B ------------------------------------------------------------------
#Marking semantics located per element - layout agnostic. SGR fragments are
@ -252,6 +287,8 @@ namespace eval ::testspace {
1 1 1 1 0
]
#2026-08-09 Agent-Updated: cor moved to nslist_marking_coroutine_tag - coroutine
#classification needs info cmdtype (8.7+), the remaining tags render on all cores
test nslist_marking_command_type_tags {each command type renders its tag with its designated colour}\
-setup $fsetup -body {
set raw [punk::ns::nslist -types all ::navfix::*]
@ -260,11 +297,24 @@ namespace eval ::testspace {
lappend result [rawhas $raw "[punk::ansi::a+ bold purple]als"]
lappend result [rawhas $raw "[punk::ansi::a+ term-aqua]ooc"]
lappend result [rawhas $raw "[punk::ansi::a+ bold cyan]ooo"]
}\
-cleanup $fcleanup\
-result [list\
1 1 1 1 1
]
#added 2026-08-09 (agent) - split from nslist_marking_command_type_tags: the cor tag
#requires coroutine classification, which needs info cmdtype (see the have_infocmdtype
#constraint note)
test nslist_marking_coroutine_tag {coroutine commands render the cor tag with its designated colour (cmdtype-dependent)}\
-constraints have_infocmdtype\
-setup $fsetup -body {
set raw [punk::ns::nslist -types all ::navfix::*]
lappend result [rawhas $raw "[punk::ansi::a+ term-hotpink]cor"]
}\
-cleanup $fcleanup\
-result [list\
1 1 1 1 1 1
1
]
test nslist_marking_exported_imported {exported commands colour green-bold; imported commands carry the -I marker}\

69
src/tests/modules/punk/ns/testsuites/ns/nsprimitives.test

@ -8,6 +8,21 @@ namespace eval ::testspace {
set result ""
}
#added 2026-08-09 (agent) - the composed string form of a 'weird' child namespace
#(child literally named :odd -> displayed ::parent:::odd) is NOT resolvable by core
#namespace commands on ANY current core when handed over as a fresh string (extra
#colons are absorbed: probed 8.6.18/8.7a6/9.0.5 all agree - 'namespace exists' 0,
#'namespace children' errors; punk::ns's own string parsing - e.g nsexists,
#nseval_ifexists - handles such names on all cores). nstree_rawlist's recursion into
#weird children nevertheless works on Tcl 9 because the values 'namespace children'
#returns carry a resolved internal rep that survives the recursion; 8.6/8.7 re-parse
#the string form and die. Probe the capability directly rather than a core version -
#it gates the literal weird-children listing pin, and its inverse gates the
#recursion-failure divergence pin.
namespace eval ::punknstest_probe {namespace eval {:x} {}}
testConstraint weirdns_children_recursable [expr {![catch {punk::ns::nstree_raw ::punknstest_probe}]}]
namespace delete ::punknstest_probe
#added 2026-07-14 (agent) - characterization pins for the punk::ns name/path string primitives and eval variants, coverage precondition for the punk::ns hygiene pass
#The primitive region of punk::ns contained variant/deprecated twins (nsparts1, nsprefix1, nsprefix_orig, nstail1, nstail_orig).
#This file originally also pinned their divergence from the live primitives (they collapsed long colon runs differently);
@ -225,7 +240,10 @@ namespace eval ::testspace {
lappend result [namespace children ::punknstest_w]
lappend result [punk::ns::nschildren ::punknstest_w]
lappend result [punk::ns::nseval_ifexists ::punknstest_w:::odd {set marker}]
lappend result [punk::ns::nseval_ifexists ::punknstest_w:::odd {info vars}]
#2026-08-09 Agent-Updated: pattern-narrowed from bare 'info vars' - pre-TIP-278
#cores (8.6/8.7) include global variables in a namespace context's 'info vars',
#so the bare form is not portable; m* still pins that the script ran in the weird ns
lappend result [punk::ns::nseval_ifexists ::punknstest_w:::odd {info vars m*}]
lappend result [catch {punk::ns::nseval_ifexists ::punknstest_w:::odd {error boom}} emsg] $emsg
lappend result [punk::ns::nseval_ifexists ::punknstest_w:::nope {set marker}]
lappend result [namespace eval ::punknstest_w {namespace exists {:nope}}] ;# 0 - not created
@ -286,7 +304,14 @@ namespace eval ::testspace {
::punknstest_c::a::g
]
#2026-08-09 Agent-Updated: gated to cores where nstree_rawlist's recursion survives
#weird children (see the weirdns_children_recursable probe above - Tcl 9 today, via
#internal-rep survival; 8.6/8.7 die re-parsing the composed name). nstree_raw is
#deliberately 'raw - no weird ns consideration' (module comment). Portable coverage:
#nstree_raw_plain_pins; divergence: nstree_raw_weird_children_norecurse - flip that pin
#back into this test if segmentwise descent is ever added to nstree_rawlist.
test nstree_raw_pins {nstree_raw requires a fully qualified ns and lists weird children literally}\
-constraints weirdns_children_recursable\
-setup {
set result ""
namespace eval ::punknstest_t {
@ -306,6 +331,48 @@ namespace eval ::testspace {
{::punknstest_t ::punknstest_t:::odd ::punknstest_t::sub}
]
#added 2026-08-09 (agent) - portable nstree_raw coverage + the pre-9 weird-child
#divergence pin, split from nstree_raw_pins when the native 8.6/8.7 runner legs were
#first exercised (they were never green for this file before 2026-08-09).
test nstree_raw_plain_pins {nstree_raw requires a fully qualified ns and lists a plain tree recursively}\
-setup {
set result ""
namespace eval ::punknstest_tp {
namespace eval sub {namespace eval deeper {}}
}
}\
-body {
lappend result [catch {punk::ns::nstree_raw punknstest_tp} emsg] $emsg
lappend result [lsort [punk::ns::nstree_raw ::punknstest_tp]]
}\
-cleanup {
catch {namespace delete ::punknstest_tp}
}\
-result [list\
1 {nstree_raw requires a fully qualified namespace}\
{::punknstest_tp ::punknstest_tp::sub ::punknstest_tp::sub::deeper}
]
test nstree_raw_weird_children_norecurse {nstree_raw recursion dies on a weird child where the core re-parses the composed name form (documented raw/no-weird-consideration contract; 8.6/8.7 today)}\
-constraints !weirdns_children_recursable\
-setup {
set result ""
namespace eval ::punknstest_t {
namespace eval sub {}
namespace eval {:odd} {}
}
}\
-body {
lappend result [catch {punk::ns::nstree_raw ::punknstest_t} emsg]
lappend result $emsg
}\
-cleanup {
catch {namespace delete ::punknstest_t}
}\
-result [list\
1 {namespace "::punknstest_t:::odd" not found}
]
test globmatchns_pins {globmatchns - * matches within a level (including a single inner colon) but not across ::, ** crosses levels, ? matches one non-colon char}\
-setup $common -body {
lappend result [punk::ns::globmatchns ::a::* ::a::b]

Loading…
Cancel
Save