From 0c090fa50b44d7b72cfdcd559546167970574246 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Sat, 8 Aug 2026 16:07:34 +1000 Subject: [PATCH] buildsuites: gated-tree repairs manifest + provenance-record pointers Closes the tcllib_checkout honesty gap: a gated tree's shipped content is its checkout PLUS the pkgindex_gate repairs, but no record travelled with the divergence. pkgindex_gate.tcl (both suites, byte-identical) now writes punkbin-upstream-repairs.toml at the gated tree root after both gate checks pass - the applied-repair enumeration ($repaired, sorted), the upstream ticket URL (promoted to data as UPSTREAM_REF), deterministic content only. Both artifact consumers carry the tree verbatim, so the enumeration ships inside every kit and lib zip adjacent to the divergence it explains; no manifest is written on gate failure (fixture-verified both directions). Records point rather than duplicate (single owner = the gate's allowlist; the manifest is written from the post-verification applied set, so it can never drift): library_artifacts.tcl [provenance] gains upstream_repairs = "punkbin-upstream-repairs.toml" when the package folder carries the manifest; build905.zig family records gain tcllib_gated = true with the resolved base/lib/tcllib/ manifest path (build86 emits no family records - covered via the shared tools). Verified: gate fixture with all five recorded defects + clean module (repairs + manifest exact); info-complete on both Tcl tools; zig ast-check + extracted-template compile render proving 18-arg format arity. Cross-suite tool copies byte-identical. No project bump (buildsuite-only). Effect materializes at the r2 rebuild chain - r2 records honest from birth. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- .../suite_tcl86/tools/library_artifacts.tcl | 12 +++++++ .../suite_tcl86/tools/pkgindex_gate.tcl | 31 +++++++++++++++++++ src/buildsuites/suite_tcl90/build905.zig | 8 ++++- .../suite_tcl90/tools/library_artifacts.tcl | 12 +++++++ .../suite_tcl90/tools/pkgindex_gate.tcl | 31 +++++++++++++++++++ 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/buildsuites/suite_tcl86/tools/library_artifacts.tcl b/src/buildsuites/suite_tcl86/tools/library_artifacts.tcl index b2844697..4b9a9da1 100644 --- a/src/buildsuites/suite_tcl86/tools/library_artifacts.tcl +++ b/src/buildsuites/suite_tcl86/tools/library_artifacts.tcl @@ -258,6 +258,13 @@ proc compose_record {ident finished tests} { foreach {n uuid} [dict get $ident provpairs] { lappend m "${n}_checkout = [toml_str $uuid]" } + if {[dict exists $ident upstream_repairs] && [dict get $ident upstream_repairs]} { + lappend m "#the packaged tree is its source checkout PLUS the pkgIndex repairs" + lappend m "#enumerated in the named file at the package folder root (pkgindex_gate" + lappend m "#output - complete by construction: the gate fails the suite build on any" + lappend m "#unrecorded divergence, in both directions)." + lappend m "upstream_repairs = \"punkbin-upstream-repairs.toml\"" + } if {!$emb && [llength $tests]} { lappend m "" lappend m "\[tests\]" @@ -334,6 +341,11 @@ foreach {folder tier license testlibs pkgpath} $opt(-packages) { if {[dict exists $tfacts critcl]} { dict set ident critcl [dict get $tfacts critcl] } + #gated trees (pkgindex_gate) carry a repairs manifest at the folder root - + #record's [provenance] points at it (the zip ships the file itself) + if {[file exists [file join $pkgpath punkbin-upstream-repairs.toml]]} { + dict set ident upstream_repairs 1 + } #stage: mtime-synced copy + embedded record, record mtime pinned to the #package's pkgIndex.tcl (a stable per-install anchor), folder mtime re-synced diff --git a/src/buildsuites/suite_tcl86/tools/pkgindex_gate.tcl b/src/buildsuites/suite_tcl86/tools/pkgindex_gate.tcl index 893e3a63..082c49b8 100644 --- a/src/buildsuites/suite_tcl86/tools/pkgindex_gate.tcl +++ b/src/buildsuites/suite_tcl86/tools/pkgindex_gate.tcl @@ -43,6 +43,9 @@ set ALLOWLIST { {tcl::chan::std version 1.0.2 1.2} {nettool srcfile nexttool.tcl nettool.tcl} } +#upstream report covering the ALLOWLIST records - carried into the repairs +#manifest the gate writes into the gated tree (see the manifest block below). +set UPSTREAM_REF {https://core.tcl-lang.org/tcllib/tktview/523f7e055647611328efa2539717023d18b99ccd} #-------------------------------------------------------------------------------- proc fail {msg} {puts stderr "pkgindex_gate FAIL: $msg"; flush stderr; exit 1} @@ -175,6 +178,34 @@ if {[llength $stale]} { fail "stale ALLOWLIST record(s)" } +#--- repairs manifest: ship the applied-repair enumeration WITH the gated tree +#(punkbin-upstream-repairs.toml at the tree root). The kit-family copy and the +#lib-tier zip carry the tree verbatim, so the enumeration is always physically +#adjacent to the divergence it explains; punkbin-artifact records point here +#rather than duplicating the list. Complete by construction: the gate has +#already failed above unless applied repairs == ALLOWLIST exactly. +#Deterministic content only (no timestamps) - the artifact byte-identity +#contract (no-volatile-fields) applies to the tree this file ships inside. +set mf [list] +lappend mf "#punkbin-upstream-repairs (schema 1) - written by pkgindex_gate.tcl into the" +lappend mf "#gated package tree it ships with. This tree is the upstream source checkout" +lappend mf "#(named by the _checkout field of the accompanying punkbin-artifact" +lappend mf "#record) PLUS exactly the repairs below - complete by construction: the gate" +lappend mf "#FAILS the build on any divergence without a reviewed allowlist record, in" +lappend mf "#both directions (unrecorded defect / record upstream has since fixed)." +lappend mf "#Repair direction is index-follows-file: the sourced file's 'package provide'" +lappend mf "#is the truth; only pkgIndex.tcl declarations are rewritten." +lappend mf "schema = 1" +lappend mf "gate = \"pkgindex_gate\"" +lappend mf "upstream_ref = \"$UPSTREAM_REF\"" +lappend mf "repairs = \[" +foreach r [lsort $repaired] { + lappend mf " \"$r\"," +} +lappend mf "\]" +writefile [file join $outdir punkbin-upstream-repairs.toml] "[join $mf \n]\n" + puts "pkgindex_gate OK: checked $checked indexed loader(s), repaired [llength $repaired]" foreach r $repaired {puts " repaired: $r"} +puts " manifest: punkbin-upstream-repairs.toml ([llength $repaired] repair(s) enumerated)" exit 0 diff --git a/src/buildsuites/suite_tcl90/build905.zig b/src/buildsuites/suite_tcl90/build905.zig index fadb323d..e7db24ff 100644 --- a/src/buildsuites/suite_tcl90/build905.zig +++ b/src/buildsuites/suite_tcl90/build905.zig @@ -2625,8 +2625,14 @@ pub fn build(b: *std.Build) !void { \\cpu_floor = "{s}" \\cpu_model = "{s}" \\{s} + \\#tcllib_checkout names the SOURCE checkout; the shipped tcllib tree is that + \\#checkout PLUS the pkgIndex repairs enumerated in this kit's + \\#base/lib/tcllib{s}/punkbin-upstream-repairs.toml (pkgindex_gate output - + \\#complete by construction: the gate fails the build on any unrecorded + \\#divergence, in both directions). + \\tcllib_gated = true \\ - , .{ artifact_name, fk.variant, fk.working_name, familyrev, build_id, originurl, packager, project, projecturl, tcl_h_patchlevel, piperepl_block, batteries, builtin.zig_version_string, @tagName(optimize), cpu_floor, target.result.cpu.model.name, prov_lines }); + , .{ artifact_name, fk.variant, fk.working_name, familyrev, build_id, originurl, packager, project, projecturl, tcl_h_patchlevel, piperepl_block, batteries, builtin.zig_version_string, @tagName(optimize), cpu_floor, target.result.cpu.model.name, prov_lines, tcllib_ver }); } var family_tree_base: [family_kits.len]std.Build.LazyPath = undefined; diff --git a/src/buildsuites/suite_tcl90/tools/library_artifacts.tcl b/src/buildsuites/suite_tcl90/tools/library_artifacts.tcl index b2844697..4b9a9da1 100644 --- a/src/buildsuites/suite_tcl90/tools/library_artifacts.tcl +++ b/src/buildsuites/suite_tcl90/tools/library_artifacts.tcl @@ -258,6 +258,13 @@ proc compose_record {ident finished tests} { foreach {n uuid} [dict get $ident provpairs] { lappend m "${n}_checkout = [toml_str $uuid]" } + if {[dict exists $ident upstream_repairs] && [dict get $ident upstream_repairs]} { + lappend m "#the packaged tree is its source checkout PLUS the pkgIndex repairs" + lappend m "#enumerated in the named file at the package folder root (pkgindex_gate" + lappend m "#output - complete by construction: the gate fails the suite build on any" + lappend m "#unrecorded divergence, in both directions)." + lappend m "upstream_repairs = \"punkbin-upstream-repairs.toml\"" + } if {!$emb && [llength $tests]} { lappend m "" lappend m "\[tests\]" @@ -334,6 +341,11 @@ foreach {folder tier license testlibs pkgpath} $opt(-packages) { if {[dict exists $tfacts critcl]} { dict set ident critcl [dict get $tfacts critcl] } + #gated trees (pkgindex_gate) carry a repairs manifest at the folder root - + #record's [provenance] points at it (the zip ships the file itself) + if {[file exists [file join $pkgpath punkbin-upstream-repairs.toml]]} { + dict set ident upstream_repairs 1 + } #stage: mtime-synced copy + embedded record, record mtime pinned to the #package's pkgIndex.tcl (a stable per-install anchor), folder mtime re-synced diff --git a/src/buildsuites/suite_tcl90/tools/pkgindex_gate.tcl b/src/buildsuites/suite_tcl90/tools/pkgindex_gate.tcl index 893e3a63..082c49b8 100644 --- a/src/buildsuites/suite_tcl90/tools/pkgindex_gate.tcl +++ b/src/buildsuites/suite_tcl90/tools/pkgindex_gate.tcl @@ -43,6 +43,9 @@ set ALLOWLIST { {tcl::chan::std version 1.0.2 1.2} {nettool srcfile nexttool.tcl nettool.tcl} } +#upstream report covering the ALLOWLIST records - carried into the repairs +#manifest the gate writes into the gated tree (see the manifest block below). +set UPSTREAM_REF {https://core.tcl-lang.org/tcllib/tktview/523f7e055647611328efa2539717023d18b99ccd} #-------------------------------------------------------------------------------- proc fail {msg} {puts stderr "pkgindex_gate FAIL: $msg"; flush stderr; exit 1} @@ -175,6 +178,34 @@ if {[llength $stale]} { fail "stale ALLOWLIST record(s)" } +#--- repairs manifest: ship the applied-repair enumeration WITH the gated tree +#(punkbin-upstream-repairs.toml at the tree root). The kit-family copy and the +#lib-tier zip carry the tree verbatim, so the enumeration is always physically +#adjacent to the divergence it explains; punkbin-artifact records point here +#rather than duplicating the list. Complete by construction: the gate has +#already failed above unless applied repairs == ALLOWLIST exactly. +#Deterministic content only (no timestamps) - the artifact byte-identity +#contract (no-volatile-fields) applies to the tree this file ships inside. +set mf [list] +lappend mf "#punkbin-upstream-repairs (schema 1) - written by pkgindex_gate.tcl into the" +lappend mf "#gated package tree it ships with. This tree is the upstream source checkout" +lappend mf "#(named by the _checkout field of the accompanying punkbin-artifact" +lappend mf "#record) PLUS exactly the repairs below - complete by construction: the gate" +lappend mf "#FAILS the build on any divergence without a reviewed allowlist record, in" +lappend mf "#both directions (unrecorded defect / record upstream has since fixed)." +lappend mf "#Repair direction is index-follows-file: the sourced file's 'package provide'" +lappend mf "#is the truth; only pkgIndex.tcl declarations are rewritten." +lappend mf "schema = 1" +lappend mf "gate = \"pkgindex_gate\"" +lappend mf "upstream_ref = \"$UPSTREAM_REF\"" +lappend mf "repairs = \[" +foreach r [lsort $repaired] { + lappend mf " \"$r\"," +} +lappend mf "\]" +writefile [file join $outdir punkbin-upstream-repairs.toml] "[join $mf \n]\n" + puts "pkgindex_gate OK: checked $checked indexed loader(s), repaired [llength $repaired]" foreach r $repaired {puts " repaired: $r"} +puts " manifest: punkbin-upstream-repairs.toml ([llength $repaired] repair(s) enumerated)" exit 0