Skip to content

build: the size ratchet is answered — 57,488,000, measured on the platform the number is set from - #726

Draft
AbirAbbas wants to merge 3 commits into
devfrom
fix/724-the-size-budget-is-answered
Draft

AbirAbbas wants to merge 3 commits into
devfrom
fix/724-the-size-budget-is-answered

Conversation

@AbirAbbas

Copy link
Copy Markdown
Collaborator

What was true

make check — the end-of-change ritual CLAUDE.md sends everybody to — stopped
at its last step on dev, for every change, whatever that change touched:

bin/aforge is 55542025 bytes. The budget in SIZE-BUDGET is 54600000. Over by 942025.

Nobody caused it and nobody could clear it from inside their own work. #624
was the last merge that weighed in under the cap; by dev@8d8cd6c8 the binary
had grown 1,908,736 bytes and crossed a number nobody moved.

What is true now

SIZE-BUDGET is 57,488,000 — two percent above darwin/amd64 at 56,360,432, the
heaviest of the four platforms, which is the headroom every figure in PERF.md's
size-ratchet section was given. That section gains the fifth reset in the same
commit as the number, per its own standing rule: the per-merge attribution, what
grew and what did not, and the four-platform table the figure came from.

Nothing a person sees in the running program changes. No manual page moves —
nothing about the running chat changed. No Go file is touched.

The attribution (linux/amd64, Go 1.26.5, each figure a make build)

merged bytes added
#624, the last merge under the cap 53,633,289
#653 55,234,825 1,601,536
#658 55,271,689 36,864
#673 55,382,281 110,592
#689 55,501,065 118,784
#721 (8d8cd6c8) 55,542,025 40,960

#653 is 84% of it and crossed the cap by itself. The rest is the ordinary
accretion of twenty-odd merges, none over 120 KB.

The shrink was looked for first, and is not there

PERF.md names two honest moves and the first one is unavailable:

  • No dependency was added. The only go.mod change across the range moves
    github.com/rivo/uniseg from indirect to direct; it was already linked.
  • Nothing new is embedded unpacked. The one embed that grew is
    internal/manual/chat.pack.gz, 707,105 → 782,330 — the manual learning about
    the features that landed, already gzipped, and required by the manual law.
    internal/manual's raw and packed sources are behind mutually exclusive build
    tags, so the shipped binary carries the corpus once.
  • The weight is compiled first-party code. Section by section between the two
    binaries: .text +1,030,464, .gopclntab +592,718, .rodata +198,176,
    .noptrdata +75,200, everything else under 7,000 each. The source says the
    same: +26,203 net non-test lines in internal/tui3, +13,011 in
    internal/session, +2,509 in internal/remote, +1,210 in cmd/aforge.
  • The dependencies were weighed too. Ranked by the file bytes their symbols
    occupy: modernc.org/sqlite 1,807,889, github.com/dop251/goja 1,791,194,
    golang.org/x/text 1,538,848 (of which x/text/collate is 1,267,813, pulled
    in by goja). Each sits behind a shipped capability — the store, and the
    JavaScript a saved program is written in (internal/jsrun). Dropping either is
    a product decision, not a size fix, and taking all of goja and its
    collation tables would still leave darwin/amd64 over the old cap.

The four platforms, each with its own furrow staged

platform bytes
linux/arm64 51,052,706
darwin/arm64 52,082,226
linux/amd64 55,542,025
darwin/amd64 56,360,432

Two lines that named the wrong platform

The refusal in Makefile and the informational job in ci-full.yml both still
said the budget was set on linux/arm64. That stopped being true at #235 — the
number has been set on darwin/amd64 since the reset that came down. The refusal
was telling whoever hit it to reset against an architecture the figure was never
taken from. Both now say darwin/amd64, and the CI comment says why that job stays
informational: linux/amd64 weighs about eight hundred kilobytes less, so a hard
compare there would pass a tree that is over the cap on the platform the cap is
measured on.

Validation contract

  1. make check on a clean checkout runs to the end; its last step prints
    bin/aforge: <bytes> bytes, under the SIZE-BUDGET budget of <budget>. and the
    Over by block is not printed.
  2. make build alone is still ungated: green, and silent about bytes, on a tree
    deliberately over the cap.
  3. When the binary next crosses the new cap, make size fails with the same
    words it fails with today. The gate is moved, never loosened.
  4. SIZE-BUDGET still holds one integer and nothing else — cat of it is what
    [ … -gt … ] compares, so the attribution lives in PERF.md.
  5. ## The size ratchet in PERF.md accounts for the number in the same commit:
    before-and-after, what grew, and the four-platform table.
  6. Where CI prints which platform the budget was set on, that is the platform it
    was set on.
  7. Nothing a person sees in the running program changes: same commands, same
    strings, same capabilities, same manual.

What must not change: no test edited to pass, no line added to
.github/known-red.txt, no manual page moved, internal/session/prompts/system.md
untouched, the furrow embed still fetched-at-build-time and uncommitted.

Fixes #724

Gates

Run in this worktree, GOFLAGS=-buildvcs=false, Go 1.26.5, linux/amd64.

