Skip to content

Idea to Evaluate: Break the Monolithic Rule Files Into Fine-Grained Narrow-Purpose Files With a Generated Orchestration Layer #1440

Closed as not planned

Description

@ptr727

This is an idea to evaluate, not a proposal to ratify. It is filed so it is not lost, and so the
next session starts by assessing whether it is right rather than by implementing it. Nothing here is
decided, and the maintainer has explicitly not chosen it.

The idea, in the maintainer's terms

Break up the monolithic rule files into fine-grained files, each with a very narrow purpose, so that a
single edit touches a minimal scope. Tie them together with an orchestration layer, on the reasoning
that this is no different from what the skills tree already does.

Why it is worth evaluating rather than dismissing

Evidence from one branch, PR #1435, which added two bullets to one GOVERNANCE.md section:

  • Generation beat discipline, absolutely. The three generated agent-conduct copies drifted zero
    times across twenty review rounds. Every hand-maintained surface drifted at least once:
    repo-config/README.md five times, docs/fleet-map.md twice, README.md and AGENTS.md once each.
  • Review cost scales with unit size, not edit size. The edit was nine lines. The unit is roughly
    2,400 characters, and the whole-unit rule meant re-reading all of it, twenty times.
  • Five of six breaks were "fixed one surface, missed its sibling." Every one was two statements of
    the same rule inside one file or between two files. A file with one purpose has fewer siblings inside
    it to fall out of step.
  • Net effect on the backlog for the whole session: 195 open to 196 open.

What it would supersede, and what it would not

This overlaps three filed issues and is not the same as any of them, which is the main reason to
evaluate it before doing them:

None of the three reduces the blast radius of an edit. That is the variable this idea attacks and they
do not.

Questions the evaluation has to answer

These are the things that would decide it, and none is answered here:

  1. What is the right unit? One rule per file is the extreme. The skills tree suggests something
    coarser. The carry manifest, spec/files.json, currently addresses files, and the fidelity model
    addresses sections, so the unit choice interacts with both.
  2. What does the orchestration layer actually do, and is it generated or authored? The skills tree
    has build_dist.py filling include regions from a rule's home, which is the mechanism that scored
    zero drift. Whether an assembled GOVERNANCE.md is generated from parts, or replaced by parts, is
    the central design question.
  3. What happens to carriage? Sections are carried at declared fidelity per spec/section-model.md.
    Many small files change what a downstream repo carries, what the audit checks, and what
    carry.py's section re-vendor operates on.
  4. Does it actually reduce total cost, or move it? More files means more cross-file references,
    which is the failure mode that produced five of this branch's six breaks. The claim is that a
    generated tie-together layer removes them the way it did for skills, and that claim needs testing
    rather than assuming.
  5. What is the migration, and what does it cost? A decomposition of the current corpus is a large
    change to the exact material that has proven most expensive to change.
  6. Is it worth doing before feature work? The maintainer's stated frustration is that days have
    gone into prose and rules with no feature work. An evaluation that concludes "yes, and it costs
    another N days" has to be weighed against not doing it.

Status

Filed at the maintainer's instruction, to be evaluated in a later session. No work is authorized by
this issue, and prose and rules work is stopped as of 2026-09-08.

