docs(campaign): name the metric block's real writers, per site - #1690
Merged
Conversation
`campaign_snapshot_metrics` was retired in #597 and the campaign metric block is now owned by four refresh hooks — `campaign_metrics_refresh`, `campaign_attribution_refresh`, `campaign_lead_conversion_refresh` in `campaign.hook.ts`, and `campaign_member_metrics_refresh` in `campaign_member.hook.ts`. Several live comments still named the retired hook as the current writer. A tree-wide grep found nine occurrences over seven files, not the four the audit listed. Each was read on its own terms rather than renamed in bulk, because several of them narrate what changed and are meant to keep the old name. Named the real writer where the comment claimed the hook was live: - `campaign-completion.flow.ts` called it "the existing `campaign_snapshot_metrics` afterUpdate hook" that "then snapshots into metrics". The nightly flip is a `status` transition, so `campaign_metrics_refresh` recomputes on it — and the block was already current before the sweep ran, so the note says refresh rather than snapshot. - `sales.seed.ts` described the opportunity `crm_campaign` link as what the retired hook "counts when a campaign completes". `campaign_attribution_refresh` is what counts attributed opportunities, on every insert, update and delete. - `seed-consistency.test.ts` listed the retired hook in its hook-to-field map and named a `describe` block after it. Both now name the refresh, and the block carries the four hook names. The `it` inside that still explained its assertion as a completion-time snapshot was corrected as well: the renamed block would otherwise have attributed completion-only firing to the four refresh hooks. Marked as history where the mention is deliberate: - `campaign-member-lifecycle.test.ts` needs the old name to explain why a completion-time assertion cannot prove the acceptance criterion. It now opens "The RETIRED `campaign_snapshot_metrics` — gone since #597" instead of leading with a bare hook name in the past tense. Left alone, already self-evidently historical: `campaign.hook.ts` ("The old …"), `campaign_member.hook.ts` ("the removed …"), `campaign.object.ts` ("the long-retired …", corrected by #1670) and that PR's changeset ("a hook retired long ago"). No assertion changed: comment, block-name and prose only. `pnpm verify` green. Co-authored-by: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-steve
marked this pull request as ready for review
September 6, 2026 10:56
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1668
campaign_snapshot_metricswas retired in #597. The campaign metric block is now owned by four refresh hooks —campaign_metrics_refresh,campaign_attribution_refresh,campaign_lead_conversion_refresh(campaign.hook.ts) andcampaign_member_metrics_refresh(campaign_member.hook.ts); all four names re-verified as livename:declarations onorigin/main.The count first: nine occurrences, not four
The card listed 4 files. A full-tree grep (
git grep -n, plus a rawgrep -rnover the working dir includingcontent/,docs/,scripts/to catch anything untracked) finds nine occurrences across nine files.content/,docs/andscripts/are clean — every hit is insrc/,test/or.changeset/.That is one more file than the dispatch's own count of 8:
.changeset/six-readonly-notes-audited-per-writer.mdlanded with PR #1670 after that grep was taken.Per-site decision
Read and decided per site, not renamed in bulk — several occurrences narrate what changed and are supposed to keep the old name.
src/flows/campaign-completion.flow.ts:14campaign_snapshot_metricsafterUpdate hook then snapshots into metrics" — a live claim, and false.src/data/sales.seed.ts:929campaign_snapshot_metricscounts when a campaign completes" — present-tense data relationship.test/seed-consistency.test.ts:24test/seed-consistency.test.ts:274describeblock named for the retired hook.test/campaign-member-lifecycle.test.ts:235src/objects/campaign.hook.ts:93campaign_snapshot_metricsfired on→ completedand nothing else", followed by "Completion is now simply one of the transitions this catches."src/objects/campaign_member.hook.ts:168campaign_snapshot_metricsmade everyone wait for."src/objects/campaign.object.ts:169.changeset/six-readonly-notes-audited-per-writer.md:36What (a) resolved to
in_progress → completed, which is astatustransition, socampaign_metrics_refreshrecomputes on it. The note now also says this is a refresh, not a snapshot — the block was already current before the sweep ran.campaign_attribution_refresh(object: 'crm_opportunity',afterInsert/afterUpdate/afterDelete, computingnum_opportunities/num_won_opportunities/ summedactual_revenue) — on every opportunity write, not once at completion.seed-consistency.test.ts: the map entry and thedescribeboth name the refresh, and a comment above the block carries all four hook names.One bounded in-place fix, declared
Inside the renamed
describe, anitstill explained its assertion as a completion-time snapshot ("The hook only fires on the transition INTOcompleted"). Renaming the block re-points that comment at the four refresh hooks, making it newly false — so it was corrected in the same edit. Same defect class as the card, prose +itname only, no new verification surface.Verification of the card's own premises
campaign.object.ts:166/185. Commitb63e0e76replaced both notes: line 166's "the campaign_snapshot_metrics hook writes these through the data API, and 16.x drops writes to readonly fields" and line 185's "the campaign_snapshot_metrics hook writes this rollup". One occurrence survives at line 169, and it is correct: "not by the long-retiredcampaign_snapshot_metrics", followed by all four names. Nothing done here.origin/main.test/hook-write-shape.test.tsneeded no change — it is in epic Epic: bring this repo's test farm back under the 2026-08-31 ruling — platform-first,os lint --strictfirst, then retire the local re-implementations by family #1579 family F6 (Retire the local hook / action / flow write-shape tests the platform's *-body-write-* and flow-node-write rules already enforce (epic #1579, step 3, family F6) #1587)'s retirement table, and its occurrence is already exemplary history: "campaign_snapshot_metricsused to sit here alone… it was replaced by a refresh that runs on every input change." Left untouched, so the F6 question never arises.src/objects/campaign_member.object.ts(crm_campaign_member.added_date can honestly be declaredreadonly— its only writers are INSERTs, which the readonly strip never touches #1667, in the decision box), and none of [finding] The 17.3.0 upgrade left 19 comments asserting 17.2.0 is "the pinned" version — third recurrence of #1460 / #1467, and #1669 names only 1 of the 13 files #1676's 13 version-label files.Acceptance
After this change, a reader who greps
campaign_snapshot_metricsgets six hits, and every one is past tense and self-identifying as history: "a hook retired long ago" · "The old …" · "the long-retired … : [all four names]" · "the removed …" · "The RETIRED … gone since #597, replaced by the four refresh hooks" · "used to sit here alone … it was replaced by". Three of the six name the replacement hooks outright. No hit reads as live.Constraints honoured
expect(line at all, added or removed — including the message arguments. Only comments, onedescribename and oneitname.content/docs/releases/untouched.test/, so the prose is not chargeable:business semantics ~85,032·interaction layer ~37,963·authored total ~137,336, all unchanged and clean.Tests
pnpm verifyfully green, exit 0, at4050ba00— all eight stages ran (validate,typecheck,lint,lint:i18n-gate,hygiene,hygiene:tokens,build,test):🤖 Generated with Claude Code
https://claude.ai/code/session_018xtjdpZFjgWh4Ad9Wcx68J
Generated by Claude Code