Context
ai/scripts/lint/lint-skill-manifest.mjs gives a FALSE-GREEN when run without --base. Hit twice during PR #13588 (the reviewer-contract skill edits): local npm run ai:lint-skill-manifest printed [lint-skill-manifest] OK, but the per-file + net byte-delta gates were never evaluated, so a +672 net (and a per-file overflow) only surfaced in CI, which runs --base origin/dev.
The Problem
lint() guards BOTH byte-delta checks behind if (base) {...} (lint-skill-manifest.mjs:1119, :1232) — checkOversizedWorkflowMaps (per-file ≤250) and checkSkillMarkdownNetDelta (net ≤250). Without --base those are silently skipped, yet main() still prints a bare [lint-skill-manifest] OK (:1280). An agent editing a .agents/skills/**/references/*.md workflow-map runs the local script, sees OK, assumes the ≤250 budgets passed — then CI fails on the delta. Cost: a false-green → push → CI-catch round-trip per occurrence, recurring across every agent that edits skill substrate.
The Fix
When options.base is absent, the success output must NOT read as budget-passing — it should name that the byte-delta gates were skipped, e.g.:
[lint-skill-manifest] OK (structural checks only — byte-delta gates skipped; run with --base origin/dev, as CI does, to check the <=250 per-file + net skill-Markdown growth budgets)
Acceptance Criteria
Out of Scope
- Auto-defaulting
--base to origin/dev (could break a fresh clone without the ref fetched); a clear notice is the minimal safe fix.
Evidence
PR #13588 cycle-1/cycle-2: the local no-base lint read green while Euclid's --base CI caught the +672 net (and separately a multi-line [skill-growth-justified] token that the [^\]\n]+ regex silently rejected). Captured in agent memory feedback_skill_substrate_edit_byte_budget.
Release classification
post-release (developer-experience / lint tooling). Boardless.
Origin Session ID: abe80be3-6235-4a9e-99bc-b14659ba806a
Context
ai/scripts/lint/lint-skill-manifest.mjsgives a FALSE-GREEN when run without--base. Hit twice during PR #13588 (the reviewer-contract skill edits): localnpm run ai:lint-skill-manifestprinted[lint-skill-manifest] OK, but the per-file + net byte-delta gates were never evaluated, so a +672 net (and a per-file overflow) only surfaced in CI, which runs--base origin/dev.The Problem
lint()guards BOTH byte-delta checks behindif (base) {...}(lint-skill-manifest.mjs:1119,:1232) —checkOversizedWorkflowMaps(per-file ≤250) andcheckSkillMarkdownNetDelta(net ≤250). Without--basethose are silently skipped, yetmain()still prints a bare[lint-skill-manifest] OK(:1280). An agent editing a.agents/skills/**/references/*.mdworkflow-map runs the local script, seesOK, assumes the ≤250 budgets passed — then CI fails on the delta. Cost: a false-green → push → CI-catch round-trip per occurrence, recurring across every agent that edits skill substrate.The Fix
When
options.baseis absent, the success output must NOT read as budget-passing — it should name that the byte-delta gates were skipped, e.g.:[lint-skill-manifest] OK (structural checks only — byte-delta gates skipped; run with --base origin/dev, as CI does, to check the <=250 per-file + net skill-Markdown growth budgets)Acceptance Criteria
--baserun does NOT print a bareOKthat reads as a full pass; it names the skipped byte-delta gates and the--base origin/devform.--baserun is unchanged (bareOKon full pass).Out of Scope
--basetoorigin/dev(could break a fresh clone without the ref fetched); a clear notice is the minimal safe fix.Evidence
PR #13588 cycle-1/cycle-2: the local no-base lint read green while Euclid's
--baseCI caught the +672 net (and separately a multi-line[skill-growth-justified]token that the[^\]\n]+regex silently rejected). Captured in agent memoryfeedback_skill_substrate_edit_byte_budget.Release classification
post-release (developer-experience / lint tooling). Boardless.
Origin Session ID: abe80be3-6235-4a9e-99bc-b14659ba806a