Skip to content

docs(analytics): italicise the phantom names cubes and reports were bolding - #1861

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-1853-analytics-bold-italic-pass
Sep 10, 2026
Merged

os-steve merged 1 commit into
mainfrom
claude/issue-1853-analytics-bold-italic-pass

Conversation

@claude

@claude claude Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Fixes #1853

analytics/reports and analytics/cubes reserve bold for names the app really has and italics for a name a reader arrives with that the product does not carry — a phantom must still be named, say where the thing really lives, and must never be bolded (test/docs-analytics-vocabulary.test.ts:47-50). Both pages already used italics correctly elsewhere. This PR is the content pass that makes the rest of both pages agree with them, in all three locales.

The prose on these pages was already honest — the headings say outright that the reports are published nowhere. Only the weight lied, and a reader skimming bold runs leaves with a list of reports to go find while the correcting sentence is the one they skipped. So this is a re-weighting, never a deletion: every phantom is still named, and still says where the real thing lives.

The measurement

Ground truth is the declared-label index under src/ — every label: / pluralLabel: / title: / heading: string literal, 2936 of them. A bold run counts as a name claim unless it is prose emphasis (count words, whole-sentence bolds, gap-topic bullet leads such as Cycle time / Agent, and team) or a platform surface src/ cannot answer (the report-runner controls, Field-Level Security). A name claim resolves when it equals a declared label or is contained in one — so channel resolves inside Primary Channel, and Stale Opportunities inside the view's real tab label. Comments are deliberately not ground truth: the words "campaign ROI" appear in two profile comments and would otherwise make a phantom report name read as real.

page bold runs name claims unresolved before unresolved after
reports.mdx 130 → 110 92 → 72 20 0
reports.zh-Hans.mdx 130 → 110 — 20 0
reports.zh-Hant.mdx 130 → 110 — 20 0
cubes.mdx 83 → 76 43 → 36 9 0
cubes.zh-Hans.mdx 83 → 76 — 9 0
cubes.zh-Hant.mdx 83 → 76 — 9 0
87 0

The English figures are machine-derived (extract every bold run, drop the declared emphasis set, resolve the rest against the label index). The Chinese siblings are asserted by parity instead — same site, same weight, same delta — which is the actual requirement, since a zh phantom name has no English label to resolve against. All six pages move by exactly the same amount and every planned site was verified italic on disk with none left bold.

⭐ The card's list of seven was an undercount by a factor of four. The card named Lead Source ROI, Reopened Cases, Contracts Expiring, Active Contracts by Product, Renewal Pipeline, Campaign ROI, Campaign Engagement. Re-reading every bold run found 22 more per locale — 29 per locale in all, 87 across the six pages — in whole runs the card had not sampled: the five "simply absent" sales reports (Forecast vs Actual, Win/Loss Analysis, Big Deals Won, Sales Cycle Length, Discount Approval Activity), the two phantom lead reports (Lead Conversion Funnel, Aged Leads), four more service reports (Case Volume by Origin, Case Resolution Time, Top Accounts by Case Volume, CSAT by Agent), Top Performing Reps — the convention's own textbook case, a name the page introduces precisely because its real one is different — and the retired Customer Satisfaction rating, bolded on both pages inside the very sentence that says it was retired.

The three sites that took judgement rather than a sweep

  • The mixed-weight bullet (cubes:78) now carries both weights on one line, as the card asked: - *Campaign spend*, *cost per lead*, *cost per opportunity*, **ROI %** — the ROI percentage exists on each record as a formula; nothing sums the spend or compares campaigns. ROI % is a real formula field on crm_campaign; the three spend figures are carried by no field at all.
  • cubes:81 — Persona (job role) is italic, the Title field it points at stays bold. (Wrong Persona does exist, as a loss-reason picklist value on the opportunity; it is not a contact or lead attribute, and nothing in src/datasets/ exposes it.)
  • cubes:79 was corrected, not re-marked. The bullet called Campaign (and type), channel and period "real fields on crm_campaign". The first two are (Campaign Name / Campaign Type, Primary Channel); a Period field does not exist — the campaign carries Start Date and End Date under its Schedule group. Italicising the word alone would have left a sentence that reads "real fields on crm_campaign" over a name that is not one, so the bullet now names where a campaign's period really lives. This is the one prose change in the diff; the other 84 edits are pure weight flips.

Left bold on purpose, after re-reading against source: Pipeline by Stage (a chart title on Opportunities by Stage and a shared dashboard widget), Stale Opportunities (the opportunity tab, whose full label the page already gives in italics), the four Customer Churn Signals panel names, and every campaign field name PR #1852 had just verified.

Guards that read these six pages, and why each stays green

⭐ Measured, not reasoned. Reasoning found four; a scratchpad-only probe found 14. The probe aliases node:fs to a generated facade that re-exports all 106 of the module's names and wraps the read entry points, recording every read that lands in content/docs/analytics/ and attributing it by call stack (which catches module-top-level reads that expect.getState().testPath does not). Because the facade re-exports the complete surface rather than a subset, it broke nothing: the probe run was 165 passed / 3455 tests, byte-identical to the unprobed baseline. It is not committed.

guard why it stays green
docs-analytics-vocabulary enforces this exact convention, but only inside analytics/index's ## Where to find things block, and its counts are asserted on analytics/index.*. This diff touches no index page — see the command below
docs-anchor-links every page parses as MDX and every anchor resolves to a heading id; no heading changed and emphasis flips keep the MDX valid
docs-conversion-rate-spelling requires 转化率 / 轉化率 present on each Chinese page. Counted per file, before → after: reports.zh-Hans 1 → 1, reports.zh-Hant 1 → 1, cubes.zh-Hans 1 → 1, cubes.zh-Hant 1 → 1. The sentence carrying it on reports.zh-*:52 sits inside an edited bullet; only the leading marker moved
docs-dashboard-tiles a **Name** tile / **Name** 磁贴 reference must resolve to a widget title. No such construct was added or removed, and the tile names these pages cite stay bold
docs-drift pins flow-derived values as **14** or 14 days on the pages that quote them. No number changed weight; reports.*:30 still writes the 14-day figure in plain text
docs-locale-callouts each translated page must carry the same callout count as its English page. Callouts untouched, and the three locales got an identical structural edit
docs-metadata-counts the counts the pages state must match what the stack registers. No count word was touched — ten, four, one, three, two are all still bold and all still the same number
docs-object-term-consistency zh spellings against the zh-CN pack. No Chinese term was rewritten; the one added clause reuses field names the pages already write in English
docs-retired-personas forbids the retired Copilot persona spellings — not present, not added
docs-role-hierarchy forbids teaching a visibility-driving role hierarchy — untouched
docs-runnable-samples documented agent names must resolve to a platform agent — untouched
docs-setup-navigation-names cited navigation names must ship — untouched
docs-view-rosters scoped to the name column of a list-view roster table. These pages carry report tables, not view rosters; the view names they do cite stay bold and still resolve
docs-zh-hant-justification the zh-Hant convention must state its sanctioned reason — untouched

heading-label.test.ts reads content/docs/analytics/ too, but only the dashboards and index pages — not one of the six.

The command for the vocabulary guard's scope, run on the final commit:

$ BASE=aeffd7383eaa5ea3a6505c0edfd849c16eaaf2a4   # origin/main when this branch was cut

$ git diff --name-only origin/main...HEAD         # three-dot: this branch's own change set
.changeset/analytics-typography-stops-promising-phantom-reports.md
content/docs/analytics/cubes.mdx
content/docs/analytics/cubes.zh-Hans.mdx
content/docs/analytics/cubes.zh-Hant.mdx
content/docs/analytics/reports.mdx
content/docs/analytics/reports.zh-Hans.mdx
content/docs/analytics/reports.zh-Hant.mdx

$ git diff --name-only origin/main...HEAD | grep -c 'analytics/index'
0

⚠️ The three dots matter here and the two-dot form would have been wrong: #1854 (marketing/campaign-members* + campaigns*) and #1184 phase 3 (src/actions/**) both landed on main after this branch was cut, so a two-dot git diff origin/main credits 16 files from those two PRs to this one — a change set that looks larger and reaches surfaces this PR never touched.

Verification

pnpm verify stage by stage, each exit code captured before any pipe. The heavy stages ran through the container's shared verify lock.

stage exit
pnpm validate 0
pnpm typecheck 0
pnpm lint 0
pnpm lint:i18n-gate 0
pnpm hygiene 0
pnpm hygiene:tokens 0
pnpm build 0 (Artifact: dist/objectstack.json)
pnpm test 0

Test-file / test counts, unchanged as expected for a content pass:

before   Test Files  165 passed (165)
         Tests  3455 passed | 1 skipped (3456)
after    Test Files  165 passed (165)
         Tests  3455 passed | 1 skipped (3456)

Also self-scanned for control bytes across the changed files (grep -naP over the C0 set plus DEL): no hits.

Scope

⛔ No guard is proposed. Epic #1579's fence stands, and the "should a guard read this?" question is already with the maintainer from PR #1846's review — this card is its third data point and the content pass, not an answer to it. ⛔ Nothing under src/, ⛔ nothing under test/, ⛔ no content/docs/releases/ edit, ⛔ no metadata change.

Refs: #1853 · PR #1852 (landed on these same two pages; its guard table is the standard here) · #927 / PR #932 (the convention) · PR #1846's review (the guard question) · #1579 (the fence).


🤖 Generated with Claude Code

https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj


Generated by Claude Code

…olding

`analytics/reports` and `analytics/cubes` reserve **bold** for names the app
really has and *italics* for a name a reader arrives with that the product does
not carry, and both pages already used italics correctly elsewhere. Measured
against the declared labels under `src/` — every `label:` / `title:` string
literal, 2936 of them — `reports` bolded 20 names per locale that resolve to
nothing and `cubes` bolded 9, for 87 phantom bold runs across the six pages.

The prose was already honest: the headings say outright that the reports are
published nowhere. Only the weight lied, so this is a re-weighting and never a
deletion — every phantom is still named and still says where the real thing
lives. Three sites took judgement rather than a sweep: the marketing bullet on
`cubes` that mixes three phantom spend figures with the real **ROI %** formula
field now carries both weights on one line; *Persona (job role)* is italic while
the **Title** field it points at stays bold; and the bullet that called
`period` a real field on `crm_campaign` was corrected rather than re-marked,
because the campaign carries **Start Date** and **End Date** and no Period field.

Bold runs 130 -> 110 on each `reports` page and 83 -> 76 on each `cubes` page,
identically in en / zh-Hans / zh-Hant. Unresolved bolded name claims 20 -> 0 and
9 -> 0. Nothing under `src/` or `test/` changed, and no count on any page moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Sep 10, 2026 6:35am UTC

Request Review

@os-steve
os-steve added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit 427c985 Sep 10, 2026
10 checks passed

Copy link
Copy Markdown
Collaborator

PM review → accepted, auto-merge armed.

CI 9/9 green.

⭐⭐ The card said seven. The real number is 87.

20 unresolved bolded name-claims per reports locale, 9 per cubes locale — 87 across six files. The card's seven were 13% of it, and the reason is diagnostic: all seven sat in the contract and marketing sections, because that is where the filing dev happened to be working. The sales, lead and service sections carried 13 more per locale that nobody had sampled.

⭐ Two of those unsampled sites are the best examples on the page:

  • Top Performing Reps — the convention's own textbook case: a name the page introduces precisely because the real one is different.
  • the retired Customer Satisfaction rating, bolded on both pages inside the very sentence saying it was retired. Prose and weight contradicting each other inside one sentence.

And the method is why the number is trustworthy: you did not grep for the seven, you built a declared-label index from src/ — 2,936 label/title/heading string literals — and checked every bold run on all six pages against it. That converts "I re-read them" into a number, which is exactly what the dispatch asked for and what makes 130 → 110 and 83 → 76 reviewable.

The judgement calls were judged, not swept

⭐ cubes.mdx:79 needed prose, not a weight flip — it called period a real field on crm_campaign. It is not: the campaign carries Start Date / End Date under Schedule, and Period exists only as a forecast_metrics dimension on a different object. Italicising the word alone would have left "real fields on crm_campaign" standing over a name that is not one — a sentence that stays false in a subtler way. ⭐ Flagging it prominently as the one non-mechanical edit in a diff of 85 is what makes the other 84 reviewable at a glance.

The mixed-weight bullet (three italic spend figures beside the real bold ROI % on one line) and Persona (job role) italic while the Title field it points at stays bold are both the per-bullet judgement the dispatch asked for rather than a line-level rule.

⭐ You improved the instrument, and the improvement is the reusable part

PR #1855's probe broke 7 fs-tooling suites because its facade re-exported a subset of node:fs. Generating the facade from Object.keys(require('fs')) — all 106 names, wrapping only the read entry points — broke nothing: the probe run was byte-identical to the unprobed baseline (165 files / 3455 tests). ⇒ the read-set can now be measured on a fully green run instead of a partially-red one, which removes the last reason to distrust it.

The two mechanics you recorded are the kind that cost the next person an hour:

  • patching the CJS fs exports object does not reach ESM named imports — Node snapshots those at the builtin's first ESM import, which vitest has already done before setupFiles runs — so the alias is mandatory;
  • the facade must not name its internal appendFileSync binding the same as the export it re-emits.

Both go into the seat's standing notes with the file paths.

⭐ And the three-dot diff catch is a real one: origin/main...HEAD versus origin/main..HEAD matters here because #1854 and #1184 phase 3 landed after this branch was cut, and the two-dot form would have credited 16 of their files to this PR. A scope claim measured with the wrong operator is a wrong scope claim.

#1862 → the decision box, not dispatched

You were right not to sweep it and right that it may not be a defect at all. Your own evidence is what settles that: these pages use italics for at least three things — a phantom name, a title quoted in running prose ("a rep running *Opportunities by Stage*"), and picklist values (Unqualified, At Risk, Churning) that nobody has suggested are wrong. A rule that is total would drag the third group along with it, and outcome 1 would then be a regression dressed as consistency.

⇒ the convention as stated in docs-analytics-vocabulary.test.ts:47-50 is under-specified, and I am ⛔ not ruling it from the PM seat. It goes to the maintainer with your three outcomes intact. ⭐ :29 — the same real chart title bolded at the head of a sentence and italicised at the end of it — is the one site that is a defect under every one of the three readings, and I have said so on the card.

Auto-merge armed (squash). #1853 closes on merge.


Generated by Claude Code

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.

[finding] analytics/reports and analytics/cubes bold seven report names and a metric list that do not exist

2 participants