$ go build ./...                                     exit 0
$ go vet ./...                                       exit 0
$ make fmt-check                                     exit 0
$ make test-packed-manual                            exit 0, ok  internal/manual  (packed-corpus path)
$ make test-laws                                     exit 0, "laws: 60 files in 17 packages", every package ok
$ go test -count=1 ./internal/manual/                ok  github.com/Agent-Field/aforge-v2/internal/manual  1.579s
$ go test -count=1 -run Manual ./internal/tui3/ ./internal/session/
                                                     ok  .../internal/tui3  0.171s
                                                     ok  .../internal/session  0.161s
$ go test -count=1 ./internal/ci/                    ok  github.com/Agent-Field/aforge-v2/internal/ci  1.073s
$ go test -count=1 ./internal/furrowbin/...          ok (the pin, the fetch, the staging)
$ make size                                          bin/aforge: 55542025 bytes, under the SIZE-BUDGET budget of 57488000.

No Go package is touched by this diff, so "touched packages" has none to run.
internal/ci (the known-red ratchet) and internal/furrowbin (the embed the
measurement depends on) were run anyway. .github/known-red.txt is unchanged.

Manual test

Contract 1 — before, on the branch's base tree:

$ make size
bin/aforge is 55542025 bytes. The budget in SIZE-BUDGET is 54600000. Over by 942025.
make: *** [Makefile:244: size] Error 1

Contract 1 — after, with the new number:

$ make size
bin/aforge: 55542025 bytes, under the SIZE-BUDGET budget of 57488000.

Contracts 2, 3 and 6 — SIZE-BUDGET temporarily set to 1000, then restored:

$ make build ; echo "build exit=$?"
build exit=0                      # green, and it says nothing about bytes

$ make size
bin/aforge is 55542025 bytes. The budget in SIZE-BUDGET is 1000. Over by 55541025.

Shrink what you added — pack a corpus (internal/packed), drop a
dependency, stop embedding what can be fetched — or raise the number
in SIZE-BUDGET IN THIS COMMIT, so the extra weight is a decision somebody
signed for rather than a drift nobody saw. PERF.md states the policy.

The budget is set on darwin/amd64, the heaviest of the four
platforms, with the toolchain of the day. A new Go release moves
this number on its own; that too is a reason to reset it
deliberately, never to ignore red.

Contract 7 — the binary this budget weighs, driven in tmux against an isolated
home on deepseek/deepseek-v4-flash, a real turn:

  › in one short sentence, what is aforge?

  aforge is a working colleague that helps you think, make decisions, and turn requests
  into useful results using tools and delegated work.
                                                    · 16:50 · 4.7s · $0.0014 ·

aforge · deepseek-v4-flash · via digitalocean · 2.8s      crew balanced ·  $0.0014 · 14.9k/1M · 1% · YOLO

and /help on the same run still draws its whole key table:

    ctrl+e         open the model's thinking, streaming or finished
    ctrl+t         a new chat start page · your draft stays put · esc back
    ctrl+w         close this tab · select the last open chat · keep your draft
    alt+t          the task roster · ↑↓ move · →← fold · enter opens · esc back

Owner decision

Opened as a draft: 57,488,000 is a 2.9 MB rise and the ratchet exists so a
rise is somebody's signature rather than a drift. The safe reversible option is
what is implemented — the number moves, nothing is removed, and every figure it
was taken from is written down so the decision can be re-litigated against real
bytes rather than an argument.

The one lever this change deliberately does not pull is internal/jsrun and its
goja + collation tables, about 3.06 MB behind the JavaScript a saved program is
written in. That is a product decision about a shipped capability, it belongs to
its own change, and on its own it would not have kept darwin/amd64 under the old
cap.

🤖 Generated with Claude Code

AbirAbbas and others added 3 commits September 9, 2026 16:51
…ent it

#624 was the last merge that weighed in under the cap. By dev@8d8cd6c8 the
binary had grown 1,908,736 bytes and crossed a number nobody moved, so `make
check` — the ritual CLAUDE.md sends everybody to — stopped at its last step for
every change on dev, whatever that change touched. Nobody caused it and nobody
could clear it from inside their own work.

The first of the two honest moves was looked for and is not there. The range
added no dependency; the only embed that grew is the chat manual's own pack,
already gzipped and required by the manual law. What is left is compiled
first-party code — .text +1,030,464 and .gopclntab +592,718 of the 1,908,736,
against +26,203 net non-test lines in internal/tui3 and +13,011 in
internal/session. Of the dependencies, the three that weigh anything sit behind
the store and behind the JavaScript a saved program is written in; dropping
either is a product decision and not a size fix, and taking all of goja and its
collation tables would still leave darwin/amd64 over the old cap.

So the number rises, with its measurement beside it, which is that section's
own standing rule. 57,488,000 is two percent above darwin/amd64 at 56,360,432 —
the heaviest of the four platforms, each built with its own furrow staged — the
same headroom every figure in that section was given.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both places a person reads about the budget still said linux/arm64, which
stopped being true at #235 — the number has been set on darwin/amd64, the
heaviest of the four platforms, since the reset that came down. So the refusal
told whoever hit it to reset against an architecture the figure was never taken
from, and the nightly line printed the same wrong provenance beside a real
measurement.

The comment on the informational job said the two numbers "are not comparable".
They are comparable and that is the point: linux/amd64 weighs about eight
hundred kilobytes less than darwin/amd64, so a hard compare there would pass a
tree that is over the cap on the platform the cap is measured on. That is why
it stays informational, and the comment now says so.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build: the binary outgrew SIZE-BUDGET by nine hundred kilobytes, and make check now stops at its last step for everybody

1 participant