Repository navigation
README headline numbers: replace the drifted "18,000 lines / 170k tokens" with the two gate-cited numbers — business semantics ~80k, interaction layer ~39k #1187
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Aug 17, 2026 - changed the title
[-]README headline numbers: replace the drifted "18,000 lines / 170k tokens" with the two gate-cited numbers — business semantics ~78k, interaction layer ~40k[/-][+]README headline numbers: replace the drifted "18,000 lines / 170k tokens" with the two gate-cited numbers — business semantics ~80k, interaction layer ~39k[/+]on Aug 17, 2026 - addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchand removed
on Aug 17, 2026 Claim: PM loop round 3
Session:session_01XeAz8tSjwAibjdSDn9niiZ
Branch:claude/issue-1187-readme-headline-figures
Worktree:hotcrm-issue-1187
Domain:documentation
File surface:README.md,objectstack.manifest.jsonif it carries the claim,test/(stop on breach; explain in the report)
Unblocked: #1190 (#1183) merged at8ecc0bff— the gate exists. #1195 (#1182) merged at540e4887— the field removals that would have moved the published number are done, so the reading is now stable.
Serial constraints: #1193 runs in parallel oncontent/docs/revenue/products*andsrc/objects/— disjoint from this card's surface. Confirmed the headline claim appears in only two tracked files (README.mdand one archived report), so there is no contention.#1191 cannot be completed by an agent in this environment — there is no
update_repositorytool in the GitHub MCP surface and noghCLI, so the repository description is not writable from here. It is re-scoped to a drafting deliverable: produce the exact replacement string, and the maintainer pastes it into repo settings. See the dispatch.
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 { "issue": 1187, "status": "done", "branch": "claude/issue-1187-readme-headline-figures", "pr": "https://github.com/objectstack-ai/hotcrm/pull/1197", "premise_still_valid": true, "summary": "Replaced the README banner's drifted '~170k tokens (~18,000 lines)' with the two ruled layers, each taken from a run of scripts/check-source-token-ratchet.mjs on the branch: business semantics ~81k, interaction layer ~39k, with a small-print clause stating that translations and seed data are outside the count and naming the command that measures it. NOTE THE DIGIT: the gate prints ~81k where the ruling said 「写实测值 ~80k / ~39k」 — business semantics measured 80,767 at 540e4887, so ~81k is the ruling applied to today's tree rather than a departure from it, but it is the one thing the maintainer should eyeball. On phrasing I chose measured figures plus a maintainer-ruled tolerance over a durable-but-vaguer bound: a bound ('under 85k') buys durability by inflating the number, which works against a claim whose whole point is that the app is small. Durability instead comes from test/docs-readme-token-figures.test.ts holding the banner to a live --json run of the gate within the already-ruled 5% buffer (「给 5% 缓冲」), so the banner and the ratchet ceiling go stale at nearly the same reading and re-stating the claim becomes a ruling moment rather than a per-merge chore. Two scope corrections in the PR body: the archived February report never carried this claim (the card's second file is a false positive from grepping bare '18,000' — the only hit there is '120 hours/month × $150/hour = $18,000/month'), and README.md is the sole tracked file that carried it; objectstack.manifest.json, content/docs/, apps/docs/, README.legacy.md and the marketplace publisher are all clean. The test landed as a sibling file rather than inside test/docs-drift.test.ts as the dispatch suggested, because that file is 100,190 of the 102,400-byte hygiene cap and the append turned the gate red at 107KB — most of that rule family already lives in sibling test/docs-*.test.ts files.", "tests": "All at final commit f5373112 (the pushed HEAD). Full `pnpm verify` green, exit code captured directly rather than through a pipe (REAL_VERIFY_EXIT=0; the first run's 0 was tail's): validate ✓ (1190ms) · typecheck ✓ · lint ✓ · lint:i18n-gate ✓ · hygiene '✓ source hygiene clean' · hygiene:tokens '✓ source token ratchet clean' · build ✓ · test 'Test Files 111 passed (111) / Tests 2685 passed | 1 skipped (2686)'. Gate reading published in the README, from `node scripts/check-source-token-ratchet.mjs` at f5373112: 'Headline: business semantics ~81k · interaction layer ~39k · authored total ~133k' (80,767 / 38,848 / 133,465; ceilings 85,000 / 42,000 / 140,000, all green). Also ran the two ci.yml steps `verify` does not cover: `node scripts/check-stackblitz-lock.mjs` (in sync) and `pnpm changeset status --since=origin/main` (hotcrm → patch). Left to CI per #1149: test:coverage, e2e.yml, link-check.yml, CodeQL. Reverse verification of the new guard, run from the committed state each time, direction predicted before running and both legs matched: (a) restoring the pre-fix banner reddens 3 of 5 assertions — 'business semantics: 0 match(es) …', 'interaction layer: 0 match(es) …', Tests 3 failed | 78 passed — i.e. the guard would have caught the drift that opened this card; (b) corrupting only the interaction figure to ~41k, deliberately chosen as inside the ratchet ceiling (42,000) but outside the 5% band, isolates the tolerance assertion: 'interaction layer: banner says ~41k, the gate measures 38,848 (band 38,950–43,050)', Tests 1 failed | 80 passed, with the ceiling assertion correctly staying green. Restored README byte-identical afterwards (git status clean against the commit). No ablation applies — no dist/ is involved.", "open_questions": [ { "question": "#1191's surface changed underneath this task and is still moving: the GitHub repository description no longer carries the drifted ~170k claim, and I watched it change twice within four minutes while the branch was in verification (05:20:19Z: '… business logic under 100k tokens, the whole authored app under 150k …'; by 05:23Z the 150k clause was gone). I did not set either — there is no update_repository in the MCP surface and no gh CLI — so another actor on our shared identity is editing it live. I did not touch or chase it. How should #1191 be settled?", "options": [ "A — Assess #1191 against the live description rather than the string quoted in its body. Its actual defect (the ~170k claim) is already gone, and every value I observed is true against today's gate: business semantics 80,767 is under 100k, authored total 133,465 was under the 150k the earlier version carried. Close it on the live value, noting the body is stale.", "B — Keep #1191 open for one deliberate decision only: the ruling asked that customers be shown TWO layers, and the current description states a single bound on business logic, so the interaction layer is no longer represented there. The PR body carries a ready-to-paste 297-char string mirroring the README's pair if that is wanted.", "C — Treat the description/README divergence as an inconsistency to iron out and make both surfaces state the same form." ], "recommendation": "B, with A's finding folded in. The defect #1191 was filed for is fixed, so it should not stay open on its original wording — but there is one real decision left, and it is not the one in the card: the description now carries a single bound where the ruling asked for two layers. I would NOT do C. The split is correct, not accidental: the description has no CI guard and cannot get one, so it should carry bounds that cannot drift, while the README can carry exact measured figures precisely because the new test holds them to the gate. Forcing both to the same form would either put ungated digits on the most-viewed surface or strip the ruled measured pair off the one place it is enforceable." }, { "question": "The README now publishes ~81k where the ruling's text said ~80k. Confirm this is the intended reading of 「写实测值」.", "options": [ "A — Publish ~81k, the gate's own headline() output at f5373112 (business semantics 80,767), so the README and the command it tells readers to run agree exactly.", "B — Publish ~80k as literally quoted in the ruling, accepting that a reader who runs the cited script sees ~81k." ], "recommendation": "A. The dispatch and the card both state the ruling's digits are stale and to publish what the gate prints; the ruling's own instruction was to publish the measured value, and 80,411/80,356 were simply the measurement at the moment it was spoken. B would reintroduce, on day one, exactly the README-vs-reality gap this card exists to close. Flagged prominently at the top of the PR body so it is not merged unnoticed." } ], "out_of_scope_findings": [ "filed as #1196: test/docs-drift.test.ts is at 100,190 of the 102,400-byte source-hygiene cap (97.8% full), so the next rule added to it turns the gate red — as this card's first attempt did; two closed precedents (#814, #635) show the same condition being found only when it bites" ] }
Generated by Claude Code
ACCEPT — PM review of #1197. All 9 checks green. Both open questions settled below; neither needs a new ruling.
Q2 — publish
~81k, not~80k. Settled by the existing ruling, not a departure from it. 「写实测值」 means publish the measured value; the value was 80,411 when the ruling was spoken and is 80,767 today, which the gate rounds to~81k. Publishing~80kwould put the README in contradiction with the very script it tells readers to run — on day one, which is the exact failure this card exists to close. The dev's recommendation A is right, and flagging it at the top of the PR body rather than letting it merge unnoticed was the correct handling.Q1 — #1191 is being closed, and the reason is that the maintainer already fixed it by hand. The live repository description now reads:
The reference app for AI-written enterprise software: a complete CRM in typed ObjectStack metadata — business logic under 100k tokens. Small enough to hand an agent in one context window.
The
~170kclaim is gone. The single-bound form is a deliberate choice made with the two-bound alternative explicitly on the table, so option B's "the ruling asked for two layers" is superseded by the later decision. Customers still see both layers — on the README, which this PR fixes.The dev's reasoning for keeping the two surfaces in different forms is correct, and it converged independently with the same conclusion the PM reached in the maintainer session. The description has no CI guard and cannot get one — there is no
update_repositoryin the MCP surface and noghCLI — so it should carry a bound that cannot drift. The README can carry exact measured figures precisely because this PR gives it a test that holds them to a live gate run. Forcing both to one form would either put unguarded digits on the most-viewed surface or strip the measured pair off the only place it is enforceable. Rejecting option C was right.PM correction — the card's second file was my error. I told the dev to leave
docs/archive/2026-02/CRM_INDUSTRY_AI_TRANSFORMATION_REPORT.mdalone and argued at some length about not rewriting history. It never carried this claim: the sole18,000hit is$18,000/monthin a cost calculation. A baregrep "18,000"produced it. That is the third measurement slip from this PM seat in one day — two false positives and one undercount — and every one of them was caught by a dev re-running the scan instead of trusting the card.Verified independently:
- The banner publishes
~81k/~39kwith the layer contents named inline, and states the exclusion. test/docs-readme-token-figures.test.tsis a new 219-line sibling file, not an append.- The archive false positive, confirmed above.
The reverse verification is the strongest part of this delivery. Both legs were predicted before running and both matched: restoring the pre-fix banner reddens 3 of 5 assertions — so the guard demonstrably catches the drift that opened this card — and corrupting only the interaction figure to
~41k, chosen deliberately as inside the ratchet ceiling of 42,000 but outside the 5% band, isolates the tolerance assertion while the ceiling assertion correctly stays green. Choosing a value that separates two guards that would otherwise fire together is what makes it evidence rather than a smoke test. README restored byte-identical afterwards.Also correct: capturing the real
pnpm verifyexit code rather thantail's. A pipeline's exit status is the last command's, so a piped verify reports success whatever happened upstream — that is a green run that means nothing, and noticing it unprompted is the difference between running gates and reading them.Landing the test as a sibling file rather than inside
test/docs-drift.test.tswas forced and correctly diagnosed: that file is at 100,190 of the 102,400-byte hygiene cap, so the append turned the gate red at 107KB. Filed as #1196 with two closed precedents showing the same condition found only when it bit. Labelledfinding.Flipping to ready and queueing. #1191 closed separately.
Generated by Claude Code
- The banner publishes
- added a commit that references this issue
on Aug 25, 2026
Blocked-by: #1183
Blocked-by: #1182
Problem
The README's positioning claim reads "~170k tokens of typed ObjectStack metadata (~18,000 lines)". Nothing kept it honest, and it drifted.
Ruled presentation
Maintainer rulings, 2026-08-17, PM session chat (verbatim):
So the README states exactly two numbers, both comment-stripped, both taken from the gate:
No third aggregate; translations and seed data are out of the accounting (one clause may say so). The message: the entire CRM's business logic fits in a fraction of one agent context window, with the whole authored UI on top still fitting comfortably.
The gate (
scripts/check-source-token-ratchet.mjs, landed in #1190) is the only current truth. Measured history in a single working day:2342811ad038b957(after #1181)c83aa744(after #1180)The rounded headline has already moved from ~80k to ~81k since the ruling, and #1182 will move it down again by removing declared fields — which is why this card is blocked on it. Run the gate on your branch and publish what it prints; do not transcribe from this table.
Correction to this card's original figures
This card first said ~78k / ~40k. That came from the PM's hand measurement, whose comment stripper was line-oriented and therefore deleted 160 lines that live inside template literals in five
src/actions/*.tsfiles — QuickJS action-body source that carries its own//commentary. That text is authored surface an agent must read, not comment. Independently re-counted:global.actions.ts82,opportunity.actions.ts48,contact.actions.ts15,lead.actions.ts13,knowledge_article.actions.ts2.The gate's character scanner keeps it, so its figures are the correct ones. The maintainer ruled the README publishes the measured pair rather than changing the measurement basis to reproduce the old number.
Scope
scripts/check-source-token-ratchet.mjsas the measurement source so a reader can re-run it.Re-check:
grep -rn "18,000\|170k" README.md content/docs/ apps/docs/ --include=*.md*, plus the repo description andobjectstack.manifest.json.