Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .changeset/raise-the-two-sales-token-ceilings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
---

Gate and test documentation only — this PR releases nothing to HotCRM users, so the
frontmatter above is deliberately empty (the sanctioned "releases nothing" declaration
`.github/workflows/changeset-check.yml` documents, on par with the `skip-changeset` label).
The diff touches `scripts/check-source-token-ratchet.mjs`, two files under `test/` and this
changeset; it opens no file `objectstack build` reads — not `objectstack.config.ts`, not
`objectstack.composition.ts`, not one line under `src/` — so the published artifact and the
`content/docs/` documentation site are byte-identical to `main`. This follows #1928's
precedent, which raised two of these same ceilings and declared itself the same way.

**The two `src/sales` ratchet ceilings rise to `business semantics = 59,000` and
`authored total = 107,000`.** Maintainer ruling, verbatim and kept untranslated, given on
#1951 to letter A (「raise them to the `anchor()` of the post-#1916 readings, 59,000 and
107,000」):

> 「同意」

They are `anchor()` of a reading — `ceil(reading × 1.05 / 1000) × 1000` on 55,986 and
101,395, the readings PR #1950's tree prints — so the ruled 5% working buffer (「给 5% 缓冲」)
is the whole of the raise and the kind stays `ANCHORED`. ⛔ Not 57,000 / 103,000: that pair
carries a 1.8% buffer while claiming to follow the 5% rule, and the ruling names it and
refuses it.

Unchanged on purpose: `src/sales`'s `interaction layer` ceiling (31,000), every ceiling of
`src/service/`, `src/revenue/` and `src/marketing/`, the measurement basis, and the README
banner — which is pinned to the measured reading, not to a ceiling (「解耦:banner 钉实测,
ceiling 独立」), and `origin/main`'s reading did not move.
79 changes: 67 additions & 12 deletions scripts/check-source-token-ratchet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,8 @@ export const anchor = (tokens) => Math.ceil((tokens * (1 + BUFFER)) / 1000) * 10
* numbers, that the rule applied to the other eleven rows is the rule that set
* the committed one, not a new one invented for this card.
*
* The anchoring run all twelve ceilings below come from:
* The anchoring run that SET all twelve, and that three of the rows below are
* still dated to:
*
* node scripts/check-source-token-ratchet.mjs # 2026-09-16 00:00 UTC, `origin/main` at 4d7ae9f
* #1928 — the per-module budget: the readings the pre-#1928 gate printed per package
Expand All @@ -413,24 +414,78 @@ export const anchor = (tokens) => Math.ceil((tokens * (1 + BUFFER)) / 1000) * 10
* src/revenue business semantics ~15,196 · interaction layer ~2,136 · authored total ~17,485
* src/marketing business semantics ~8,001 · interaction layer ~876 · authored total ~9,096
*
* src/sales business semantics 52,379 × 1.05 = 54,998 -> ceil 1k -> 55,000 (headroom 2,621, 5.0%) 2026-09-16
* ## 2026-09-18 — #1951 raises the two `src/sales` ceilings, by ruling
*
* The ruling that authorises this raise. It was put to the maintainer as letter
* A of #1951 — "raise the two `src/sales` ceilings to the `anchor()` of the
* post-#1916 readings, 59,000 and 107,000" — and the reply, verbatim and
* untranslated, was:
*
* 「同意」
*
* That word is the whole of the maintainer's text, so the PR that raises these
* two constants quotes the letter it answers as well as the answer; #1951's
* ruling comment is the record, and the raising PR body links it. The ruling
* also refuses a number: ⛔ NOT 57,000 / 103,000, which carries a 1.8% buffer
* while claiming to follow the 5% rule 「给 5% 缓冲」 sets. The two numbers below
* are `anchor()` applied to a reading, like every other row in this table —
* that is what makes them ANCHORED rather than a grant, and it is why the kind
* column does not move. ⛔ Do not file them as RULED to save the arithmetic: a
* RULED ceiling is symmetric, so LOWERING these two would then need a ruling of
* its own, forever, and no maintainer agreed to pin them against future
* tightening.
*
* ⚠️ The reading those two rows anchor from is NOT one `origin/main` prints.
* #1916's implementation is PR #1950, and 55,986 / 101,395 are true on ITS head;
* `origin/main` at 087b7c5 reads 54,179 / 99,340. So the run below names the
* tree it was taken on, exactly as #1905's re-scoping run had to: naming the ref
* and its sha is what keeps a row reproducible, and it is the format this header
* already uses rather than a new one invented here.
*
* ⚠️ The three modules are byte-identical on that tree and on `origin/main` at
* 087b7c5 — #1916 touches `src/sales/` alone — so their readings below are
* `origin/main`'s too, re-measured on this run rather than carried over. Nine
* of the twelve rows re-anchor onto it; the three whose `anchor()` now lands
* ABOVE the ceiling they carry keep their 2026-09-16 row and are recorded as
* declined re-anchorings under the table. ⛔ Only the two constants the ruling
* names move — no other package's ceiling changes here.
*
* node scripts/check-source-token-ratchet.mjs # 2026-09-18 01:37 UTC, `refs/pull/1950/head` at 85e5dbd
* #1951 — the raise: the readings PR #1950's tree prints, per package
* src/sales business semantics ~55,986 · interaction layer ~29,725 · authored total ~101,395
* src/service business semantics ~12,593 · interaction layer ~6,228 · authored total ~21,127
* src/revenue business semantics ~15,169 · interaction layer ~2,136 · authored total ~18,279
* src/marketing business semantics ~8,001 · interaction layer ~876 · authored total ~9,096
*
* src/sales business semantics 55,986 × 1.05 = 58,785 -> ceil 1k -> 59,000 (headroom 3,014, 5.4%) 2026-09-18
* src/sales interaction layer 29,477 × 1.05 = 30,951 -> ceil 1k -> 31,000 (headroom 1,523, 5.2%) 2026-09-16
* src/sales authored total 94,445 × 1.05 = 99,167 -> ceil 1k -> 100,000 (headroom 5,555, 5.9%) 2026-09-16
* src/service business semantics 12,646 × 1.05 = 13,278 -> ceil 1k -> 14,000 (headroom 1,354, 10.7%) 2026-09-16
* src/service interaction layer 6,228 × 1.05 = 6,539 -> ceil 1k -> 7,000 (headroom 772, 12.4%) 2026-09-16
* src/sales authored total 101,395 × 1.05 = 106,465 -> ceil 1k -> 107,000 (headroom 5,605, 5.5%) 2026-09-18
* src/service business semantics 12,593 × 1.05 = 13,223 -> ceil 1k -> 14,000 (headroom 1,407, 11.2%) 2026-09-18
* src/service interaction layer 6,228 × 1.05 = 6,539 -> ceil 1k -> 7,000 (headroom 772, 12.4%) 2026-09-18
* src/service authored total 20,423 × 1.05 = 21,444 -> ceil 1k -> 22,000 (headroom 1,577, 7.7%) 2026-09-16
* src/revenue business semantics 15,196 × 1.05 = 15,956 -> ceil 1k -> 16,000 (headroom 804, 5.3%) 2026-09-16
* src/revenue interaction layer 2,136 × 1.05 = 2,243 -> ceil 1k -> 3,000 (headroom 864, 40.4%) 2026-09-16
* src/revenue business semantics 15,169 × 1.05 = 15,927 -> ceil 1k -> 16,000 (headroom 831, 5.5%) 2026-09-18
* src/revenue interaction layer 2,136 × 1.05 = 2,243 -> ceil 1k -> 3,000 (headroom 864, 40.4%) 2026-09-18
* src/revenue authored total 17,485 × 1.05 = 18,359 -> ceil 1k -> 19,000 (headroom 1,515, 8.7%) 2026-09-16
* src/marketing business semantics 8,001 × 1.05 = 8,401 -> ceil 1k -> 9,000 (headroom 999, 12.5%) 2026-09-16
* src/marketing interaction layer 876 × 1.05 = 920 -> ceil 1k -> 1,000 (headroom 124, 14.2%) 2026-09-16
* src/marketing authored total 9,096 × 1.05 = 9,551 -> ceil 1k -> 10,000 (headroom 904, 9.9%) 2026-09-16
* src/marketing business semantics 8,001 × 1.05 = 8,401 -> ceil 1k -> 9,000 (headroom 999, 12.5%) 2026-09-18
* src/marketing interaction layer 876 × 1.05 = 920 -> ceil 1k -> 1,000 (headroom 124, 14.2%) 2026-09-18
* src/marketing authored total 9,096 × 1.05 = 9,551 -> ceil 1k -> 10,000 (headroom 904, 9.9%) 2026-09-18
*
* `headroom` is the headroom **at anchor time** (`ceiling - reading`, on that
* row's own run): it is a derivation of the constant beside it, not a live
* figure, so it deliberately does not track what the gate prints today — the
* tree keeps moving between re-anchorings.
*
* Re-anchorings the 2026-09-18 run DECLINED, because `anchor()` of that run's
* reading lands ABOVE the ceiling already committed. Raising one takes a ruling
* of its own, and #1951's names the two `src/sales` rows above and nothing
* else — so these three keep the 2026-09-16 reading their constant was anchored
* from, and the row saying why is the record that they were weighed rather than
* overlooked:
*
* src/sales interaction layer anchor( 29,725) = 32,000 > ceiling 31,000 2026-09-18
* src/service authored total anchor( 21,127) = 23,000 > ceiling 22,000 2026-09-18
* src/revenue authored total anchor( 18,279) = 20,000 > ceiling 19,000 2026-09-18
*
* ⚠️ The small modules carry headroom well past 5% and there is no way around
* it: `anchor()` rounds up to the next 1,000, and on a reading of 876 that step
* alone is 14%. The rounding is kept anyway — a ceiling a reader can hold in
Expand Down Expand Up @@ -490,9 +545,9 @@ const CEILING_KIND = { ANCHORED: 'anchored', RULED: 'ruled' };
* ceiling, it is four, and a table keyed by label alone could not hold them.
*/
const COMMITTED = [
{ module: 'src/sales', label: 'business semantics', ceiling: 55000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/sales', label: 'business semantics', ceiling: 59000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/sales', label: 'interaction layer', ceiling: 31000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/sales', label: 'authored total', ceiling: 100000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/sales', label: 'authored total', ceiling: 107000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/service', label: 'business semantics', ceiling: 14000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/service', label: 'interaction layer', ceiling: 7000, kind: CEILING_KIND.ANCHORED },
{ module: 'src/service', label: 'authored total', ceiling: 22000, kind: CEILING_KIND.ANCHORED },
Expand Down
16 changes: 10 additions & 6 deletions test/docs-readme-token-figures.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ import { REPO_ROOT } from './helpers/repo-root';
* a size the app does not have — the ratchet owns the growth budget, alone, and
* a raise there sits on the maintainer floor where it always did.
*
* business semantics banner ~54k -> band 51,300–56,700 · ceiling 55,000
* business semantics banner ~54k -> band 51,300–56,700 · ceiling 59,000
* interaction layer banner ~29k -> band 27,550–30,450 · ceiling 31,000
*
* ⚠️ The ceiling column is still worked out per row, and still pinned to
Expand Down Expand Up @@ -103,11 +103,15 @@ import { REPO_ROOT } from './helpers/repo-root';
* have nothing to do with each other. `test/source-token-ratchet.test.ts` pins
* both halves of that split from the producer side.
*
* The only figure #1928 moved here is the ceiling column of the table above:
* the re-anchoring carried `business semantics` from 53,000 to 55,000, under
* the ruling quoted in the gate's own header. The band edges did not move,
* because the banner did not — 「解耦:banner 钉实测,ceiling 独立」 is exactly
* the decoupling that let one move without the other.
* The only figure a ceiling move touches here is the ceiling column of the
* table above: #1928's re-anchoring carried `business semantics` from 53,000
* to 55,000, and #1951's ruled raise carried it from 55,000 to 59,000 — both
* under a ruling quoted in the gate's own header. Neither moved a band edge,
* because neither moved the banner — 「解耦:banner 钉实测,ceiling 独立」 is
* exactly the decoupling that lets one move without the other, and #1951 is
* that decoupling paying off: the ceiling rose 4,000 tokens and this rule had
* nothing to restate, because the reading the banner is pinned to did not
* move at all.
*
* ## The measurement is the gate's, not a copy of it
*
Expand Down
2 changes: 1 addition & 1 deletion test/source-token-ratchet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ describe('source token ratchet — the ratchet itself', () => {
/**
* The second half of that advisory, and #1928 is what made it necessary.
*
* `anchor()` rounds up to the next 1,000. On `src/sales`'s 55,000 that step is
* `anchor()` rounds up to the next 1,000. On `src/sales`'s 59,000 that step is
* noise; on `src/marketing`'s interaction ceiling of 1,000 it IS the ceiling —
* every reading from 1 to 952 anchors to exactly 1,000. So a freshly anchored
* small module sits permanently past the relative trigger (headroom is 14% of
Expand Down
Loading