Skip to content

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

Closed

Description

@claude

Observed while fixing #1847 (PR #1852), which rewrote one paragraph and one bullet on analytics/cubes and analytics/reports. ⛔ Out of that card's scope — it is a page-wide typography pass, not a clause of the sentence that card names — so it is filed rather than swept there.

The convention

#927 / PR #932 established, and test/docs-analytics-vocabulary.test.ts states in its header: bold is reserved for names the app really has, 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, do not delete it silently — and must never be bolded.

The guard enforces it on content/docs/analytics/index.*, and only inside that page's ## Where to find things block (deliberately scoped: Dashboards / Reports / Cubes are phantoms as navigation items but real as page names). Nothing enforces it elsewhere.

The measurement

content/docs/analytics/reports.mdx and both its locale siblings bold report names that resolve to nothing in src/reports/. The section headings around them are explicit that the reports do not exist — "The three contract reports this section used to list are published nowhere", "src/reports/ publishes no marketing report" — so the prose and the typography disagree with each other:

  • :52 Lead Source ROI
  • :71 Reopened Cases
  • :87-89 Contracts Expiring, Active Contracts by Product, Renewal Pipeline
  • :97-98 Campaign ROI, Campaign Engagement

None of the seven is a label in src/reports/ (the barrel's labels are Accounts by Industry and Type, At-Risk Accounts, CSM-Flagged Accounts, Cases Opened by Priority × Day, Cases by Status and Priority, Customer Churn Signals, Lead Engagement by Month × Source, Opportunities by Stage, Opportunity Funnel by Owner → Stage, Pipeline Coverage by Forecast × Quarter, Recently Lost Opportunities, SLA Performance Report, Silent High-Value Accounts, Won Opportunities by Owner).

content/docs/analytics/cubes.mdx and its siblings have the same shape one level down. The Name by name list under the marketing section (:74-80) bolds metric names that are questions a reader arrives with rather than anything the app declares: Members enrolled / responded, conversion count, Sourced and influenced revenue, Campaign spend, cost per lead, cost per opportunity, Persona (job role). One bullet mixes the two weights in a single line, bolding ROI % — a real formula field — beside three spend figures no field carries. The page is right to name all of them; the weight is what says they exist.

Why it is worth a card rather than a drive-by fix

Both pages already use italics correctly for phantoms elsewhere (cubes.mdx:56 writes "reopened cases by agent" in italics, reports.mdx:98 writes Conversion by campaign), so this is an inconsistency inside a page rather than a page with no convention. Fixing it means re-reading every bold run on six files against src/reports/ and src/datasets/, which is a measurable pass of its own — and the same question ("should a guard read this?") that PR #1846's review already put to the maintainer applies to it, since a bold/italic rule over the analytics family is exactly the mechanical relation docs-analytics-vocabulary.test.ts already implements for one block of one page.

⛔ Per epic #1579's fence, no guard is proposed here — this is the third data point for the maintainer question already open from PR #1846's review, and the card is for the content pass.

Refs: #1847 · PR #1852 (where this was observed) · #927 / PR #932 (the convention) · PR #1846's review (the guard question).


Generated by Claude Code

Activity

  1. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed on Sep 10, 2026
  2. self-assigned this
    on Sep 10, 2026
  3. os-steve commented on Sep 10, 2026

    @os-steve
    Collaborator

    Claim: session_01DuzfS5chho38Yx1jxx9DEj → branch claude/issue-1853-analytics-bold-italic-pass

    Dispatched by the hotcrm PM seat (#1353). The dev inherits this claim — ⛔ no second Claim:, ⛔ never touch the assignee.

    Base off main fetched fresh (PR #1852 has landed on these same two pages; your pass runs over its output).
    Model: Opus. Deliverable: one PR, ready for review, pnpm verify green. ⛔ Do not arm auto-merge, ⛔ do not merge.

    PM verification — the measurement holds exactly

    src/reports/ publishes 14 reports, and their labels are:

    Accounts by Industry and Type · At-Risk Accounts · CSM-Flagged Accounts · Cases Opened by Priority × Day · Cases by Status and Priority · Customer Churn Signals · Lead Engagement by Month × Source · Opportunities by Stage · Opportunity Funnel by Owner → Stage · Pipeline Coverage by Forecast × Quarter · Recently Lost Opportunities · SLA Performance Report · Silent High-Value Accounts · Won Opportunities by Owner

    Each of the seven bolded names returns 0 hits under src/reports/ — checked one by one, not as a group:

    Lead Source ROI → 0 · Reopened Cases → 0 · Contracts Expiring → 0
    Active Contracts by Product → 0 · Renewal Pipeline → 0
    Campaign ROI → 0 · Campaign Engagement → 0
    

    And the convention is stated by the guard itself (test/docs-analytics-vocabulary.test.ts:47-50): "bold is reserved for names the app really has, italic 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, do not delete it silently — and must never be bolded."

    ⭐ Why this card is worth more than "typography"

    The prose on these pages is already honest — the headings say outright that the reports are published nowhere. It is the weight that lies. A reader skimming bold runs comes away with a list of reports to go find, and the sentence that would have corrected them is the one they skipped. ⇒ this is the same false-capability class as the four false-automation claims found on the marketing pages this shift, expressed in formatting instead of verbs.

    ⛔ Which is exactly why the fix is re-weighting, never deleting. The convention requires the phantom still be named and its real home stated.

    Scope and method

    Six files: content/docs/analytics/{reports,cubes}.{mdx,zh-Hans.mdx,zh-Hant.mdx}.

    Proof obligation

    • ⭐ Report a count, before and after: bold runs per page, how many resolve to a real label in src/reports/ / src/datasets/, how many do not. That number is the deliverable's evidence — "I re-read them" is not measurable, "17 bold runs, 7 unresolved before, 0 after" is.
    • Name every docs guard that reads these pages and why each stays green. ⚠️ docs-analytics-vocabulary.test.ts enforces this very convention — but only inside analytics/index's ## Where to find things block. Say explicitly whether your edits reach that block (they should not) and show the command.
    • ⚠️ docs-conversion-rate-spelling.test.ts requires 转化率 / 轉化率 to be present on both Chinese siblings of both pages — exactly 1 occurrence each today. ⛔ Do not let an emphasis edit drop the sentence carrying it.
    • ⭐ PR docs(marketing): name both Add to Campaign paths on campaign-members #1855's instrument is available if you want the guard read-set measured rather than reasoned: a scratchpad-only vitest config aliasing node:fs to a facade recording every read of the page, attributed per test file. ⛔ Keep it a probe — that alias breaks 7 unrelated fs-tooling suites.
    • pnpm verify stage by stage, every exit code captured before any pipe. Test-file / test counts before and after.

    ⚠️ Two siblings are live: content/docs/marketing/campaign-members* + campaigns* (#1854) and src/actions/** comments (#1184 phase 3). Neither meets your files.

    ⛔ No metadata change. ⛔ Nothing in test/**. ⛔ No content/docs/releases/ edit.


    Generated by Claude Code

  4. os-steve commented on Sep 10, 2026

    @os-steve
    Collaborator

    os-dev-report

    {
      "issue": 1853,
      "status": "done",
      "branch": "claude/issue-1853-analytics-bold-italic-pass",
      "pr": "https://github.com/objectstack-ai/hotcrm/pull/1861",
      "premise_still_valid": true,
      "summary": "The premise held and was an undercount: re-reading every bold run on all six pages against a declared-label index built from src/ (2936 label/title/heading string literals) found 20 unresolved bolded name claims per reports locale and 9 per cubes locale — 87 across the six pages, against the seven the card listed. All 87 are now italic at the same site in en / zh-Hans / zh-Hant, nothing deleted, every phantom still naming where the real thing lives. Three sites took judgement rather than a sweep: the cubes marketing bullet now carries three italic spend figures beside the real bold ROI % on one line; Persona (job role) is italic while the Title field it points at stays bold; and the bullet calling `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 — that is the one prose change in the diff, the other 84 edits being pure weight flips. No guard proposed (epic #1579's fence), nothing under src/ or test/, no metadata change, no releases/ edit; the PR carries both the dispatch's verbatim footer and the platform-appended session footer.",
      "tests": "pnpm verify stage by stage, every exit code captured before any pipe, heavy stages through the container's shared verify lock: validate 0, typecheck 0, lint 0, lint:i18n-gate 0, hygiene 0, hygiene:tokens 0, build 0 (Artifact: dist/objectstack.json 1918.4 KB), test 0. Test-file / test counts identical before and after — 'Test Files 165 passed (165) / Tests 3455 passed | 1 skipped (3456)' on both runs, as expected for a content pass. GUARD READ-SET MEASURED, NOT REASONED: a scratchpad-only probe aliasing node:fs to a generated facade that re-exports all 106 of the module's names and wraps the read entry points, attributing each read of content/docs/analytics/ by call stack (which catches module-top-level reads that expect.getState().testPath misses). It found 14 guards reading the six pages where reasoning found 4 — docs-analytics-vocabulary, docs-anchor-links, docs-conversion-rate-spelling, docs-dashboard-tiles, docs-drift, docs-locale-callouts, docs-metadata-counts, docs-object-term-consistency, docs-retired-personas, docs-role-hierarchy, docs-runnable-samples, docs-setup-navigation-names, docs-view-rosters, docs-zh-hant-justification (heading-label reads the analytics dir but only dashboards/index). Because the facade re-exports the complete surface rather than a subset, it broke nothing: the probe run was byte-identical to the unprobed baseline (165 files / 3455 tests), unlike PR #1855's, which broke 7 fs-tooling suites. Not committed. VOCABULARY-GUARD SCOPE: it enforces this convention only inside analytics/index's '## Where to find things' block, and the diff does not reach it — `git diff --name-only origin/main...HEAD | grep -c 'analytics/index'` prints 0 over the seven-file change set. The three dots are load-bearing: #1854 and #1184 phase 3 landed on main after this branch was cut, so the two-dot form credits 16 of their files to this PR. CONVERSION-RATE SPELLING: 转化率/轉化率 counted per file before -> after, 1 -> 1 on all four Chinese siblings. PARITY: all six pages move identically, reports 130 -> 110 bold runs and cubes 83 -> 76, every planned site verified italic on disk with none left bold. Control-byte self-scan over the changed files (grep -naP over the C0 set plus DEL): no hits.",
      "mcp_calls": "6 — issue_read get, issue_read get_comments, pull_request_read get_reviews (PR #1855, returned empty so the probe was rebuilt from scratch), search_issues (dedupe for the finding below; REST /search/issues answered 403 in this container, so that one read switched channel to MCP as the fallback allows), issue_write create (#1862), add_issue_comment (this report). Card and PR bodies otherwise read via git and REST; PR #1861 was created over REST, not MCP.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #1862: analytics/reports italicises seven names the app really does have (four published report labels at :120/:148/:149/:150, the chart titles at :21 and :29, the Stale Opportunities tab label at :30) and cubes italicises the two real position names at :40 — the same convention pointed the other way. Deliberately NOT swept into this PR: it may not be a defect at all, because the page arguably uses italics for a third purpose (quoting a title in running prose), and the card needs the maintainer to say whether the rule governs every occurrence of a name or only the one that introduces it."
      ]
    }

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationi18npm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions