Skip to content

fix(card): the standing-rule line names this period's prescription, not the rule the user actually committed to #645

Description

@atomchung

Status

Defect. Found while reviewing PR #644 (#546), reproduced on main@ad4289e. Same falsehood as #546, moved from first-time users to returning ones — which is why it only became visible once #546 routed returning users into that branch deliberately.

The observation

card_renderer._next_block's no-commitment branch resolves the rule text once, from this period's prescription, and uses it in both the pending and the standing wrapper:

standing = (localized_rule(state.get("rule_dim"), language,
                           cap=state.get("max_position_pct"))
            if state.get("rule_dim") else None)
...
standing_key = "rule_standing" if prior_commitment.get("rule") else "rule_pending"
text = missing[standing_key].format(rule=standing)

rule_dim is actionable[0].get("dim") (trade_recap.py:2018) — the top scored problem this period. It has no input from prior_commitment. The two are independent by construction, so they diverge whenever the book's leading problem changes, which is the ordinary case across weeks.

Reproduced

Rendered directly, en, same prescription (position_sizing) in both, only the persisted commitment differing:

prior_commitment.rule = "Hold any new position at least 30 days before selling"

rendered              = "No rule change this period; the standing rule remains:
                         \"Cap any single position at 20%. Trim if it goes over, and do not add.\""

The user committed to a holding-period rule. The card tells them their standing rule "remains" — and then names a concentration rule they never chose.

Why it matters

Both halves of the sentence are wrong at once, and they reinforce each other: "no rule change this period" says continuity, and the quoted rule is the evidence offered for it. A user reconciling against what they committed to last time reads a rule they did not write and has no way to tell whether the product forgot their answer or silently replaced it. This is the same class as #546 and the same class as #429's dead question — a sentence whose truth nobody checked because the surrounding block was about something else.

It is worse than #546 in one respect: a first-time user has no memory to contradict, so the false claim is merely confusing. A returning user has an actual commitment they can compare against, so the product visibly disagrees with its own record.

Not in #546's scope, deliberately

#546's acceptance says "Returning-user preview with a real prior commitment may use the standing-rule continuity copy", and its stop condition forbids widening. PR #644 is correct as merged; this is the next cut.

Decision needed before implementing — two readings, and they are different products

  1. The continuity line quotes the prior commitment. standing comes from prior_commitment["rule"] when one exists. Truthful and simple, but the sentence then says "no rule change this period" while the engine may in fact be prescribing a different dimension — the card would stop surfacing that divergence at all.
  2. The line only fires when they agree, and a divergence gets its own honest wording (the engine now points somewhere else than your standing rule). More work, and it needs new copy in three locales, but it is the only reading where the block keeps saying something true and useful.

The prior_commitment payload carries rule, metric_key and metric_value (read at card_renderer.py:2325 for #292) — whether it carries a dim comparable to state["rule_dim"] needs checking before option 2 is costed.

Scope

  • Whichever reading is chosen, the quoted rule and the continuity claim must agree with the record.
  • Preview and finalized card both, and Markdown and HTML through the shared _card_structure path.
  • en / zh-TW / zh-CN synchronized; replace sentences rather than adding, per the standing no-explanatory-Note ruling.
  • docs/output-contract.md's Block-4 row moves with it (mirrored surface).

Acceptance

  • A returning user whose prior commitment differs from this period's prescription never sees a rule they did not choose presented as standing.
  • A returning user whose commitment and prescription agree still gets the continuity copy.
  • A first review is unaffected — fix(card): pre-commitment preview falsely implies a standing rule exists on a user's first-ever review #546's rule_pending path stays exactly as merged.
  • Markdown and HTML carry the same semantic line; three locales synchronized.
  • Mutation: restoring the prescription as the quoted rule reddens a focused test.
  • python3 tests/run_all.py passes.

Privacy

Fresh isolated roots and committed fictional personas only.

Related

#546 (the first-time-user half, merged as PR #644), #292 (the prior-commitment reconciliation path that already reads the correct predicate), #356 (an earlier defect in this same branch), #429 (a sentence nobody reads is a defect, not neutral).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions