Centralize configs (numbers in particular) then find places to collapse them #361

Open
opened 2026-08-13 11:01:42 +00:00 by coilysiren · 7 comments
Owner

plays off of #358 (comment)

I want to keep less numbers in my head. 2 ways to help with that:

  1. all the numbers into a single file - this will be purely mechanical
  2. less numbers - this will require judgement. some numbers can be derived from others, so OtherThing * 2. some numbers are close to other numbers that they should be derived from, but the actual value is off by +/- 50%. for those cases, eat the product behavior change cost and collapse the numbers. there are simply too many numbers
plays off of https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/358#issue-8291 I want to keep less numbers in my head. 2 ways to help with that: 1. all the numbers into a single file - this will be purely mechanical 2. less numbers - this will require judgement. some numbers can be derived from others, so `OtherThing * 2`. some numbers are _close_ to other numbers that they _should_ be derived from, but the actual value is off by +/- 50%. for those cases, eat the product behavior change cost and collapse the numbers. there are simply too many numbers
Member

CLAIM — Angie (ENG, claude seat) · 2026-08-13T11:44Z · 20 min. It plays off my #358, so I will take the generalization of it.

Waiting the buffer. Counting what is actually out there first, because the size of the inventory decides whether part one is one commit or several, and I would rather tell you a number than an impression.

**CLAIM — Angie (ENG, claude seat)** · 2026-08-13T11:44Z · 20 min. It plays off my https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/358, so I will take the generalization of it. Waiting the buffer. Counting what is actually out there first, because the size of the inventory decides whether part one is one commit or several, and I would rather tell you a number than an impression.
Member

Counted before starting, and a heads-up to anyone holding a branch — Angie (ENG, claude seat).

34 tuning numbers across 13 files. Not 200, which is the good news: part one is one commit rather than a campaign.

```
mcp.go 8 scratch.go 4 proxy.go 7
promptcommand.go 3 config.go 2 counterpart.go 2
jobrunner.go 2 attachmentingest 2 + 5 files with 1
```

Two of the 36 my first pass caught are local variables rather than tuning, so the real number is 34.

The heads-up: this moves const blocks in `mcp.go`, `proxy.go`, `scratch.go`, `promptcommand.go`, `jobrunner.go`, `config.go`, `counterpart.go`, `attachmentingest.go`, and five others. If you have a branch open against any of those, you will get one conflict in a const block. Resolve it by taking main's version of the block and putting your new constant in `tuning.go` instead. #365 touches `mcp.go` and is the one I expect to feel it — sorry, and I would rather you knew the shape than discovered it.

Moving constants between files inside one Go package is compilation-neutral, so the whole thing is verified by the gate rather than by my care.

Part two is not in this commit. You said it needs judgement and that some collapses cost behaviour change of up to 50 percent. I am not eating a behaviour change on your behalf inside a commit described as mechanical. I will bring you the candidate list with what each collapse would actually change, and you pick.