Activity

  1. ptr727 commented on Sep 8, 2026

    @ptr727
    OwnerAuthor

    Assessment

    Read live from this repository on 2026-09-08, against origin/develop at 82758ed. No file in the
    tree was changed and nothing is implemented. Every number below is reproducible from the commands
    given beside it.

    Answer in one paragraph

    The idea's diagnosis is right and its remedy is aimed one axis away from the problem. What #1435
    measured is that generation beats hand-maintenance, and it did not measure anything about file
    size, because the file that drifted most in that branch is the smallest hand-written surface it
    touched and the monolith is the one hand-written file that shipped no drift at all. The unit a
    reviewer reads whole is already the section rather than the file, declared that way in
    spec/files.json and keyed that way by canonical_review.py, so decomposing the container does not
    change the unit, does not change what a carrier reads, and does not change what a whole-unit pass
    costs. There is a real case for decomposition, and the issue does not make it: 44% of recent
    develop commits touch GOVERNANCE.md, which caps how many rules lanes can run at once
    . That case
    is about throughput, not about drift or review cost. My recommendation is to do the cheap thing the
    evidence actually supports first, which is #1317's include mechanism widened to the surfaces that
    drifted, then re-measure, and to hold #1440 as a throughput proposal to be decided on throughput
    evidence rather than on the #1435 evidence, which does not support it.

    The evidence cannot separate the two properties the idea conflates

    The skills tree is credited in the issue as the precedent, on the reasoning that it is fine-grained
    and generated. It is generated. It is not fine-grained.

    Corpus Units Median unit Largest unit
    .agents/skills/ 24 skills, one SKILL.md each 12.2 KB 37.3 KB (backlog-burndown)
    GOVERNANCE.md 22 level-two sections 2.4 KB 19.2 KB (Verification Discipline)
    for d in .agents/skills/*/; do printf "%7d %s\n" "$(cat "$d"/*.md | wc -c)" "$(basename "$d")"; done | sort -rn

    GOVERNANCE.md is already finer-grained per unit than the tree held up as the fine-grained model,
    by a factor of five at the median. So the skills tree's zero drift cannot be attributed to
    granularity. The property it has that the drifting surfaces lack is that its copies are filled by
    build_dist.py from the rule's home.

    The measured drift does not correlate with size, and does correlate with generation

    Restating #1437's table with each surface's actual size:

    Surface Size Maintained how Drifts on #1435
    agent-conduct, three copies 30.8 KB generated include 0
    GOVERNANCE.md "Communicating with the User" 6.4 KB section in a 105 KB file hand, whole-unit read owed 0 shipped
    AGENTS.md 23.4 KB hand, whole-unit read owed 1, caught by the read
    repo-config/README.md 8.4 KB hand, no whole-unit read 4
    docs/fleet-map.md 41.5 KB hand, no whole-unit read 2
    README.md 36.7 KB hand, no whole-unit read 1

    The file that drifted most is the second smallest in the set. The largest hand-written file drifted
    twice, and the monolith drifted zero times into develop. Seven of the eight drifts landed on
    files a GOVERNANCE.md decomposition would not touch at all.
    The eighth was in AGENTS.md and was
    caught by the read it already owes.

    The issue's own framing supports this: five of six breaks were "fixed one surface, missed its
    sibling", and #1437 records that each was two statements of the same rule "inside one file or between
    two files". Splitting a file converts an intra-file sibling pair into an inter-file one. The whole-unit
    read catches the first kind, by construction, and catches the second kind never. #1437 records exactly
    that outcome: the first read of the section as one whole text found three of the four breaks
    immediately.

    Q1. What is the right unit?

    It is already decided, and it is the section. GOVERNANCE.md "Verification Discipline" states it:

    The unit is what a reviewer reads whole, and the carry manifest, spec/files.json in the hub,
    rather than the document decides which, down to which files carry units at all.

    canonical_review.py keys a unit as <path> > <heading> and derives the unit set from
    spec/files.json, never from file boundaries. build_dist.py, carry.py, spec/audit.py and
    canonical_review.py share one heading-location contract (level two, exact text after case-fold,
    fence-aware) precisely so that "a section" means one thing everywhere.

    So decomposition renames units. GOVERNANCE.md > Verification Discipline becomes
    governance/verification-discipline.md, holding the same 19.2 KB of text, owing the same whole-unit
    read at the same cost. The unit is not made smaller by moving it.

    Q2. What does the orchestration layer do, and is it generated?

    There are two variants and they differ enormously in cost, which is why the question is the central
    one.

    Assembled. Parts are authored, an assembled GOVERNANCE.md is generated and committed. Carriage,
    the audit, spec/files.json, and every downstream repository are untouched, because the artifact they
    see is byte-identical to today's. The reviewed artifact is still the assembled file and the unit is
    still the section, so the review cost is unchanged. What is left is a hub-internal authoring
    convenience: smaller merge surface between concurrent hub branches.

    Replacing. Parts are the corpus and there is no assembled file. This is the variant that changes
    anything, and it is the expensive one. It is also the variant that dissolves the intent-over-verbatim
    nesting described in Q3.

    The mechanism itself already exists and is more capable than the issue assumes. build_dist.py's
    include region accepts any authored file under the root as a source, keyed <path> > <heading>.
    Its restriction is on the destination: a region is filled only in a file the walk visits, and the
    walk visits .agents/skills/**/*.md and nothing else, refusing a region anywhere else outright
    (scripts/build_dist.py:403-405). That restriction, not the corpus shape, is why the four surfaces
    that drifted could not be generated.

    Today there are seven include regions in the whole tree:

    grep -rn '<!-- include:' .agents/skills/

    Three fill agent-conduct from GOVERNANCE.md, three fill workflow-ci-contract references from
    WORKFLOW.md, one fills drive-pr from pr-review-conduct. The mechanism that scored zero drift
    is deployed on seven regions and is structurally unable to reach the surfaces that drifted eight
    times. That gap is the finding, and it is #1317's, not #1440's.

    Q3. What happens to carriage?

    Less than expected, and the reason cuts against the idea rather than for it: the carry manifest
    already addresses sections, with per-section fidelity and per-section applicability.
    From
    spec/files.schema.json, a sections[] entry is either a bare name or an object accepting name,
    fidelity (intent or verbatim) and appliesTo. Whole-file verbatim is also already
    expressible, and CLAUDE.md uses it today.

    So a 22-file decomposition is representable as data with no schema change, and it buys no
    expressive power that the manifest does not already have
    . It costs the nesting that power is
    currently used for: GOVERNANCE.md is intent as a file while its declared sections are verbatim,
    which is how a carrier adapts the connective prose while the rules stay byte-locked. A file is one
    fidelity. Twenty-two files are twenty-two fidelities and no wrapper, so under the replacing variant
    that adaptation seam disappears, and spec/fidelity-model.md's worked example of mixed fidelity
    disappears with it.

    The mechanical churn, measured rather than guessed:

    • spec/files.json: one entry with a 20-name sections[] becomes N entries. Data only.
    • scripts/carry.py, scripts/canonical_review.py, spec/validate.py: no code change. All three
      are manifest-driven and path-generic.
    • spec/audit.py: one code constant, TEMPLATE_REF_SCANNED / UNDECLARED_HEADING_SCANNED, hard-codes
      a three-file scan list and would have to grow or become manifest-driven.
    • reports/canonical-review.json: 7 recorded GOVERNANCE.md > ... passes are orphaned by the rekey.
      Small, because only 7 of 22 sections have ever been read whole here.
    • spec/divergences.json: rows keyed on the old labels go stale and validate.py fails closed on them.
    • AGENTS.md "Where the Rules Live" is the router and is verbatim fleet-wide, so repointing every
      row re-vendors to every carrying repository. 25 repositories are in the registry.
    • spec/section-model.md, spec/fidelity-model.md, spec/scope-model.md, AUDIT.md, and the Skills
      that name GOVERNANCE.md by path all repoint.

    Q4. Does it reduce total cost, or move it?

    On the two costs the issue names, it moves them.

    Drift. Answered above: zero of the eight measured drifts trace to GOVERNANCE.md's size, and
    seven landed on files decomposition does not touch.

    Review cost. The whole-unit read is section-scoped, so it is unchanged by definition. Attributing
    each commit's hunks to the section they land in, over the last 400 develop commits touching the file:

    GOVERNANCE.md
    commits touching it, last 400 on develop 88
    touching exactly one section 53 (60%)
    touching two or more 35 (40%)
    busiest sections Workflow YAML Conventions 27, Verification Discipline 22, PR Review Etiquette 19

    Two of the three busiest sections are also the two largest, at 15.3 KB and 19.2 KB. Half the file's
    bytes sit in three sections:

    Section Bytes Share
    Verification Discipline 19,186 18%
    Running the Linters Locally 18,468 18%
    Workflow YAML Conventions 15,292 15%
    remaining 19 sections 51,946 50%

    Median section: 2,380 bytes. Fifteen of twenty-two are under 3.3 KB. The corpus does not have a
    granularity problem, it has three large sections
    , and making each of them its own file leaves each
    of them large. Reducing their cost is a text-shape question, which is what #1316 and #1322 are.

    And 40% of the commits touch more than one section. Under decomposition each of those becomes a
    multi-file edit, which is the shape that produced five of #1435's six breaks.

    Q5. What is the migration, and what does it cost?

    Under the assembled variant: a build step, a spec/files.json rewrite, and a spec/audit.py
    constant. Bounded to the hub, invisible downstream, and it delivers only the merge-surface benefit.

    Under the replacing variant: the list in Q3, plus a fleet-wide re-vendor of AGENTS.md "Where the
    Rules Live" across up to 24 carrying repositories, plus repointing the reference graph. Measured over
    the 64-file corpus (the seven top-level rule files, docs/*.md, repo-config/README.md, and every
    .agents/skills/**/*.md):

    Reference class Corpus total Pointing at GOVERNANCE.md
    Named-section references, FILE.md "Heading" 135 95
    File-path references, Markdown links and code spans 634 cross-file 151
    Relative references, "above", "below", "this file" 349 47 inside GOVERNANCE.md itself

    The third row is the one that does not appear in a diff. A section that becomes its own file takes its
    "above" and "below" with it, and they rebind to whatever now surrounds them. GOVERNANCE.md holds 47
    such occurrences, the highest count of any file in the corpus, and de-relativizing a section is a
    known defect class here already.

    It is a large change to the exact material this repository has proven most expensive to change, and
    #1435 is the calibration: two lines of GOVERNANCE.md, eleven files, seventeen commits, twenty review
    rounds, and a net backlog movement of 195 open to 196 open.

    Q6. Is it worth doing before feature work?

    No, on the evidence as it stands. The version of this idea that the #1435 evidence supports is not
    this idea, it is #1317, and #1317 is small: lift build_dist.py's destination restriction to a
    declared list, then convert the restatements on repo-config/README.md, docs/fleet-map.md and
    README.md into generated regions. That is where all eight measured drifts happened and it changes
    no file's shape, no carriage, no audit, and nothing downstream.

    What it supersedes

    None of the three. It is orthogonal to all of them, which is why it reads as overlapping.

    The case for it that the issue does not make

    There is one, and it is the reason not to close this outright.

    GOVERNANCE.md is touched by 88 of the last 200 commits on develop, 44%. backlog-burndown
    groups issues so that no two groups touch the same file. With one file in 44% of rules work, that
    grouping rule serializes almost all rules work into a single lane, whatever the agent count.
    Decomposition would raise that ceiling for the 60% of commits that touch exactly one section.

    That is a throughput argument, not a drift or review-cost argument, and it should be decided on
    throughput evidence: how often two ready rules tasks actually collided on this file and had to be
    serialized. That number is not in hand, and it is measurable.

    Recommendation

    1. Do P1: Give Every Rule One Home, Replacing Restatements With Pointers or Generated Includes #1317 first, scoped concretely: lift build_dist.py's destination restriction and convert
      the restatements on the three uncarried surfaces that drifted. Small, mechanism already built,
      attacks the only failure the evidence actually identifies.
    2. Hold Idea to Evaluate: Break the Monolithic Rule Files Into Fine-Grained Narrow-Purpose Files With a Generated Orchestration Layer #1440 open, reframed from a drift proposal to a throughput proposal, with the collision
      measurement as its entry condition.
    3. Leave P1: Define the Normative-Statement Format, Lint It, and Pilot It on "Verification Discipline" #1316 and P2: Rewrite GOVERNANCE.md and the Review-Loop Skills Into the Normative Format, One Unit Per Pull Request #1322 exactly where they are. They own the three large sections and nothing
      here changes that.
    4. If decomposition is later chosen, choose the assembled variant. It gets the merge-surface
      benefit for hub-local cost and leaves carriage, the audit, and 24 downstream repositories alone.

    Decision

    The maintainer chose option 1 on 2026-09-08: do #1317 first, hold #1440 as a throughput proposal
    gated on the collision measurement, and leave #1316 and #1322 where they are.

  2. ptr727 commented on Nov 1, 2026

    @ptr727
    OwnerAuthor

    Decision triage split the undecided item out of this issue into #3752, which carries the decision label. Everything else here stays as ordinary work an agent can do without the maintainer.

  3. ptr727 commented on Nov 1, 2026

    @ptr727
    OwnerAuthor

    Maintainer answer to the split decision #3752 (decision triage, 2026-11-01): Option 1: decline the decomposition and close this issue. The throughput premise no longer holds (8-11% of develop commits touch GOVERNANCE.md, down from 44%). A future rise can be filed fresh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions