3.9 KiB
G-035 Characterise mixed .tm / pkgIndex.tcl provision of the same package
Status: proposed Scope: src/tests/modules/punk/libunknown/testsuites/ (characterization suite), src/modules/punk/libunknown-0.1.tm and src/modules/punk/packagepreference-999999.0a1.0.tm (as characterised, fixed only if outright bugs surface), src/modules/AGENTS.md + src/lib/AGENTS.md (resulting guidance) Acceptance: as in root GOALS.md index (canonical).
Context
Tcl packages arrive by two registration routes with different machinery:
- .tm modules:
tcl::tmpath scan duringpackage unknown; registration keyed on name-version from the filename; the same-version tie-break rules are now pinned by src/tests/modules/punk/libunknown/testsuites/shadowing/ (2026-07-07): tcl:™️:add prepends, head of tcl:™️:list wins exact-version ties, version beats order, punk::libunknown preserves all of it. - pkgIndex.tcl libraries: auto_path directory scan (tclPkgUnknown)
evaluating index scripts; different scan timing, different overwrite
semantics,
auto_pathordering rather than tm-list ordering.
When the SAME package is provided by both routes - same version or different
versions - the interaction is not well characterised. The user's standing
informal rule (recalled 2026-07-07): avoid mixing .tm and pkgIndex.tcl
provision for one package - unexpected behaviour was observed even after
punk::libunknown's improvements to the unknown-handler chain. That rule is
currently folklore: undocumented, unproven, and untested. Meanwhile the punk
ecosystem genuinely straddles both forms (src/modules .tm trees vs src/lib
pkgIndex libraries; kits carry both; punk::packagepreference overloads
package require on top of the unknown-handler chain), so accidental mixing
is a realistic hazard - and same-version-different-content drift (the
2026-07-06 textblock incident class) would interact with it unpredictably.
Questions the characterisation must answer
- Same name+version via .tm and via pkgIndex.tcl: which registration wins? Is it deterministic, or dependent on which scan ran first (tm scan vs auto_path scan can be triggered in either order by unrelated requires)?
- Different versions across forms: does version selection stay correct
(including under
package prefer latestand with alpha/dev versions)? Does the losing form'spackage ifneededregistration linger, and can it resurface viapackage forget+ re-require? - How do punk::libunknown and punk::packagepreference each change the
answers? (libunknown replaces/wraps the unknown chain; packagepreference
overloads
package requireitself - three layers that can each reorder scans.) - Are there differences across Tcl 8.6 and 9 (tm.tcl and tclPkgUnknown have evolved)?
Approach
- Extend the shadowing suite's child-interp probe pattern: scratch dirs providing the same test package as a .tm and as a pkgIndex.tcl library, all combinations of {same version, tm newer, pkgIndex newer} x {standard scanner, libunknown, packagepreference} x scan-trigger orderings.
- Pin observed behaviour; mark surprising-but-tolerable outcomes with GAP/known-quirk comments (the fossilmove characterization pattern) rather than encoding wishes; anything outright broken is fixed or filed.
- Convert the folklore into documentation: AGENTS.md guidance in src/modules and src/lib stating either the substantiated avoid-mixing rule with its named failure modes, or the conditions under which mixing is safe.
Notes
- Related: the shadowing pin-tests (same suite family - this goal's tests extend them), G-033 (visitor-mode path mixing makes cross-form collisions more reachable: a kit's internal libs vs a visited project's .tm trees), G-026/G-024 (same-version drift provenance), punk::packagepreference 0.1.1 (its moduledoc auto-load hook lives in exactly this machinery).
- Out of scope: redesigning the loading machinery. This goal is characterise-document-and-pin; behavioural changes only for outright bugs.