fix(engine): TAG-ANNOTATED never consulted the register for the newest tag
Reported by catalog (coord, 2026-08-17): register/repos.json has listed ktg-plugin-marketplace v7.7.2 under tags_lightweight_accepted since the 0.11.2 release (2026-08-14), but `accepted` was only ever applied to tags.slice(0, -1) — the newest tag is excluded from that slice by construction, so the entry was dead weight from the day it was written. checkTagIntegrity now checks the newest tag against `accepted` too, emitting a distinct TAG-ANNOTATED-ACCEPTED-NEWEST OK instead of silently doing nothing when the register names it exactly. Acceptance is per-tag-name, not a standing exemption: a new lightweight tag that becomes newest afterwards is still judged (tested). TDD: two new tests written failing first (an existing test's title claimed "cannot be accepted away" but never actually passed a matching `name`, so it was accidentally still green either way — reworded to test what it actually covers). Verified against a fresh clone of ktg-plugin-marketplace: the full finding set now reads OK TAG-ANNOTATED-ACCEPTED-NEWEST + OK TAG-ANNOTATED-ACCEPTED(7 older) instead of ERROR, with no knock-on effect on TAG-SIGNED (all 9 tags predate the signing policy). Register comment updated to record the three-day dead-weight window rather than silently correcting it — a decision that turns out wrong is worse than no record. 247 tests pass (245 + 2 new).
This commit is contained in:
parent
4714f13959
commit
aee0f28539
3 changed files with 72 additions and 12 deletions
|
|
@ -223,6 +223,15 @@
|
|||
"itself enforces that, since a new lightweight newest tag is not on this",
|
||||
"list and fires ERROR.",
|
||||
"",
|
||||
"This entry was DEAD WEIGHT from 2026-08-14 to 2026-08-18: `accepted` was",
|
||||
"only ever consulted for tags OLDER than newest, so v7.7.2 kept firing",
|
||||
"TAG-ANNOTATED ERROR the whole time — the exact 'we decided this' vs.",
|
||||
"'nobody looked' collapse this axis exists to prevent, one level down.",
|
||||
"Caught and reported by the catalog itself (coord, 2026-08-17), fixed in",
|
||||
"`checkTagIntegrity` (repo-standard, 2026-08-18): the accepted set is now",
|
||||
"checked against the newest tag too, emitting a distinct",
|
||||
"`TAG-ANNOTATED-ACCEPTED-NEWEST` OK rather than silently doing nothing.",
|
||||
"",
|
||||
"The two slash-named `config-audit/v*` tags on that forge are OUT OF SCOPE",
|
||||
"by construction, not omitted by a fetch gap: the engine reads",
|
||||
"`refs/tags/v*` — the repo's own version line — and a namespaced",
|
||||
|
|
|
|||
|
|
@ -708,15 +708,27 @@ export function checkTagIntegrity({ tagObjects, name }, register) {
|
|||
|
||||
const findings = [];
|
||||
const newest = tags[tags.length - 1];
|
||||
if (!newest.annotated) {
|
||||
findings.push({
|
||||
level: 'ERROR',
|
||||
code: 'TAG-ANNOTATED',
|
||||
bucket: 'broken',
|
||||
msg: `newest tag \`${newest.name}\` is lightweight — it can be moved to another commit with no record that it ever pointed elsewhere, and the catalog pins releases by tag. Re-cut it annotated: \`git tag -a -f ${newest.name} ${newest.name}^{}\`.`,
|
||||
});
|
||||
}
|
||||
const accepted = new Set(register?.tags_lightweight_accepted?.[name] ?? []);
|
||||
if (!newest.annotated) {
|
||||
if (accepted.has(newest.name)) {
|
||||
// Named acceptance, not a standing exemption: only THIS exact tag is
|
||||
// excused, so a later real release still fires ERROR the moment it
|
||||
// becomes newest and isn't itself on the list (proven by the sibling
|
||||
// test below).
|
||||
findings.push({
|
||||
level: 'OK',
|
||||
code: 'TAG-ANNOTATED-ACCEPTED-NEWEST',
|
||||
msg: `newest tag \`${newest.name}\` is lightweight, but the register accepts it by name as an exception to the newest-tag rule — a safe remedy exists (\`git tag -a -f\`) but costs more than the finding for this specific tag. Any OTHER tag that becomes newest is still judged.`,
|
||||
});
|
||||
} else {
|
||||
findings.push({
|
||||
level: 'ERROR',
|
||||
code: 'TAG-ANNOTATED',
|
||||
bucket: 'broken',
|
||||
msg: `newest tag \`${newest.name}\` is lightweight — it can be moved to another commit with no record that it ever pointed elsewhere, and the catalog pins releases by tag. Re-cut it annotated: \`git tag -a -f ${newest.name} ${newest.name}^{}\`.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
const olderLightweight = tags.slice(0, -1).filter((t) => !t.annotated);
|
||||
const older = olderLightweight.filter((t) => !accepted.has(t.name));
|
||||
const excused = olderLightweight.filter((t) => accepted.has(t.name));
|
||||
|
|
@ -842,7 +854,7 @@ export function checkTagSigned({ tagObjects }, register) {
|
|||
level: 'SKIP',
|
||||
skip: 'byDesign',
|
||||
code: 'TAG-SIGNED-LIGHTWEIGHT',
|
||||
msg: `${lightweight.length} tag(s) cut under the policy are lightweight (${lightweight.map((t) => t.name).join(', ')}) — a lightweight tag has no tag object to carry a signature, so signing is not a remedy it has. TAG-ANNOTATED owns that finding; this check declines rather than report one defect twice.`,
|
||||
msg: `${lightweight.length} tag(s) cut under the policy are lightweight (${lightweight.map((t) => t.name).join(', ')}) — a lightweight tag has no tag object to carry a signature, so signing is not a remedy it has. TAG-ANNOTATED owns the verdict on these — an ERROR, or an OK if the register names one as an accepted exception; this check declines rather than report one defect twice.`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -903,15 +903,54 @@ test('an unaccepted lightweight tag still fires, and the WARN counts only the un
|
|||
});
|
||||
|
||||
// The newest tag is what a consumer resolves today and what an operator can
|
||||
// re-cut at no cost. It is the one lightweight tag with a safe remedy, so it
|
||||
// is the one that cannot be accepted away.
|
||||
test('the NEWEST lightweight tag is still an ERROR even when the register accepts its name', () => {
|
||||
const reg = { tags_lightweight_accepted: { alpha: ['v2.0.0'] } };
|
||||
const f = checkTagIntegrity({ tagObjects: [{ name: 'v1.0.0', annotated: true }, { name: 'v2.0.0', annotated: false }] }, reg);
|
||||
// re-cut at no cost, so acceptance is never inherited from a repo merely
|
||||
// having OTHER accepted entries — only an exact name match on THIS tag excuses
|
||||
// it (the exception directly below).
|
||||
test('an unaccepted newest lightweight tag is still an ERROR, even when the register has other entries for this repo', () => {
|
||||
const reg = { tags_lightweight_accepted: { alpha: ['v9.9.9'] } };
|
||||
const f = checkTagIntegrity({ tagObjects: [{ name: 'v1.0.0', annotated: true }, { name: 'v2.0.0', annotated: false }], name: 'alpha' }, reg);
|
||||
const hit = f.find((x) => x.code === 'TAG-ANNOTATED');
|
||||
assert.equal(hit.level, 'ERROR');
|
||||
});
|
||||
|
||||
// A tag that sorts "newest" by version string without being the newest
|
||||
// RELEASE — a monorepo-era tag predating a split, consumed by nothing — has a
|
||||
// real safe remedy (`git tag -a -f`, same commit) that still costs more than
|
||||
// the finding when nothing resolves it. The register names the tag by EXACT
|
||||
// NAME, never "this repo's newest is always excused" — caught the moment
|
||||
// `ktg-plugin-marketplace v7.7.2` was found dead weight: the register had
|
||||
// accepted it since 2026-08-14 (repos.json `tags_lightweight_accepted`) but
|
||||
// `accepted` was only ever consulted for tags OLDER than newest, so the
|
||||
// recorded decision could never take effect. Reported by the catalog
|
||||
// (coord, 2026-08-17): measured against the real register and real tag data,
|
||||
// exactly two findings — ERROR TAG-ANNOTATED on the (then-)inert acceptance,
|
||||
// OK TAG-ANNOTATED-ACCEPTED for the 7 older accepted tags.
|
||||
test('the newest lightweight tag IS excused when the register names it exactly, with a distinct OK code', () => {
|
||||
const reg = { tags_lightweight_accepted: { alpha: ['v2.0.0'] } };
|
||||
const f = checkTagIntegrity({ tagObjects: [{ name: 'v1.0.0', annotated: true }, { name: 'v2.0.0', annotated: false }], name: 'alpha' }, reg);
|
||||
assert.equal(f.some((x) => x.code === 'TAG-ANNOTATED'), false);
|
||||
const ok = f.find((x) => x.code === 'TAG-ANNOTATED-ACCEPTED-NEWEST');
|
||||
assert.equal(ok.level, 'OK');
|
||||
assert.match(ok.msg, /v2\.0\.0/);
|
||||
});
|
||||
|
||||
// Acceptance names ONE tag, not a standing exemption for "whatever is newest".
|
||||
// A real new tag cut after the accepted one is still judged the moment it
|
||||
// becomes newest and isn't itself on the list — exactly what the register's
|
||||
// own comment promises: "a new lightweight newest tag is not on this list and
|
||||
// fires ERROR".
|
||||
test('a NEW lightweight tag cut after an accepted newest is still judged', () => {
|
||||
const reg = { tags_lightweight_accepted: { alpha: ['v2.0.0'] } };
|
||||
const f = checkTagIntegrity({ tagObjects: [
|
||||
{ name: 'v1.0.0', annotated: true },
|
||||
{ name: 'v2.0.0', annotated: false },
|
||||
{ name: 'v3.0.0', annotated: false },
|
||||
], name: 'alpha' }, reg);
|
||||
const hit = f.find((x) => x.code === 'TAG-ANNOTATED');
|
||||
assert.equal(hit.level, 'ERROR');
|
||||
assert.match(hit.msg, /v3\.0\.0/);
|
||||
});
|
||||
|
||||
test('acceptance is per repo — a name accepted for one repo does not excuse another', () => {
|
||||
const tagObjects = [{ name: 'v0.1.0', annotated: false }, { name: 'v1.0.0', annotated: true }];
|
||||
const f = checkTagIntegrity({ tagObjects, name: 'beta' }, ACCEPT_REG);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue