From c2938e2dcf3c15a929d82815b6efec4d7f343983 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Sun, 9 Aug 2026 01:24:47 +1000 Subject: [PATCH] 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 ::a:::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 --- .../modules/punk/ns/testsuites/ns/nslist.test | 52 +++++++++++++- .../punk/ns/testsuites/ns/nsprimitives.test | 69 ++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/tests/modules/punk/ns/testsuites/ns/nslist.test b/src/tests/modules/punk/ns/testsuites/ns/nslist.test index 8f245ceb..d6075d2e 100644 --- a/src/tests/modules/punk/ns/testsuites/ns/nslist.test +++ b/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}\ diff --git a/src/tests/modules/punk/ns/testsuites/ns/nsprimitives.test b/src/tests/modules/punk/ns/testsuites/ns/nsprimitives.test index dd5afd3f..9795eb8d 100644 --- a/src/tests/modules/punk/ns/testsuites/ns/nsprimitives.test +++ b/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]