Repository navigation
docs(analytics): correct the campaign inventory the cube argument rests on - #1852
Conversation
…against source `analytics/cubes` and `analytics/reports` — all three locales of each — said `crm_campaign_member` stamps First Opened, First Clicked, Response Date and Responded per member. Two of those four were deleted in #597; the member's response block is `status` / `response_date` / `has_responded`, under its Response Tracking group. `analytics/reports` carried the claim a second time as a paraphrase ("the opens, clicks and responses are stamped on each member record"), in all three locales. Both pages also placed the campaign's whole money block in the Performance section. Five of the fields they name are grouped under Budget & ROI — budgeted_cost, actual_cost, expected_revenue, actual_revenue and the roi formula (campaign.object.ts:144-195, :243; campaign.view.ts:152-158). Performance holds the six counters and response_rate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PM review → accepted, auto-merge armed.CI 9/9 green on ⛔ You falsified one of my rulings, and you are rightMy dispatch said, as a ruling not a hint: "The campaign half of the same sentence is correct and stays — the Performance section it names is a real field group." True of the fields, false of their section, exactly as you put it. I re-derived it before arming this: and ⭐ And it is the same defect PR #1850 fixed one page over (Costs → Budget & ROI). Two pages, two different wrong names for the same section, neither of which a reader could find — which says the drift is in how these pages were written, not in one sentence. Fixing it rather than filing it was the right call and I want the boundary stated so it is not read as licence: it is one clause of the sentence this card exists to rewrite. ⛔ It is not a precedent for correcting whatever else a page gets wrong once you are in it — which is precisely why #1853 went out as a card instead. Using the fields' declared labels (Number Sent / Number of Responses / …) instead of the compressed The verification is the strongest of this docs series
The rewrite says something stronger than the card asked for"An open or a click is not an unaggregated figure but an unrecorded one." ⭐ That is the sentence the two pages needed. My dispatch framed the risk as an inventory listing deleted fields; the real damage was that the surrounding argument — why campaign analytics has no cube — implied the data exists and merely is not rolled up. Sourcing the negative from the object docblock's own platform measurement (outbound-only email service, #1853Correctly filed rather than swept: a page-wide typography pass over six files is not a clause of this card's sentence, and the #927 / PR #932 convention (bold = names the app has, italics = names a reader arrives with) makes it a real inconsistency inside a page rather than a style preference. ⭐ Noting that Auto-merge armed (squash). #1847 closes on merge — third and last family of the #597 sweep. Generated by Claude Code |
Fixes #1847
Six files —
analytics/cubesandanalytics/reports, three locales each — still described the campaign member #597 removed, in the passage that argues why campaign analytics has no cube. Rewritten against what the metadata declares today: the member's response block isstatus·response_date·has_responded(campaign_member.object.ts:215·:232·:242), grouped under Response Tracking (:95), and the app records no open, click or bounce at all — the object's own docblock (:12-28) carries the platform measurement.⭐ One of the dispatch's rulings did not survive measurement
The dispatch ruled: "The campaign half of the same sentence is correct and stays." The fields are correct and they stay. Their section is not, and it is inside the same sentence, not beside it:
Measured on
main@c423673: five of the fields those sentences place in Performance are grouped under Budget & ROI —budgeted_cost(campaign.object.ts:145),actual_cost(:152),expected_revenue(:159),actual_revenue(:182) and theroiformula (:244), against{ key: 'budget', label: 'Budget & ROI' }at:40. The form agrees and says why:campaign.view.ts:157-160putsroibeside the two manual-entry cost fields it divides by, "rather than at the bottom of Performance, where its dependency on two fields three sections away was invisible". Performance (campaign.object.ts:41, form atcampaign.view.ts:163-175) holds the six counters andresponse_rate.This is the same defect class PR #1850 corrected one page over (Costs → Budget & ROI on
marketing/campaigns), and it is the same defect as the member half: a name that does not resolve. It is fixed here rather than filed, because it is one clause of the sentence this card exists to rewrite — not a widening into what else the page gets wrong.The rest of the PM's re-measurement held exactly:
cubes.mdx:72andreports.mdx:95carry the four-stamp sentence verbatim, both Chinese siblings carry it with the English field names inside Chinese prose — confirmed on all six files.reports.mdx:98's paraphrase is not English-only, as the filing had it. All three locales carry it, at:98in each, exactly as the dispatch re-measured.cubes.*carries no equivalent paraphrase — re-checked independently:grep -niE "open|click"oncubes.mdxreturns three hits, all of them about cases (the day a case was opened, reopened cases by agent, open/new/resolved counts), and the Simplified and Traditional siblings return zero hits for 打开 / 点击 / 開啟 / 點擊.Per file — what was rewritten, and where each new claim comes from
analytics/cubes.mdx(+.zh-Hans/.zh-Hant) — the Marketing — no dataset, no cube section, one paragraphcrm_campaign_memberstamps First Opened, First Clicked, Response Date and Responded per member"campaign_member.object.ts:215/:232/:242, groupresponselabelled Response Tracking at:95. Responded was not a field either:has_respondedis the boolean,statusthe picklistcampaign.object.ts:41,:190-237); costs, revenues and ROI % in Budget & ROI (:40,:145-182,:244):201), Number of Responses (:207), Number of Leads (:213), Converted Leads (:219), Opportunities Created (:225), Won Opportunities (:231)analytics/reports.mdx(+.zh-Hans/.zh-Hant) — 📣 Marketing reports, two sites:95src/views/campaign.view.ts)"campaign.view.tscitation now pointing at a true statement (:157-160and:163-175):98Why no callout here, unlike PR #1846 and PR #1850: neither page carries a single blockquote today (0 in all six files), and the negative claim belongs inside the inventory it corrects rather than beside it. Callout parity is therefore still 0/0/0 per page — see the guard table.
Chinese wording
zh-Hans takes its response vocabulary from the zh-CN pack — 响应 · 已响应 · 响应时间 (
src/translations/zh-CN/objects.marketing.ts:110-123) — and its negative claim from the wording PR #1846 shipped oncampaign-members.zh-Hans:59: 「本应用不跟踪打开、点击或退信」. zh-Hant mirrors it in each page's own Traditional conventions — 回應, not 響應 (the ruling on PR #1846), 開啟/點擊/退信 ascampaign-members.zh-Hant:59writes them, and 彙總 rather than 汇总/聚合 because that is the word both Traditional analytics pages already use for aggregation. Field and section names stay English on both Chinese pages — every other campaign field in these paragraphs is already written that way, and 時間戳 for stamp is the spellingcubes.zh-Hant:52already uses.Docs guards — every one that reads these six files, and why it stayed green
docs-conversion-rate-spelling.test.tsCARRIERSledger names both of these pages: 转化率 / 轉化率 must be PRESENT in each Chinese locale, and no Chinese page may spell it 转换率cubes.zh-Han*:83andreports.zh-Han*:52— outside both edited paragraphs, and re-counted after the edit: still exactly 1 in each of the four files, 0 occurrences of the rejected spelling anywhere incontent/docs/analytics/. Ablated belowdocs-locale-callouts.test.tscubesand 0/0/0 onreports, before and after — no callout added or removed. Ablated belowdocs-analytics-vocabulary.test.tsanalytics/indexrules read the landing page by name; its two tree-wide sweeps (no page draws acubes/directory; the ≥100-page vacuity guard) do read all six filessrc/cubes/path added — the paths these paragraphs name aresrc/datasets/campaign.dataset.tsandsrc/views/campaign.view.ts, both real; the landing page is untoucheddocs-dashboard-tiles.test.ts.mdxundercontent/docs: a**Name**bold run followed by a tile word must be a real widget titledocs-anchor-links.test.ts/docs/marketing/campaignsand its locale twins) are unanchored and unchangeddocs-drift.test.tsdocs-metadata-counts.test.tsREADME.md+ every.mdx, for count claims in 20 declared spellings(\d+) datasetsdocs-object-term-consistency.test.tscrm_case/crm_quotespellingsdocs-role-hierarchy.test.ts,docs-retired-personas.test.ts,persona-copy.test.tsdocs-zh-hant-justification.test.tsdocs-setup-navigation-names.test.ts**App → …**path incontent/docs/**docs-runnable-samples.test.tscontent/docs+src/docsfor documented agent names and the action-example selection keypnpm hygiene(check-source-hygiene.mjs)content/grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'— no hitsdocs-src-tree-paths.test.ts,heading-label.test.ts,docs-object-coverage.test.ts,docs-view-rosters.test.tsPRODUCT_TREE_DOCSis six getting-started/customization pages,heading-labelis scoped to the threedashboardspages, and neither ledger has an analytics rowNothing would have caught this drift — the third page family in a row where that is true. ⛔ Per epic #1579's fence no guard is added here; this is the third data point for the question already with the maintainer from PR #1846's review, not a third attempt to answer it.
⭐ Ablations — two guards this PR did not break, proven able to catch it
Both were run on the committed tree (
fa0efba), each mutation proven on disk by content count and blob hash before the run, each restored withgit checkout HEAD -- PATHand the restoration proven by an emptygit diff HEADand a hash equal to theHEADblob.1.
docs-conversion-rate-spelling.test.ts— the carrier leg. Replaced 「按人物画像的转化率」 with 「按人物画像的每线索成本」 oncubes.zh-Hans.mdx— the sentence stays, the metric leaves. On disk: 转化率 count1 → 0, injected text count1, blobed7f4bc → 6ae12b3. Result: exit 1,× 'analytics/cubes' still states the metric in both scripts—AssertionError: expected '---\ntitle: 多维数据集…' to contain '转化率', 1 failed | 3 passed. Restored: blob back toed7f4bc,git diff HEADempty.2.
docs-locale-callouts.test.ts— the parity leg. Inserted one> **ABLATION CALLOUT — English only.**block intoreports.mdxonly, the exact mistake this PR would have made had it added a callout the way PR #1846 and PR #1850 did. On disk: blockquote lines0 → 1, marker count1, blobd29a8a5 → f9d0e25. Result: exit 1,× every translated page has the same number of callouts as its English page—content/docs/analytics/reports.zh-Hans.mdx: 0 callout(s), but content/docs/analytics/reports.mdx has 1, and the same for.zh-Hant. Restored: blob back tod29a8a5,git diff HEADempty.Verification
pnpm verifyrun stage by stage on the committed tree, every exit code captured before any pipe (cmd > log 2>&1; EXIT=$?):pnpm validatecrm_campaignorcrm_campaign_memberpnpm typecheckpnpm lint4 warning(s), 12 suggestion(s)pnpm lint:i18n-gate✓ i18n lint gate: 0 i18n/missing-* issuespnpm hygiene✓ source hygiene cleanpnpm hygiene:tokens✓ source token ratchet clean— authored total ~138,265 of ~140,000, unmoved: the ratchet measuressrc/**/*.tsand this PR touches nonepnpm builddist/objectstack.json (1916.9 KB)pnpm testTest-file / test counts are identical before and after: 165 / 3455 passed / 1 skipped measured on the pre-change tree at
c423673, and the same onfa0efba. No test file added, removed or edited — ⛔ nothing intest/**is touched.CI: this PR's paths put it on the Docs App workflow (
content/docs/**filter) and on Link Check (**/*.mdxfilter, which then scans the.mdfiles — the changeset).Scope
Six docs files plus the changeset, nothing else. ⛔ No metadata change — #597 removed the member's tracker columns because nothing could write them, and this PR does not re-add them. ⛔ Nothing in
test/**. ⛔ Nocontent/docs/releases/edit. The two live siblings (src/dashboards/executive.dashboard.tson #1849,content/docs/marketing/campaign-members.*on #1845) meet none of these files.Observed, not fixed here
docs-analytics-vocabulary.test.tsenforces onanalytics/index(bold for names the app has, italics for names a reader arrives with). It is a page-wide convention on these two pages, shared with the contract-report bullets above them, so correcting it is a page-typography pass rather than a clause of the sentence this card names. Reported rather than swept.🤖 Generated with Claude Code
https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
Generated by Claude Code