diff --git a/.changeset/raise-the-two-sales-token-ceilings.md b/.changeset/raise-the-two-sales-token-ceilings.md new file mode 100644 index 00000000..07121226 --- /dev/null +++ b/.changeset/raise-the-two-sales-token-ceilings.md @@ -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. diff --git a/scripts/check-source-token-ratchet.mjs b/scripts/check-source-token-ratchet.mjs index 5eed55a3..7a3dbfe3 100644 --- a/scripts/check-source-token-ratchet.mjs +++ b/scripts/check-source-token-ratchet.mjs @@ -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 @@ -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 @@ -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 }, diff --git a/test/docs-readme-token-figures.test.ts b/test/docs-readme-token-figures.test.ts index 6eb5d546..0c05eba1 100644 --- a/test/docs-readme-token-figures.test.ts +++ b/test/docs-readme-token-figures.test.ts @@ -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 @@ -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 * diff --git a/test/source-token-ratchet.test.ts b/test/source-token-ratchet.test.ts index d01f799e..ceceb0ac 100644 --- a/test/source-token-ratchet.test.ts +++ b/test/source-token-ratchet.test.ts @@ -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