Skip to content

feat(quote): show the discount ceiling on the quote-generation screen - #1711

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-1214-discount-ceiling-visible
Sep 6, 2026
Merged

os-steve merged 1 commit into
mainfrom
claude/issue-1214-discount-ceiling-visible

Conversation

@claude

@claude claude Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Part of #1214 — item 4 only. The card stays open: item 2's owner half is routed
upstream (objectstack#16290) and has not landed here.

Description

The Generate Quote screen asks for a Discount % and said nothing about
the 60% ceiling. That ceiling is a hard block with no override — the
discount_within_ceiling script validations on crm_quote and
crm_quote_line_item — so the only way for a rep to learn the number was to
enter one, submit, and read the rejection.

The screen field now reads Discount % (≤ 60) and carries 0-60 as its
placeholder. Both strings interpolate QUOTE_DISCOUNT_CEILING from
src/objects/_thresholds.ts, imported rather than retyped, matching what the
two validation rules already do. _thresholds.ts itself is untouched.

⛔ The ceiling is unchanged and it still blocks. This PR only makes the rule
visible where it applies.

Type of Change

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

Related Issues

Part of #1214 (item 4). Unblocked by #1206, whose fix shipped in PR #1700.
This PR does not address #1214's remaining item, which stays open.

Changes Made

  • src/flows/quote-generation.flow.ts — import QUOTE_DISCOUNT_CEILING; the
    discount screen field gains an interpolated label and placeholder, plus
    a comment recording why there is no max.
  • .changeset/discount-ceiling-is-visible-where-it-applies.md — hotcrm: patch.

What was measured, and what could not ship

The card asked for a hint plus a client-side max. The max half is not
authorable at platform 17.3.0, measured rather than assumed:

key 17.3.0 result
max / min rejected by name — ScreenFieldConfigSchema is strict; Unrecognized key(s) on this screen field
helpText / description rejected the same way on a screen field
label accepted, forwarded, always visible
placeholder accepted, forwarded, visible only while the input is empty

ScreenFieldConfigSchema's entire key set is name / label / type /
required / options / defaultValue / placeholder / visibleWhen, and
the executor forwards exactly those into the ScreenSpec the client renders.
So max fails pnpm validate rather than quietly doing nothing — it is not a
key that could have been authored and left inert. The browser still lets a rep
type 70; the difference is the field now told them it will be refused.

Two further measurements shaped the result:

  • The label is the load-bearing carrier, not the placeholder. The dialog
    seeds its form state from defaultValue, and this field has defaultValue: 0,
    so the input is never empty on open and the placeholder surfaces only for the
    moment the rep clears the box to type. Useful, but it cannot be the only hint.
  • No screen-level description was set. It is authorable, but the dialog
    already falls back to a fully localized platform subtitle in all four locales.
    Overriding it would have traded localized text for an English-only string.

i18n

No translation entry was added, and this is deliberate. The flows translation
group ships status: planned with authorWarn: true in the platform liveness
ledger, verified against the installed packages. Two consequences:

  1. i18n/missing-flow is suppressed, so lint:i18n-gate reports 0 issues
    both before and after this change — it could not have caught a miss here.
  2. Authoring flows.quote_generation.screens.screen_1.fields.discount.label
    would store a string no shipped runner reads, and would raise
    liveness-planned-property. The console bundle resolves no flow translation
    keys at all.

That is why the six existing screen dialogs in this app already render English
in every locale. This field is now consistent with them, not a new gap. When the
screen-flow runner lands upstream and the ledger row flips to live, this label
becomes translatable along with the rest of that surface.

Testing

  • pnpm verify — exit 0, the full chain green
  • pnpm test — 161 files, 3408 passed, 1 skipped
  • pnpm validate, pnpm typecheck, pnpm lint, pnpm lint:i18n-gate,
    pnpm hygiene, pnpm hygiene:tokens, pnpm build — each exit 0
  • Built artifact inspected: dist/objectstack.json ships
    "label": "Discount % (≤ 60)", "placeholder": "0-60" on the discount
    screen field
  • The literal 60 appears nowhere in quote-generation.flow.ts, so the
    rendered number can only have come from the import
  • No new test added, per the card's ruling and AGENTS.md

Checklist

  • I have added a changeset (hotcrm: patch, matching the precedent set by
    the sibling PR for items 1/3/5/6 of this card)
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • New and existing unit tests pass locally with my changes

Additional Notes

Item 4's premise was re-verified on current main before any edit: the field
was still label: 'Discount %' with no ceiling hint, and #1206's rounding fix
is present in the same file, so the serial fence really is released.


Generated by Claude Code

The Generate Quote screen asked for a Discount % and said nothing about the
60% ceiling, a hard block with no override, so the only way to learn the
number was to enter one, submit, and read the rejection.

The field's label and placeholder now interpolate QUOTE_DISCOUNT_CEILING --
the same constant the crm_quote and crm_quote_line_item validation rules
interpolate, imported rather than retyped -- so the hint cannot drift from
the rule it describes. The ceiling and its hard-block behaviour are unchanged.

No client-side max ships with it: ScreenFieldConfigSchema is strict at 17.3.0
and rejects the key by name, so it would fail validation rather than quietly
do nothing, and the executor forwards no such key into the ScreenSpec the
client renders. The comment beside the field records that measurement.

Co-authored-by: Claude
@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 12:52pm UTC

Request Review

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

Labels

backend Server-side behaviour — hooks, flows, actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants