# 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::tm` path scan during `package 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::tm::add prepends, head of tcl::tm::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_path` ordering 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 latest` and with alpha/dev versions)? Does the losing form's `package ifneeded` registration linger, and can it resurface via `package forget` + re-require? - How do punk::libunknown and punk::packagepreference each change the answers? (libunknown replaces/wraps the unknown chain; packagepreference overloads `package require` itself - 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.