Skip to content

fix(seed): reconcile the Acme narrative, and flag a non-customer - #1657

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-1646-seed-book-narrative-facts
Sep 6, 2026
Merged

fix(seed): reconcile the Acme narrative, and flag a non-customer#1657
os-steve merged 1 commit into
mainfrom
claude/issue-1646-seed-book-narrative-facts

Conversation

@os-steve

@os-steve os-steve commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Closes #1646
Closes #1647

Description

Two corrections to src/data/sales.seed.ts, folded because they answer one
question: does a hand-written assertion in the seed book agree with the rows
sitting next to it.

#1646 — the Acme description. The card named one sentence. Verifying its
claim that every other sentence reconciles turned up two more, so all three
are corrected here (the card's own reasoning applies unchanged to each: it is
the longest piece of hand-written narrative in the seed book, and nothing
mechanical will ever find a false line in it).

#1647 — the flagged panel that could only render one row. Stark Medical
now carries health_score: 'at_risk', taking the route the grading ruling
picked: an at_risk partner satisfies the panel criterion and is
semantically sound, so the card's "invent bad data or soften the comment"
dilemma does not bind. The block's comment is true and is untouched.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Changes Made

1. "Renewal due in 45 days" (#1646, the named sentence)

No seeded record carries a 45-day renewal horizon. Measured on this branch:

claim record measured
renewal due in 45 days Acme Annual Renewal 2025 closed_won, close_date = daysAgo(15)
contract horizon Acme contract in revenue.seed.ts end_date = daysFromNow(335), auto_renewal: true
the governance workshop Acme Platform Upgrade (OPEN) close_date = daysFromNow(30), next_step names the workshop

The sentence had folded the open upgrade into a renewal that was already won.
It now names the upgrade, its real horizon, and the workshop that gates
signature — the shape the ruling asked for.

2. "Slipped one opportunity ($75K add-on) ... due to slow procurement cycle"

Acme Add-on (Lost) is closed_lost with loss_reason: 'timing' and
loss_details naming a two-year HubSpot contract on Acme's marketing org.
Procurement appears nowhere on that deal, and the deal did not slip — it was
lost. The line now states the loss and the reason the record gives.

3. "Login issues ticket is approaching its SLA"

sla_due_date is derived from the priority x tier matrix
(src/objects/_case-sla.ts). That case is high on an enterprise account
and two days old, so it is due 8 hours after creation — its clock ran out
roughly 40 hours before the demo boots. It is past its SLA, not approaching
it; case_sla_monitor flags it on its first sweep. needs eyes today is kept
because it is still true.

Everything else in that description reconciles and is byte-identical: the
$220K ARR and 22% uplift match the closed renewal, the open $150K upgrade
matches the opportunity, and the open ticket and the billing dispute match
seeded cases.

4. Stark Medical is flagged at_risk (#1647)

csm_flagged_accounts groups by type to separate a flagged customer from a
flagged prospect or partner — the one thing the grid view
crm_account.at_risk_accounts cannot show. That is not a matter of comment:
the view's filter carries { field: 'type', operator: 'equals', value: 'customer' }
ahead of the health term, verified in the implementation.

at_risk rather than churning is the honest severity as well as the
matching one: Stark's pilot was won, its expansion died on no_budget 60
days ago, and the partnership contract is still in legal review — a partner
can be at risk, but was never a subscription that could churn.

FLAGGED grouping, computed with the panel's own criterion read off the report
metadata (is_active: true AND health_score $in ['at_risk','churning'],
rows: ['type']):

              before                          after
FLAGGED       Initech  (at_risk,  customer)   Initech  (at_risk,  customer)
              Wayne    (churning, customer)   Wayne    (churning, customer)
                                              Stark    (at_risk,  partner)

panel rows    customer: 2      -> 1 row       customer: 2, partner: 1  -> 2 rows

Stark's clock stays at today(), so like Wayne it is outside every windowed
panel: it reaches csm_flagged_accounts and no other block, and the
type == 'customer' grid view still cannot see it. That is the report-block
versus grid-view difference demonstrated on data for the first time.

5. The doctrine block records the third row and the blanks

Only five of nine accounts carried health_score before this PR, and the four
blanks are exactly the four non-customers. Judged not a stated convention:
this file writes its deliberate omissions down (billing_country / territory
"deliberately NOT authored here", Apex's other bucket "a stated
classification here, not a blank", Lattice's missing state), and no comment,
guard roster or field constraint mentions these. The health_score block now
says why Stark is filled and why the three prospects stay blank — a CSM
asserts something about a relationship, and nobody has been in the room with
an account that was never won.

No guard is added, on either card: free prose has no mechanical relation to the
rows it narrates, and pinning a seeded distribution here was ruled out twice.

Testing

pnpm verify fully green on the final commit — validate, typecheck,
lint, lint:i18n-gate, hygiene, hygiene:tokens, build, test:

✓ Validation passed (1369ms)
✓ i18n lint gate: 0 `i18n/missing-*` issues
✓ source hygiene clean
✓ source token ratchet clean      (src/data is outside the ratchet by ruling)
Artifact: dist/objectstack.json (2039.9 KB)

Test Files  161 passed (161)
     Tests  3400 passed | 1 skipped (3401)

Specifically re-verified after the change:

Out of scope — found while measuring, not fixed here

Three record-to-record contradictions turned up around Acme that are not
in either card's description. None is touched by this PR; they need their own
cards (the dedup search could not run — see the report).

  1. The governance workshop has three different schedules. The opportunity's
    next_step says "the week of close_date - 14d" (= daysFromNow(16)); the
    seeded event is planned for daysFromNow(6) with invitations already out;
    and the task asking someone to schedule it is not_started, due
    daysFromNow(7) — a day after the workshop it plans.
  2. An activated contract for a deal still in proposal. The Acme contract
    is status: 'activated', signed_date: daysAgo(32), contract_value: 150000,
    and it links crm_opportunity: 'Acme Platform Upgrade' — an opportunity that
    closes in 30 days at 60%.
  3. The generated demo cases couple account to status perfectly. In
    service.seed.ts the 30-case generator indexes both a 5-element account list
    and a 5-element status list by i % 5, so every Acme demo case is new,
    every Globex one in_progress, every Wayne one resolved, every Initech one
    closed and every Stark one escalated. No account shows a status mix.

Generated by Claude Code

Two corrections to `src/data/sales.seed.ts`, both answering one question:
does a hand-written assertion in the seed book agree with the rows sitting
next to it. #1646 and #1647.

The Acme description is the longest piece of hand-written narrative in the
seed book and the one an evaluator is most likely to read end to end. Three
of its lines had drifted off the records they name.

"Renewal due in 45 days" matched nothing. The renewal closed_won 15 days
ago, the contract runs another 335 days and auto-renews, and the AI
governance workshop belongs to the OPEN platform upgrade 30 days out. The
line had folded an open upgrade into a renewal already won; it now names the
upgrade, its horizon, and the workshop that gates the signature.

Checking the card's claim that every other line reconciled turned up two
more. The $75K add-on was not "slipped due to a slow procurement cycle on
their side": it is closed_lost on loss_reason 'timing', with loss_details
naming a two-year HubSpot contract on their marketing org. And the login
ticket is not "approaching its SLA": since due dates became derived from the
priority x tier matrix, a high-priority case on an enterprise account is due
8 hours after creation, so that clock ran out about 40 hours before the demo
boots. Both lines now state what the records state. The rest of the
description reconciles and is untouched.

Stark Medical now carries health_score 'at_risk'. csm_flagged_accounts
groups by type to separate a flagged customer from a flagged prospect or
partner, which the at_risk_accounts grid cannot show because it filters
type == 'customer' first. Every flagged account was a customer, so the panel
rendered one group row and demonstrated none of that. A partner whose pilot
was won and whose expansion died on a capital freeze can be at risk, while
churning would describe a subscription it never had, so the honest severity
is also the matching one. Computed with the panel's own criterion read off
the report metadata:

  before  customer: 2                 -> 1 group row
  after   customer: 2, partner: 1     -> 2 group rows

The health_score doctrine block records the third row and states why the
three prospects stay blank. No guard is added: free prose has no mechanical
relation to the rows it narrates. The territory partition (6 NA / 2 EMEA /
1 other) and the 41 / 72 / 104-day activity bands are unchanged — no address
and no activity clock moved. No report, panel criterion, object, view or
test changed.

Co-authored-by: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 6, 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 6, 2026 5:05am UTC

Request Review

@github-actions github-actions Bot added the metadata Declarative metadata — schema, security posture, UI surfaces label Sep 6, 2026
@os-steve
os-steve marked this pull request as ready for review September 6, 2026 06:12
@os-steve
os-steve added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 0ec59c2 Sep 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

2 participants