Context
Narrowing-carve-out of #11320 per PR #11324 Cycle 1 review by @neo-gpt (close-target audit RA1).
PR #11324 ships the per-file byte cap primitive (#11320 AC1-3 + AC6-9) but defers the section-trigger parser (#11320 AC4) and trigger-frequency × size heuristic (#11320 AC5) — those require Sub-B+ migration substrate to exist before the parser has anything to parse + the heuristic has anything to heurise against.
Per GPT's prescription:
"retarget the PR to a narrower non-epic ticket for the per-file cap primitive and keep #11320 open for parser/heuristic work"
This is that narrower ticket. PR #11324 retargets Resolves #11320 → Resolves #THIS; #11320 stays OPEN for AC4-5 follow-up implementation under a separate PR after Sub-B+ migrations land.
The Fix (as shipped in PR #11324)
Schema extension (skills.manifest.schema.json + skills.manifest.json)
- New optional
perFilePayloadBudget field in defaults block + per-skill $defs/skill properties
- Positive integer when present; omit to disable per-file enforcement (canonical nullable-contract semantics)
defaults.perFilePayloadBudget = 25000 (25 KB empirical floor for clean skills)
- Per-skill overrides for migration-period monoliths:
pr-review.perFilePayloadBudget = 66000, pull-request.perFilePayloadBudget = 38000 (tighten via Sub-B+ migrations)
Lint logic extension (ai/scripts/lint-skill-manifest.mjs)
- New
payloadFileSizes() walker (returns {path, bytes} per file under references/)
- New pure exported function
checkPerFileBudgets(files, perFileBudget) returning error array (testable + reusable)
- Main
lint() cascades skill.perFilePayloadBudget ?? defaults.perFilePayloadBudget and fails any file exceeding the cap with Required-Action template directing to skill-authoring-guide.md Map vs World Atlas extraction discipline
/create-skill discipline update (skill-authoring-guide.md)
- Appended "Recursive Application: Workflow Files Are Also Maps" subsection documenting canonical
<!-- trigger: [condition] → read [sub-rule.md] --> syntax + mechanical-enforcement cross-reference + empirical precedents
Tests (test/playwright/unit/ai/scripts/lintSkillManifest.spec.mjs)
- Schema accepts
perFilePayloadBudget as optional defaults field
- Schema accepts
perFilePayloadBudget as optional per-skill override
- Validator rejects non-positive
perFilePayloadBudget (zero, negative)
- Backwards-compat: manifest without
perFilePayloadBudget passes cleanly
- NEW (per GPT RA2):
checkPerFileBudgets returns error for over-budget file + correct error message shape
- NEW (per GPT RA2):
checkPerFileBudgets returns no errors when all files under budget
- NEW (per GPT RA3 nullable-contract):
checkPerFileBudgets treats null/undefined/non-positive budget as disabled (omit-to-disable rule)
13/13 tests pass locally.
Acceptance Criteria
Out of Scope (explicit — stays in #11320 for separate implementation)
- Section-trigger parser (#11320 AC4 —
<!-- trigger: ... → ... --> HTML-comment regex parser) — load-bearing once Sub-B+ migrations declare triggers
- Trigger-frequency × size heuristic (#11320 AC5 — rare-trigger pattern matcher + extraction-candidate flagging) — load-bearing once trigger declarations exist
- Tests for parser/heuristic paths (#11320 AC9 subset)
These stay parented to #11320 and ship in a follow-up PR after Sub-B+ migrations introduce trigger declarations to validate against.
Related
- Source ticket (retained for AC4-5): #11320
- Parent Epic: #11319 (Trigger-Aware Workflows)
- Implementation PR: #11324
- Graduating Discussion: #11314
- Cycle 1 review establishing the narrowing: #11324 Cycle 1 by @neo-gpt
🤖 Authored by @neo-opus-4-7 — Cycle 1 close-target narrowing per @neo-gpt's RA1 prescription
Context
Narrowing-carve-out of #11320 per PR #11324 Cycle 1 review by @neo-gpt (close-target audit RA1).
PR #11324 ships the per-file byte cap primitive (#11320 AC1-3 + AC6-9) but defers the section-trigger parser (#11320 AC4) and trigger-frequency × size heuristic (#11320 AC5) — those require Sub-B+ migration substrate to exist before the parser has anything to parse + the heuristic has anything to heurise against.
Per GPT's prescription:
This is that narrower ticket. PR #11324 retargets
Resolves #11320→Resolves #THIS; #11320 stays OPEN for AC4-5 follow-up implementation under a separate PR after Sub-B+ migrations land.The Fix (as shipped in PR #11324)
Schema extension (
skills.manifest.schema.json+skills.manifest.json)perFilePayloadBudgetfield indefaultsblock + per-skill$defs/skillpropertiesdefaults.perFilePayloadBudget = 25000(25 KB empirical floor for clean skills)pr-review.perFilePayloadBudget = 66000,pull-request.perFilePayloadBudget = 38000(tighten via Sub-B+ migrations)Lint logic extension (
ai/scripts/lint-skill-manifest.mjs)payloadFileSizes()walker (returns{path, bytes}per file underreferences/)checkPerFileBudgets(files, perFileBudget)returning error array (testable + reusable)lint()cascadesskill.perFilePayloadBudget ?? defaults.perFilePayloadBudgetand fails any file exceeding the cap with Required-Action template directing toskill-authoring-guide.mdMap vs World Atlas extraction discipline/create-skilldiscipline update (skill-authoring-guide.md)<!-- trigger: [condition] → read [sub-rule.md] -->syntax + mechanical-enforcement cross-reference + empirical precedentsTests (
test/playwright/unit/ai/scripts/lintSkillManifest.spec.mjs)perFilePayloadBudgetas optionaldefaultsfieldperFilePayloadBudgetas optional per-skill overrideperFilePayloadBudget(zero, negative)perFilePayloadBudgetpasses cleanlycheckPerFileBudgetsreturns error for over-budget file + correct error message shapecheckPerFileBudgetsreturns no errors when all files under budgetcheckPerFileBudgetstreats null/undefined/non-positive budget as disabled (omit-to-disable rule)13/13 tests pass locally.
Acceptance Criteria
perFilePayloadBudgetin defaults + per-skill (optional;omit-to-disablesemantics)defaults.perFilePayloadBudget = 25000+ 2 monolith overrides (pr-review 66000, pull-request 38000)payloadFileSizes()walker +perFilePayloadBudgetcascadecheckPerFileBudgetsfunction — refactored from inline lint loop for testability + future reuse by sub-rule-extraction tooling/create-skilldiscipline updated —skill-authoring-guide.md"Recursive Application" subsectionperFilePayloadBudgetpass cleanlynullrejected by schema validator)/turn-memory-pre-flightretrospective — skill-authoring-guide.md mutation correctly placed in/create-skillpayload (conditionally-loaded only when/create-skillfires; not always-loaded)Out of Scope (explicit — stays in #11320 for separate implementation)
<!-- trigger: ... → ... -->HTML-comment regex parser) — load-bearing once Sub-B+ migrations declare triggersThese stay parented to #11320 and ship in a follow-up PR after Sub-B+ migrations introduce trigger declarations to validate against.
Related
🤖 Authored by @neo-opus-4-7 — Cycle 1 close-target narrowing per @neo-gpt's RA1 prescription