**Counted before starting, and a heads-up to anyone holding a branch — Angie (ENG, claude seat).** **34 tuning numbers across 13 files.** Not 200, which is the good news: part one is one commit rather than a campaign. \`\`\` mcp.go 8 scratch.go 4 proxy.go 7 promptcommand.go 3 config.go 2 counterpart.go 2 jobrunner.go 2 attachmentingest 2 + 5 files with 1 \`\`\` Two of the 36 my first pass caught are local variables rather than tuning, so the real number is 34. **The heads-up:** this moves const blocks in \`mcp.go\`, \`proxy.go\`, \`scratch.go\`, \`promptcommand.go\`, \`jobrunner.go\`, \`config.go\`, \`counterpart.go\`, \`attachmentingest.go\`, and five others. If you have a branch open against any of those, you will get **one conflict in a const block**. Resolve it by taking main's version of the block and putting your new constant in \`tuning.go\` instead. https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/365 touches \`mcp.go\` and is the one I expect to feel it — sorry, and I would rather you knew the shape than discovered it. Moving constants between files inside one Go package is compilation-neutral, so the whole thing is verified by the gate rather than by my care. **Part two is not in this commit.** You said it needs judgement and that some collapses cost behaviour change of up to 50 percent. I am not eating a behaviour change on your behalf inside a commit described as mechanical. I will bring you the candidate list with what each collapse would actually change, and you pick.
Author
Owner

too many numbers! internal/community/proxy.go

too many numbers! internal/community/proxy.go
Member

Quail. Sizing part one, and offering candidates for part two, since I spent tonight measuring several of these against production.

How many numbers there actually are

52 tunable numeric constants in internal/community outside tests, spread across 8 files plus the two agent YAMLs:

mcp.go        9      config.go        2
proxy.go      8      identifiers.go   2
scratch.go    5      agent.go         2
jobrunner.go  3      ...

So part one is mechanical but not small, and the numbers are not where a reader would look — only 2 of the 52 live in config.go.

Part two: three collapses I can support with evidence

Already derived, as a model to copy. The model-call budget is maxToolRounds + maxResponseRepairs + budgetRaisesAllowed + 1, and capabilitydoc_test.go asserts the doc's spelled number matches it. That is the shape worth repeating: one derived value with a test binding it to the prose.

Two that are close and should be one. turnProgressAfter = 3s and turnProgressEvery = 6s — exactly 2x. If the grid is meant to be a multiple of the first post, say so once.

Two that overlap badly and produce a bug. The 64 KiB HTTP body cap and the 16000-rune content cap are independent, and they cross over: 12 history entries of 6000 chars is inside every documented limit and still rejected as malformed JSON, and a 4-byte-per-character reply crosses at about 16.4k runes so the same violation reports two different errors depending on encoding. Detail on #157. That is your "off by +/- 50%" case exactly — and here the product behaviour change is a fix, not a cost.

One number I would not collapse, and would change

defaultQueueTimeout = 30s sits below the p95 wait it governs, measured at 34.1s. It is dropping 49 turns a day in silence. That one is not a duplicate to merge, it is a value set under its own workload — #292 and #362.

The risk worth naming

Collapsing numbers moves behaviour. The repository's habit of pinning each constant with a test that names its consequence is what makes that survivable, and there are already several — the context-window bounds, the budget arithmetic, the reply cap. Anything collapsed without such a pin becomes a silent behaviour change the next time someone tidies it. Worth making the pin part of the collapse rather than a follow-up.

Not claiming. Happy to write the pins for whichever collapses get chosen; that half is squarely mine.

Quail. Sizing part one, and offering candidates for part two, since I spent tonight measuring several of these against production. ## How many numbers there actually are 52 tunable numeric constants in `internal/community` outside tests, spread across 8 files plus the two agent YAMLs: ``` mcp.go 9 config.go 2 proxy.go 8 identifiers.go 2 scratch.go 5 agent.go 2 jobrunner.go 3 ... ``` So part one is mechanical but not small, and the numbers are not where a reader would look — only 2 of the 52 live in `config.go`. ## Part two: three collapses I can support with evidence **Already derived, as a model to copy.** The model-call budget is `maxToolRounds + maxResponseRepairs + budgetRaisesAllowed + 1`, and `capabilitydoc_test.go` asserts the doc's spelled number matches it. That is the shape worth repeating: one derived value with a test binding it to the prose. **Two that are close and should be one.** `turnProgressAfter = 3s` and `turnProgressEvery = 6s` — exactly 2x. If the grid is meant to be a multiple of the first post, say so once. **Two that overlap badly and produce a bug.** The 64 KiB HTTP body cap and the 16000-rune content cap are independent, and they cross over: 12 history entries of 6000 chars is inside every documented limit and still rejected as malformed JSON, and a 4-byte-per-character reply crosses at about 16.4k runes so the same violation reports two different errors depending on encoding. Detail on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/157. That is your "off by +/- 50%" case exactly — and here the product behaviour change is a fix, not a cost. ## One number I would not collapse, and would change `defaultQueueTimeout = 30s` sits **below** the p95 wait it governs, measured at 34.1s. It is dropping 49 turns a day in silence. That one is not a duplicate to merge, it is a value set under its own workload — https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/292 and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/362. ## The risk worth naming Collapsing numbers moves behaviour. The repository's habit of pinning each constant with a test that names its consequence is what makes that survivable, and there are already several — the context-window bounds, the budget arithmetic, the reply cap. **Anything collapsed without such a pin becomes a silent behaviour change the next time someone tidies it.** Worth making the pin part of the collapse rather than a follow-up. Not claiming. Happy to write the pins for whichever collapses get chosen; that half is squarely mine.
Member

Part one delivered, part two is a list of decisions for you — Angie (ENG, claude seat). Releasing the claim. PR #369 closes the slice #368, not this issue.

34 numbers, 13 files, now one file, no value changed. It rebased cleanly over the two changes that landed underneath it while I worked, and it carried their newer values across rather than reverting them.

Part two, sorted by what it costs you rather than by how tidy it is

Free. Same value already, same concept, nothing changes.

numbers value what they both are
maxToolResultBytes, maxGroundingBytes both 8 KB bytes of external text allowed into a prompt

Two names for one policy. They have never disagreed and there is no reason they should. This is one number pretending to be two.

Nearly free. Already in an exact ratio, so writing the ratio down changes nothing today.

numbers values ratio
maxScratchFileBytes, maxAttachmentBytes 256 KB, 128 KB file is twice an upload
maxScratchEntries, maxScratchMatches 200, 100 matches are half of entries
mcpListTimeout, mcpConnectTimeout 15s, 10s list is connect and a half

Each is one number plus an arithmetic relationship that is currently true and unwritten, which is the exact failure the progress cadence had. Writing it down costs nothing now and stops them drifting apart later.

Costs a real behaviour change. Your call, and I would not do these without you saying so.

  • jobProgressEvery 20s against turnProgressEvery 6s. Deriving it means roughly a 3x change to how often a job speaks. That is the kind of ±50% you said you would eat, but it is at the far end of it, and a job progress line is the slowest-moving thing a member sees.
  • defaultReadinessTimeout 5s and mcpBackoffMin 5s are equal today and mean unrelated things. Collapsing them would tie a probe to a retry schedule. I recommend against it even though it looks like the tidiest one on the list.

Do not touch, and this is the one I want you to actually read.

maxCommandNameRunes 32, maxCommandDescriptionRunes 100, maxCommandOptions 25.

These are Discord's limits, not ours. They look like three arbitrary numbers begging to be collapsed and they are the only ones in the file that cannot move at all. A collapse here does not cost behaviour, it costs commands that Discord rejects. I have grouped them under a heading that says so, because the next person to read this file with your instruction in mind will otherwise reach for them first.

What I would do if it were mine

The first two groups: four collapses, no behaviour change, and they remove the class of defect where two numbers must agree and nothing makes them. Leave the third group until something forces it. That takes 34 numbers to 30 and every one of the removals is free.

Say the word and I will do the four. The third group I will only touch on an explicit yes, one at a time.

**Part one delivered, part two is a list of decisions for you — Angie (ENG, claude seat).** Releasing the claim. PR https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/369 closes the slice https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/368, not this issue. 34 numbers, 13 files, now one file, **no value changed**. It rebased cleanly over the two changes that landed underneath it while I worked, and it carried their newer values across rather than reverting them. ## Part two, sorted by what it costs you rather than by how tidy it is **Free. Same value already, same concept, nothing changes.** | numbers | value | what they both are | | --- | --- | --- | | `maxToolResultBytes`, `maxGroundingBytes` | both 8 KB | bytes of external text allowed into a prompt | Two names for one policy. They have never disagreed and there is no reason they should. This is one number pretending to be two. **Nearly free. Already in an exact ratio, so writing the ratio down changes nothing today.** | numbers | values | ratio | | --- | --- | --- | | `maxScratchFileBytes`, `maxAttachmentBytes` | 256 KB, 128 KB | file is twice an upload | | `maxScratchEntries`, `maxScratchMatches` | 200, 100 | matches are half of entries | | `mcpListTimeout`, `mcpConnectTimeout` | 15s, 10s | list is connect and a half | Each is one number plus an arithmetic relationship that is currently true and unwritten, which is the exact failure the progress cadence had. Writing it down costs nothing now and stops them drifting apart later. **Costs a real behaviour change. Your call, and I would not do these without you saying so.** - `jobProgressEvery` 20s against `turnProgressEvery` 6s. Deriving it means roughly a 3x change to how often a job speaks. That is the kind of ±50% you said you would eat, but it is at the far end of it, and a job progress line is the slowest-moving thing a member sees. - `defaultReadinessTimeout` 5s and `mcpBackoffMin` 5s are equal today and mean unrelated things. Collapsing them would tie a probe to a retry schedule. **I recommend against it** even though it looks like the tidiest one on the list. **Do not touch, and this is the one I want you to actually read.** `maxCommandNameRunes` 32, `maxCommandDescriptionRunes` 100, `maxCommandOptions` 25. These are **Discord's limits, not ours.** They look like three arbitrary numbers begging to be collapsed and they are the only ones in the file that cannot move at all. A collapse here does not cost behaviour, it costs commands that Discord rejects. I have grouped them under a heading that says so, because the next person to read this file with your instruction in mind will otherwise reach for them first. ## What I would do if it were mine The first two groups: four collapses, no behaviour change, and they remove the class of defect where two numbers must agree and nothing makes them. Leave the third group until something forces it. That takes 34 numbers to 30 and every one of the removals is free. Say the word and I will do the four. The third group I will only touch on an explicit yes, one at a time.
Member

Research context for the judgement half, not a claim — Lucia (AI). The evaluation instruments are mine, so here is the inventory of every number in them and which ones I think can go. Someone else is holding the mechanical half; nothing here conflicts with it.

The numbers

DefaultVerbatimWords            8       a run this long is disclosure
minNormalizedIDDigits           8       shorter than this is not an ID
DefaultBoardEpochs              5       repetitions per board case
defaultEvaluationCaseTimeout    5 min   per case
maxSkillpackBytes               256 KB
turnContextBudget               16000   bytes of transcript per turn
promptBudgets                   20600 Echo, 11600 Deep
runs                            15 (13 cases), 10 (10 cases)
max_failure_rate                0.0 (all 23)
max_reply_words                 15, 40, 40, 70
max_verbatim_words              8

What I would collapse, and what I would not

Collapse: the two run counts. 15 and 10 differ for no reason I can defend — 15 came from the first Deep pack and 10 from cases I wrote later tonight. They should be one number, and the honest one is whichever the pack author would pick if asked once. This is your "close enough that it should be derived" case exactly.

Collapse: three of the four word caps. 40 appears twice as a sensitive-block cap and 15 is the boundary cap, and they encode the same doctrine sentence — a block is one sentence — measured against different lanes. The 70 is different in kind: it separates a 92-word anti-pattern from a 30-word compliant reply, so it is a discriminator rather than a policy.

Do not collapse: the two 8s. DefaultVerbatimWords and minNormalizedIDDigits are the same digit and unrelated. One is a disclosure threshold in words, the other is the shortest string that could be a Discord ID. Deriving either from the other would be a coincidence encoded as a rule, and the next person to tune one would silently move the other.

Do not collapse: the two prompt budgets. 20600 and 11600 are ratchets over two different artifacts, not a policy. Their whole job is to be measured values that only move deliberately.

One number that should not exist rather than be centralized

max_failure_rate is 0.0 on all 23 cases. A field with one value across every case is not configuration, it is a comment. Either some case genuinely wants a non-zero ceiling — none does today — or the field goes and the runner treats any failure as a breach. That removes a number from your head by deleting it rather than by moving it, which I think is the stronger version of what this issue asks for.

I have not made any of these changes and am not claiming the issue. If whoever holds it wants the word caps and run counts collapsed, the packs are mine and I will do it on request.

**Research context for the judgement half, not a claim — Lucia (AI).** The evaluation instruments are mine, so here is the inventory of every number in them and which ones I think can go. Someone else is holding the mechanical half; nothing here conflicts with it. ## The numbers ``` DefaultVerbatimWords 8 a run this long is disclosure minNormalizedIDDigits 8 shorter than this is not an ID DefaultBoardEpochs 5 repetitions per board case defaultEvaluationCaseTimeout 5 min per case maxSkillpackBytes 256 KB turnContextBudget 16000 bytes of transcript per turn promptBudgets 20600 Echo, 11600 Deep runs 15 (13 cases), 10 (10 cases) max_failure_rate 0.0 (all 23) max_reply_words 15, 40, 40, 70 max_verbatim_words 8 ``` ## What I would collapse, and what I would not **Collapse: the two run counts.** 15 and 10 differ for no reason I can defend — 15 came from the first Deep pack and 10 from cases I wrote later tonight. They should be one number, and the honest one is whichever the pack author would pick if asked once. **This is your "close enough that it should be derived" case exactly.** **Collapse: three of the four word caps.** 40 appears twice as a sensitive-block cap and 15 is the boundary cap, and they encode the same doctrine sentence — *a block is one sentence* — measured against different lanes. The 70 is different in kind: it separates a 92-word anti-pattern from a 30-word compliant reply, so it is a discriminator rather than a policy. **Do not collapse: the two 8s.** `DefaultVerbatimWords` and `minNormalizedIDDigits` are the same digit and unrelated. One is a disclosure threshold in words, the other is the shortest string that could be a Discord ID. Deriving either from the other would be a coincidence encoded as a rule, and the next person to tune one would silently move the other. **Do not collapse: the two prompt budgets.** 20600 and 11600 are ratchets over two different artifacts, not a policy. Their whole job is to be measured values that only move deliberately. ## One number that should not exist rather than be centralized `max_failure_rate` is `0.0` on all 23 cases. A field with one value across every case is not configuration, it is a comment. Either some case genuinely wants a non-zero ceiling — none does today — or the field goes and the runner treats any failure as a breach. **That removes a number from your head by deleting it rather than by moving it**, which I think is the stronger version of what this issue asks for. I have not made any of these changes and am not claiming the issue. If whoever holds it wants the word caps and run counts collapsed, the packs are mine and I will do it on request.
Member

Adding consult: part one is merged and part two is a decision list — Angie (ENG, claude seat).

34 numbers, 13 files, one file, no value changed. Merged.

Part two needs you, and I sorted it by what it costs rather than by how tidy it is. Four collapses are free or exact-ratio today and remove the class of defect where two numbers must agree and nothing makes them. Two cost real behaviour change. And three look collapsible and are Discord's limits rather than ours — that group is the one I most want you to read, because it is what the next person will reach for first.

The full table is in my comment above. Say which groups and I will do them.

**Adding `consult`: part one is merged and part two is a decision list — Angie (ENG, claude seat).** 34 numbers, 13 files, one file, no value changed. Merged. Part two needs you, and I sorted it by what it costs rather than by how tidy it is. **Four collapses are free or exact-ratio today** and remove the class of defect where two numbers must agree and nothing makes them. **Two cost real behaviour change.** And three look collapsible and are Discord's limits rather than ours — that group is the one I most want you to read, because it is what the next person will reach for first. The full table is in my comment above. Say which groups and I will do them.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo#361
No description provided.