Build as keel-fab, with a version this project chose #9
No reviewers
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Keel-Linux/fab!9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "pkg/keel-fab"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #8. It also closes #7, in the same pull request rather than a separate one: #7 asks for a changelog entry that makes the running version exist in git, for the
require-changelogwiring, and for provenance checkable from a manifest and a git tag. The first is already true and was true before #7 was filed (below); the other two are here. There is nothing left in #7 that this does not do, and the constraint is one pull request per repository.What
1.1.1+keel2actually is, measured before anything was writtenThe installed package on the build host is byte for byte
/root/src/fab/../fab_1.1.1+keel2_all.deb, sha2561b8ee5bcc2a9e91596f521abe561f4c69a4c1b92e1ee014d952eabd8b6186adf, built there on 2026-09-27 at 17:14:56 UTC./var/lib/dpkg/info/fab.md5sumsis identical to the.deb's ownmd5sums, anddpkg -V fabis clean.It was built from
/root/src/fabat commite610377with a clean worktree. Every file it ships is in git. Comparing the extracted.debagainst that checkout, file by file: 22 of 25 byte identical, and the three that differ (/usr/bin/fab,share/make-release-deb.py,share/turnkey-version.py) differ only indh_python3's shebang normalisation,#!/usr/bin/python3to#! /usr/bin/python3.product.mkisa06bfe03, as #7 records. There is nothing in the running fab that is not in this repository.And the changelog entry exists.
e610377is debian: changelog 1.1.1+keel2, the unit slots the build host needs, and it merged tomasteras #6 at 2026-09-27T19:58:53Z, ten hours before #7 was filed at 2026-09-28T06:06:20Z.git log --oneline -- debian/changelogonmastertoday returns two commits, not one. The measurement in #7 read a stale ref: in the build host cloneHEADise610377, butremotes/origin/masteris16730a5, the #5 merge, because the clone had not fetched since before #6.So the defect is not the one #7 describes, and it is worse in one respect and better in another:
1.1.1+keel2appears nowhere in the historymaster, merged in #6 before #7 was filedshare/product.mk, a path this package shipsgit tag -lcarried only upstream'sv0.5..v1.1.1The last row is what was actually unfixed, and it is why
core.manifest'sfab_version 1.1.1+keel1named no commit. Two annotated tags now exist, pushed ahead of this branch so the new check passes:fab/1.1.1+keel1onb07a733andfab/1.1.1+keel2one610377, each recording what was built from it and that it was tagged after the fact.One unrelated finding, for whoever owns
docs/build-host.md: it records the+keel1.debas sha256f4bf09be9535…, and the file on the host and its own.changesboth say1dc54a20acc2….The shape, and why
The package becomes
keel-fabat2.0.0. The repository staysfab. Decision 0006 rules on repository names, and infrastructure keeps its upstream name; this renames the Debian package, which is a different axis, and the fork, its history and its upstream compatibility are untouched. No+keelN.2.0.0and not0.1.0, and the changelog gate is what settled it.0.1.0was proposed first, matching the scheme every package this project owns already starts at:keel0.1.0,keel-transition0.1.0,keel-archive-keyring0.1.0. The gate wired up in this same branch refused it on its first run, which is the first thing it has ever caught here.dpkg --compare-versions 0.1.0 gt 1.1.1+keel2is false;require-changelogcompares the proposed top version against the base's exactly that way,repreproanddpkg-genchangesread a changelog as one monotonic series too, anddpkg-genchangeswas already warning on the 0.1.0 build. A rename does not give the changelog a fresh start. The reset was the wrong signal as well: the other Keel packages start at 0.1.0 because they had no predecessor, while this code has been building every layer in production since before it was ours.2.0.0sorts above every upstream 1.x and both+keelNbuilds, carries no suffix, and says what happened.tests/packaging.shnow asserts the ordering with that measurement in the comment.The apt tooling agrees without being changed, which is the strongest argument for the name.
apt/lib/build.shclassifies a package as native when theSourcestarts withkeel, the clone has noupstreamremote, and neitherdebian/watchnordebian/upstream/metadataexists. This clone has noupstreamremote and neither file, so all three now hold andbin/build-packagewill accept0.1.0on its own. The+keelNguard correctly stops applying instead of having to be overridden with--native.Provides: fab,Conflicts: fab,Replaces: fab, all unversioned.apt-cache rdepends fabon the build host is empty and nodebian/controlin the organization depends onfab, soProvidessatisfies nothing here. It does not protect an install by name: apt prefers a realfabin an enabled archive (TurnKey's, at 999 on the build host) and removeskeel-fabfor it, and a fab plan cannot resolve a virtual name at all (tkldev#4). What protects the host is the negative pinPackage: fab/Pin: release o=turnkeylinux/Pin-Priority: -1(notPin: origin "", which only matches a local repository), which makes apt#15 a prerequisite of the conversion.ConflictsandReplacesare the load-bearing pair: the two packages ship the same paths and must never be co-installed. A versionedProvides: fab (= 1.1.1+keel2)was considered and rejected: it would satisfy a versioned dependency onfab, of which there are none anywhere, at the cost of writing upstream's version number back into a package whose point is not to carry it.The call sites decide the command names, and they say keep them
Counted across the organization (about 700 references, measured in review over 40 repositories; the first count was 10 to 20 percent lower), and not one of them reads the Debian package name: they are
$PATHcommand lookups, make variables and filesystem paths, and Debian imposes no relation between a package's name and the paths it ships.fab-chrootPATHfab-apply-overlayPATHfab-plan-resolvePATHfab-apply-removelistPATHfab-apply-patch,fab-install,fab-cpp,fab-query,fab-plan-annotatePATHfab-investigate,fab-rewindPATHFAB_PATH/turnkey/fab-keelFAB_ARCH$(FAB_PATH)/common/usr/share/fabFAB_SHARE_PATHimport fabfablib, and always wasSo every command name, every path and the
fablibmodule stay exactly as they are. Renaming the binaries is a much larger change and is not in here. The nine/usr/bin/fab-*aliases are each asserted separately intests/packaging.sh, because the one thing a rename really does break isdebian/fab.install,debian/fab.linksanddebian/fab.docs: debhelper keys them on the binary package name, and a rename that leaves them behind builds a package with no/usr/bin/fab*and no/usr/share/fabwhile saying nothing, with the failure surfacing at the firstfab-chrootof the next build.Nine sites do read the package name. Eight are listed under "not in this pull request" below. The ninth was inside this repository and is fixed here:
fab --versionranapt-cache policy fab, which asks about whatever package is calledfabon the machine rather than about itself. After this rename it would answer(none), measured on the build host against a real virtual package.bt-layer:214writes that answer into every layer manifest asfab_version, so it would have written(none)into the provenance record of every image built afterwards.debian/rulesnow records the changelog version at/usr/share/fab/versionandfablib/version.pyreads it back, which is also the right answer on a host that installed a.debfrom a file and has no archive entry either way.Which fab built this layer, in both directions
A manifest records the builder as a version string and nothing else, so the string is provenance only if it resolves to a commit.
fab_version 1.1.1+keel1becomesgit rev-parse fab/1.1.1+keel1.bin/check-release-tagsmakes that total: every changelog entry whose distribution is notUNRELEASEDis a release, and every release below the newest must have a tag<source>/<version>whose tree carries that version at the top of its changelog. The newest entry is exempt, being the release a pull request is proposing. The source name comes from the entry, so the two versions released before the rename are checked asfab/…and notkeel-fab/….git describe --match '*/*'on a commit names its release, and that tag's changelog gives the version a manifest would record. No new machinery.Recording a commit in the manifest as well is worth doing, and is not needed now.
keelalready keeps any manifest key it does not know and writes it back unchanged (keel/docs/layers.md, "Optional fields"), so afab_commitfield costs one line atbt-layer:214and nothing at all inkeel. What it buys over the tag is the case the tag cannot cover: a.debbuilt from an untagged or dirty tree, which is exactly what happened on 2026-09-27. The tag invariant closes that procedurally and the CI job keeps it closed, sofab_commitis belt and braces rather than a prerequisite. It is abuildtaskschange, so it is a second pull request in that repository, and it is filed as Keel-Linux/buildtasks#12 rather than bundled here.Converting the build host, and the way back
Nothing was built, installed or changed on the build host. Access there was read only throughout, no lock was taken, and no layer was published or rebuilt. The package was built in a throwaway
debian:trixiecontainer to provedebian/rulesworks and to compare the result against what the host runs.The conversion is one command and is reversible, because
fab_1.1.1+keel2_all.debstays in/root/srcand nothing deletes it:Verify after either direction with
fab --version,dpkg -L keel-fab | grep /usr/bin, and onefab-chrootin a scratch tree.Two things to know before scheduling it.
/etc/apt/preferences.d/keel-fabpinsPackage: fab/Pin: version 1.1.1+keel1*, and the installed version is1.1.1+keel2, so that pin matches nothing today and only Debian version ordering is keeping the local build in place over upstream's1.1.1at priority 999; it needs fixing whether or not this lands. Anddocs/build-host.mdsections 2 and 3 describe the package and the pin and will need the new name.Measured
126 of 126, 100 percent. The gate stays at 100. The TAP helpers moved to
tests/tap.shwhen the third suite wanted them; the handbook records copying a test library instead of sharing it as something this project did wrong and would do again unless written down.What no assertion about
debian/can prove is that the built package is the same package, so that was measured, over the full file set.keel-fab 2.0.0against thefab 1.1.1+keel2installed on the build host: 35 entries old, 37 new; 27 at the same path, 26 byte identical (all nine/usr/bin/fab-*symlinks andshare/product.mkamong them;/usr/bin/fabdiffers by theget_versionchange alone); 8 renamed by debhelper keying on the package name (fourdist-infofiles, three underusr/share/doc,runtime.d/fab.rtupdate); 2 new,fablib/version.pyand/usr/share/fab/version. Nothing dropped, anddpkg-genchangesno longer warns.That comparison is also what caught the one real regression in this change, which no reading of
debian/would have.dh_python3finds a private python directory by the binary package name, so while the package was calledfabit picked up/usr/share/fabon its own; renaming it silently dropped the byte-compilation registration and the shebang rewrite. Naming the directory fixes that, but a single call with an argument replaces the default pass rather than adding to it, and the default pass is what movesfabliboff/usr/lib/python3.13/dist-packagesonto the version independent/usr/lib/python3/dist-packages, so one call trades one silent divergence for a worse one. All three variants were built and compared; both calls are needed, anddebian/rulessays why.Not in this pull request, deliberately
Each is a different repository, so each is its own issue and its own pull request.
apt(#15)fababove. 4 package-name reads intests/build-package.bats(:56,:192-194),docs/layout.mdpool path, and the native classification depending on there being noupstreamremote.buildtasks(#12)fab_commitin the manifest atbt-layer:214. Also the deadbt-img:113-118gate, which assumes afab_<ver>_all.debfilename.tkldev(#4)tkldev-setup:372installsfabby name, whichProvidesdoes not protect (see above);plan/main:3names it in a fab plan, which cannot resolve a virtual package and drops it silently. Before the archive ever dropsfab.handbookdocs/infra-recovery.md:96installsfabby name;docs/build-host.mdsections 2 to 4. At conversion time.bootstrapREADME.rst:32listsfabas a dependency;Makefile:41checks for the command, which is unaffected.require-changelog,keel-coreamong them. Audited in Keel-Linux/tracker#18, since it is common to the whole organization.handbook(#18)docs/build-host.mdsections 2 and 3 at conversion time.Test plan
tests/coverage.sh 100.shellcheck -xclean on every file this branch adds or touches. The remaining findings intests/regtest.shandtests/override.share upstream's and untouched.debian:trixiecontainer and its contents were compared against the.debinstalled on the build host, path set and byte content.bin/check-release-tagspasses on this branch, withfab/1.1.1+keel1andfab/1.1.1+keel2pushed.package / changelog,release-tagsandtests / coverageall green. The first two ran here for the first time, andpackage / changelogearned its keep immediately by refusing0.1.0.keel-faband2.0.0, and schedules the conversion. Handbook decision note 0017 (Keel-Linux/handbook#18) carries the reasoning.Review of #9
Read-only throughout: nothing was built, installed or changed on the build host, no lock was taken. The package was built independently in a throwaway
debian:trixiecontainer, and the apt behaviour below was measured in a second container rather than on the host.First, the thing #7 got wrong
Confirmed, and the correction in this pull request is the right outcome.
e610377is "debian: changelog 1.1.1+keel2", it is an ancestor ofmaster, and it merged as #6 at2026-09-27T19:58:53Z. #7 was filed at2026-09-28T06:06:20Z.git log --oneline origin/master -- debian/changelogreturns two commits.The cause is one step more specific than "the build host's own
master". On the host,/root/src/fabis on local branchpkg/keel2ate610377with a clean worktree, andgit log -- debian/changelogthere, at HEAD, already returns both commits. What is stale is the remote-tracking ref:remotes/origin/masteron that host is16730a5, the #5 merge, so the host has not fetched since before #6 landed.masteris858d193,behind 4of a staleorigin/masterand behind 6 of the real one. A measurement taken againstorigin/masterin that clone produces exactly the line #7 reports.The
1.1.1+keel2installed tree claim also reproduces, exactly, and by a stronger method than file counting. Of the 18 paths the installed package takes from git, 15 are byte identical toe610377, and for the three that are not, re-applying only the shebang normalisation reproduces the installed md5sums:sha256 1b8ee5bc…on/root/src/fab_1.1.1+keel2_all.debmatches,dpkg -V fabis clean, and both annotated tags point where the body says. Tagging after the fact is the honest thing here and the annotations say so in the tag message, which is the right place for it. Nothing running on the build host is outside this repository.Everything below is about what the change does next, ordered by severity.
HIGH 1.
Provides: fabdoes not protect the build host. Measured.debian/control:28, and the body's row "tkldev| Both are satisfied byProvides: fab, so neither is urgent".apt prefers a real package over a virtual provider. The build host has a real
fabin an enabled archive:Reproduced in a container with
keel-fab 2.0.0installed from a file at 100 and a realfabin an archive at 999:Same result when upstream's real
fabis3.0.0, abovekeel-fab 2.0.0. So after the conversion, onetkldev-setuprun, or one run of the disaster-recovery procedure inhandbook/docs/infra-recovery.md:96, silently replaces the builder with upstream's fab, losing theSOURCE_DATE_EPOCHhandling and the unit phases, and the next build is wrong rather than broken.apt-get upgradeanddist-upgradeare safe: nothing depends onfab, so nothing pulls it in unattended.What closes it, also measured:
With that in place
apt-get install fabcorrectly answers "keel-fab is already the newest version".This makes apt#15 a prerequisite of the conversion, not an independent follow-up. Its current text asks for the
fabstanza to be widened and then renamed; it does not ask for upstream's realfabto be made unselectable, and that is the part the rename creates. apt#15 also still says the new stanza should pin0.*, which was written before2.0.0.HIGH 2.
tkldev/plan/main:3is not satisfied byProvides:either, and fails silentlySame body row. This one is not an apt question at all.
tkldev/Makefileisinclude $(FAB_PATH)/common/mk/turnkey.mk, soplan/maingoes throughfab-plan-resolve, and fab's own resolver does not resolve virtual packages:fablib/plan.py:205-206takes the pool's answer and doespackage_name = fname.split("_")[0], thenself._deps[deps[package_name]]. The.debfilename's first field must be string-equal to the requested name. Akeel-fab_2.0.0_all.debreturned for a request offabraises an uncaughtKeyError._get_provided(plan.py:329) readsProvidesonly from packages already fetched, andprovidedis only subtracted fromall_missingatplan.py:406. It never causes a provider to be fetched.And the miss is silent:
missingis initialised atplan.py:366and never mutated, whilebrokendepsis built by iterating it atplan.py:421-422, soresolve()returns(spec, [])even whenall_missingis non-empty. A plan entry the pool cannot supply is dropped from the spec with no error.That is upstream code and not this pull request's doing, so it is not a blocker for the diff. But it means the deferral rationale is wrong for this site, and it is latent rather than immediate only because
apt/pool/main/f/fab/fab_1.1.1+keel1_all.debis still in the archive: TKLDev images built after the conversion would keep shipping the pre-rename fab while the build host runskeel-fab, and the dayfableaves the pool they would ship no fab at all without saying so.plan/main:3needs to becomekeel-fab, and it needs its own issue before the conversion, not after.HIGH 3. The newest release is exempt forever, which is #7's hole one version deep
bin/check-release-tags:95-105.The exemption is right for a pull request. The problem is that nothing ever revokes it.
release-tagshas noif:, so it does run onpush: branches: [master], but the script exempts the newest entry there too. Sokeel-fab 2.0.0merges with the check green, gets built, gets installed on the host, andbt-layer:214writesfab_version 2.0.0into every manifest, whilegit rev-parse keel-fab/2.0.0fails, until somebody adds the next changelog entry. That is exactly the state #7 was filed about.Two ways to close it, either is fine:
push: masterrun require the newest release to be tagged, for examplebin/check-release-tags --require-newest, and push the tag with the merge as was done forfab/1.1.1+keel1andfab/1.1.1+keel2; orbin/build-package: refuse to build a.debwhose top changelog version has no tag. The untagged.debon 2026-09-27 was produced by a build, not by a merge.There is also a bypass worth knowing about: an
UNRELEASEDentry on top keeps the newest released entry exempt, becauseproposedis set from the first non-UNRELEASEDentry. Verified:HIGH 4. The gate accepts a lightweight tag on a commit that is not in the branch
bin/check-release-tags:59-61and:107-120.has_tagonly checksrefs/tags/<name>exists, andtag_versiononly compares the first line of that tree's changelog. Nothing checks the tag is annotated, and nothing checks it is reachable. Demonstrated on a scratch repository: two lightweight tags on an orphan branch whose commits contain entirely different content pass the gate.The annotated part is not cosmetic. The note's other direction,
git describe --match '*/*', only sees annotated tags:So the two halves of the "in both directions" invariant are enforced to different standards, and the half that CI checks is the weaker one. Two lines fix it:
The tags actually pushed are annotated and on
master, so this is about what the rule permits next time, not about what is there now.tests/release-tags.shcurrently locks the looser behaviour in, because every fixture usesgit tag "$2".MEDIUM 5.
fab --versioncan still write a wrongfab_version, throughFAB_SHARE_PATHfablib/version.py:22-24.share_path()honoursFAB_SHARE_PATH. Nothing else infaborfablibreads that variable any more; its only other life is as a make variable,share/product.mk:60andcommon/mk/turnkey.mk:26, both?=and neither exported, so a normalbt-layerrun is fine and I could not make it misfire. But an exportedFAB_SHARE_PATHpointing at a checkout, which is a plausible thing for someone debugging fab to do, makespackage_version()returnunknown,fab --versionprint it and exit 0, andbt-layer:214writefab_version unknowninto the manifest.bt-layercannot catch it either:fab_version "$(fab --version)"is a command substitution in an argument list, so even a non-zero exit is discarded underset -e.Given the stated premise that a wrong provenance record is worse than none, the test override wants to be its own variable, say
FAB_VERSION_FILE, so that nothing a build environment sets can redirect the version lookup. Making--versionexit non-zero onunknownis worth doing too, but only helps once buildtasks#12 reads the status.The rest of that path is sound. I built the package and
/usr/share/fab/versioncontains exactly2.0.0,package_version()returns'2.0.0', and the file can never be empty becauseread_text().strip() or UNKNOWNcovers it.override_dh_installwriting into a directorydh_installmust have created means a missing directory is a loud build failure, not a silent empty file, which is the right way round.MEDIUM 6. The "28 paths, 26 byte identical" measurement excludes 7 files without saying so
I rebuilt the package and compared it against the
fab 1.1.1+keel2installed on the host. The substantive claims all hold, and thedh_python3finding is real and well handled:make-release-deb.pyandturnkey-version.pycome out byte identical to the installed ones,runtime.d/keel-fab.rtupdateis present, andfabliblands in/usr/lib/python3/dist-packagesrather thanpython3.13, which is the three-way result the two calls were for.The arithmetic is not reproducible as written. The old package ships 26 regular files plus 9 symlinks. 28 reconstructs only as 19 files plus 9 symlinks, that is, with the 4
dist-infofiles and the 3usr/share/doc/fab/files dropped. All three things the summary does not mention live in that dropped set:usr/share/doc/fab/becomesusr/share/doc/keel-fab/, so three paths the old package had are not present under their old names. Nothing in the organization reads that path, so the impact is nil, but "all 28 paths the old package had are present" is not what happened.changelog.gzdiffers,115f2f5cto20760196. It is a third differing file, not two.usr/lib/python3/dist-packages/fab-1.1.0.dist-info/is unchanged, stillfab, still1.1.0.Also
usr/share/python3/runtime.d/fab.rtupdatebecomeskeel-fab.rtupdate, which the body covers with a glob rather than calling it a rename.Restating it as "35 entries in the old package, 32 byte identical, 3 renamed by debhelper, 2 new" would be both truer and stronger.
MEDIUM 7.
pyproject.tomlis untouched, so there are now three version sourcespyproject.toml:7-8keepsname = "fab",version = "1.1.0".importlib.metadata.version("fab")on the built package returns1.1.0while dpkg sayskeel-fab 2.0.0and/usr/share/fab/versionsays2.0.0. Keeping it frozen is probably deliberate, since it is what keeps the fourdist-infofiles byte identical, but nothing says so, and the next person to "fix" version reporting will reach forimportlib.metadataand get1.1.0. One comment inpyproject.tomlor indebian/rulessettles it.MEDIUM 8. The native classification depends on there being no
upstreamremote, and 0008 invites oneapt/lib/build.sh:83. The argument for the name is that all three native conditions now hold, and one of them isgit -C "$dir" remote | grep -qx upstream. Decision 0008 keeps the fork upstream compatible with cherry-picks in both directions, and the ordinary way to cherry-pick from upstream isgit remote add upstream. Whoever does that on the build host clone makesbin/build-packageclassifykeel-fabas a rebuild and refuse2.0.0for lacking+keelN. Neither this pull request nor apt#15 mentions it. It wants either a note inapt/lib/build.shor a condition that does not depend on a local remote name.MEDIUM 9.
bin/check-release-tagshas no floorEvery non-
UNRELEASEDentry below the newest is a release, with no lower bound. It passes today only because the changelog has four entries and the oldest, upstream'sfab (1.1.1), isUNRELEASED. If a future merge from upstream brings real upstream entries into the file, the job demandsfab/1.1.0,fab/1.0.3and so on forever, and upstream's tags arev1.1.0,v1.0.3. A floor, or a--since, costs a line.Related, smaller: a version with an epoch can never satisfy the rule, because
refs/tags/keel-fab/1:2.0.0is not a legal refname. Worth a line in the header given the note proposes this rule for the other repositories.MEDIUM 10. The call-site inventory misses two live sites and understates one scope
The central negative claim is sound and I reproduced it independently across all 40 repositories in the organization: no
debian/controlanywhere depends onfab,import fabis genuinely zero, no recipe Makefile, no shared makefile incommonand nothing inkeel,keel-coreorbuildtasksreads the package name. buildtasks and the 22 recipe Makefiles need no edit. Missing from the table of nine:handbook/docs/infra-recovery.md:96:apt-get install -y fab deck pool turnkey-chroot …, the documented rebuild-from-a-fresh-Debian procedure. This is the one that combines with HIGH 1: it installs upstream's fab on a recovered host.apt/lib/build.sh:112,118:build_archive_versionpasses the repository name toapt-cache policy. That is the same bug this pull request just fixed infab --version. It is an error-path hint only, so nothing breaks, but it belongs in the row.docs/build-host.md"sections 2 and 3". Section 4, "Rebuilding and reinstalling fab", lines 88-111, is the runbook someone will actually execute, and it namesdpkg -l fab,apt-cache policy faband the pin file.In the other direction, "~30 literal
fabassertions intests/build-package.bats" overcounts: of the 34 occurrences only 4 are package-name reads, at:56and:192-194. The rest are the repository name, which is not changing.build_changes_path:137derives filenames fromdpkg-parsechangelog -S Source, so the.deband.changesnames follow the rename on their own.MEDIUM 11. The reference counts are not reproducible, and the table contradicts the prose
Measured across all 40 repositories, excluding
.git/:fab-chrootfab-apply-overlayfab-plan-resolveFAB_PATHFAB_ARCH/usr/share/fabimport fabLow by 10 to 20 percent throughout and by 3.4 times for
/usr/share/fab. Undercounting is the safe direction for a claim of the form "none of these reads the package name", so the conclusion is unaffected, but the prose says "roughly 380 references" while the table sums to 631. Say which tree and which exclusions produced the numbers, or round them off.MEDIUM 12. The coverage number is a pass rate
tests/coverage.sh:37-40computes the share of checks that pass, so it reads 100 whenever the suites are green and can only fall when a test fails. Addingpackagingandrelease-tagstosuites=therefore does not measure whether their branches are exercised; the claim rests entirely on the header's hand enumeration. That is pre-existing and honestly described, butdocs/traps.mdalready carries "100 percent line coverage on the same file" as something that misled this project once, and the two new suites are the first here where a branch can go unexercised without the number moving. Worth a sentence inCOVERAGE.md.LOW
19 + 56 + 36 + 15, and I ran all four:1..19,1..56,1..36,1..15, zeronot ok. The Measured table says 126 and the test plan says 125.19:58:53Zto06:06:20Z.master, whichgit branch -vvthere still reports asbehind 4" is behind 4 of aorigin/masterthat is itself stale at16730a5; against the realmasterit is behind 6. The conclusion is right either way, and the sharper statement is that the host has not fetched since before #6.shellcheck -xclean on every file this branch adds or touches" is true at warning level and above.tests/units.shandtests/source-date-epoch.sh, both touched here, carry 6 and 9 note-levelSC2317. Identical counts onmaster, so nothing was introduced; the claim just wants "no warnings or errors".debian/rules:15hardcodesdebian/keel-fab/. It fails loudly if the name changes again, which is acceptable, but$(shell dh_listpackages)costs nothing.aptcan never co-install the two: with--no-removeit stops atE: Packages need to be removed but remove is disabled.dpkg -i --force-conflicts --force-overwritecan, and becauseReplacesis one-directional the result is thatkeel-fabkeeps ownership of/usr/bin/faband all nine aliases even thoughfabunpacked second. Removingkeel-fabthen deletes them, leavingfab 1.1.1+keel2installed,dpkg -V fabexiting 0, and no/usr/bin/faband no/usr/bin/fab-chrooton the machine. So: never reach for--force-conflictshere, and verify withdpkg -S /usr/bin/fabrather thandpkg -V.On the conversion itself
The mechanics are sound and I checked all three directions in a container.
apt-get install ./keel-fab_2.0.0_all.debremovesfab, installskeel-fab, and every path including the nine aliases ends up owned bykeel-fab.--allow-downgradesneeded since the names differ:apt-get install /root/src/fab_1.1.1+keel2_all.debremoveskeel-faband restores/usr/bin/fab-chroot..deb, which is the property that matters.So the reversibility claim holds. What is not yet true is that it is safe to schedule: HIGH 1 has to be closed in apt#15 first, with the negative pin and not only the widened stanza, and HIGH 2 needs
tkldev/plan/mainfiled before the archive ever dropsfab.Verdict
No CRITICAL. Four HIGH, none of them in the diff itself: the packaging is right, the
dh_python3work is right and well evidenced, the version choice is right and the test pins it, and #7's premise really was wrong. The HIGH items are in the deferral reasoning and in the reach of the new gate, and three of the four are a few lines each.Warning.
HIGH 3 and 4 are fixed in
6a1f93c(reproduced: an untagged newest release fails under--require-newest, and an UNRELEASED entry on top no longer exempts the release below it; a lightweight or unreachable tag fails). HIGH 1 and 2 gate the conversion, not this merge, and are apt#15 and tkldev#4; note the negative pin has to bePin: release o=turnkeylinux, sincePin: origin ""only matches a local repository (reproduced, see apt#15). After merging, push an annotatedkeel-fab/2.0.0on the merged head, or the default-branchrelease-tagsjob goes red.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.