Skip to content

HF-307: warn once when a typed key enters its notice window (5/8) - #1736

Open
marcin-kordas-hoc wants to merge 2 commits into
hf-307-entitlement-gating-pr4from
spike/hf307-notice-window
Open

HF-307: warn once when a typed key enters its notice window (5/8)#1736
marcin-kordas-hoc wants to merge 2 commits into
hf-307-entitlement-gating-pr4from
spike/hf307-notice-window

Conversation

@marcin-kordas-hoc

@marcin-kordas-hoc marcin-kordas-hoc commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Consumes the license key's notice field: a VALID typed key whose usage_until lies within notice days of the current UTC instant prints a single console warning naming the expiry date (with a (UTC) marker). Stacks on #1731; rebased onto its current head on 19.08 (the base moved during PR3/PR4's review passes, which had left this PR conflicting).

Why now

Per Kuba's D5-A (ClickUp, 12.08): hard blocking at/after expiry stays in 3.5.0 and the full rev 5 §4.1 window model is a follow-up — but trials made the notice warning concrete for this release: a trial is technically just a key with grace=0 and notice>0 whose warnings must surface in the console (packages meeting 12.08), and the trial mechanism lands in August.

What changed

  • licenseResolution.ts: expiryWithinNoticeWindow() — usage-axis only (rev 5: notice/grace have no effect on the release_until axis), window ends exactly where the soft-stop phase would begin, blind to graceDays by design.
  • licenseKeyValidator.ts: notifyLicenseKeyNotice() with per-key warn-once accounting (_noticedKeys keyed by the raw key string) — deliberately not the process-lifetime boolean the state messages use: two engines built with two different keys each get their own warning.
  • Blocking behaviour at/after expiry is byte-identical to before; the key's silent flags suppress the warning; CHANGELOG entry included.

Verification

Paired tests: hyperformula-tests@spike/hf307-notice-window (authored RED-first, 8 assertions: inside/outside window, release_until never warns, expired still hard-blocks, silent suppresses, per-key warn-once across two engines). Full license suite 212/212 under Jest (12 suites, unit/license + unit/helpers/licenseKeyValidator), re-measured after the 19.08 rebase onto the current #1731 (e9863f27) — the earlier 165/165 predated PR3's and PR4's review fixes, tsc --noEmit clean, eslint --quiet clean on changed files.

🤖 Generated with Claude Code


Note

Low Risk
Console-only notice on the typed-key path; expiry blocking and entitlement logic are unchanged aside from the new warning hook.

Overview
Adds a one-time console warning when a still-valid typed license key’s usage-based expiry (usage_until) falls inside its configured notice period. The message names the expiry date with a (UTC) marker.

expiryWithinNoticeWindow in licenseResolution.ts applies only to the usage axis (not release_until), ends the window at the usage-until day boundary (ignores grace), and is wired from resolveLicense when the key is valid and not silent.

notifyLicenseKeyNotice in licenseKeyValidator.ts tracks warn-once per raw key string (_noticedKeys), separate from the existing once-per-page invalid/expired messaging. Test reset clears both flags.

Blocking at/after expiry is unchanged; silent flags suppress the new warning. CHANGELOG updated.

Reviewed by Cursor Bugbot for commit 7b5398d. Bugbot is set up for automated code reviews on this repo. Configure here.

@qunabu

qunabu commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 18, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
hyperformula-docs aa835bf Commit Preview URL

Branch Preview URL
Aug 20 2026, 12:57 PM

@marcin-kordas-hoc
marcin-kordas-hoc force-pushed the spike/hf307-notice-window branch from c1cce95 to cbe23f0 Compare August 18, 2026 06:17
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown

Performance comparison of head (aa835bf) vs base (e9863f2)

                                     testName |    base |    head | change
--------------------------------------------------------------------------
                                      Sheet A |   481.5 |  485.42 | +0.81%
                                      Sheet B |  150.34 |  150.55 | +0.14%
                                      Sheet T |  135.42 |  137.48 | +1.52%
                                Column ranges |  462.69 |  461.58 | -0.24%
                                Sorted lookup | 13836.8 | 14592.7 | +5.46%
Sheet A:  change value, add/remove row/column |   14.47 |   14.15 | -2.21%
 Sheet B: change value, add/remove row/column |  126.34 |  125.34 | -0.79%
                   Column ranges - add column |   144.9 |  142.11 | -1.93%
                Column ranges - without batch |  446.06 |  448.38 | +0.52%
                        Column ranges - batch |  113.82 |  112.79 | -0.90%

@marcin-kordas-hoc
marcin-kordas-hoc marked this pull request as ready for review August 18, 2026 07:32
@marcin-kordas-hoc
marcin-kordas-hoc force-pushed the hf-307-entitlement-gating-pr4 branch from 5d67b5d to 46ac32d Compare August 18, 2026 08:57
The key's `notice` field was parsed into LicenseExpiry and read by nothing.
Now a VALID typed key whose usage_until lies within `notice` days of the
current UTC instant prints a single console warning naming the expiry date
(UTC marker included). The warn-once identity is the key string, not the
process — two engines built with two different keys each get their own
warning. release_until-axis keys never warn (rev 5: notice/grace have no
effect there), the key's silent flags suppress it, and blocking at/after
expiry is byte-identical to before (Kuba's D5-A: hard stop stays in 3.5.0,
the full rev 5 §4.1 window model is a follow-up).

Trials made this concrete: a trial is just a key with grace=0 and notice>0
whose warnings must surface in the console (packages meeting 12.08).

Implemented by a prep-ship lane (task HF-307-notice-window); verified here:
license suite 165/165 under Jest, tsc --noEmit clean, eslint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdHPZAjciZFWqGa19Yf7it
@marcin-kordas-hoc
marcin-kordas-hoc force-pushed the spike/hf307-notice-window branch from cbe23f0 to 7b5398d Compare August 19, 2026 09:55
@marcin-kordas-hoc

Copy link
Copy Markdown
Collaborator Author

Paired tests PR: handsontable/hyperformula-tests#37 — merge it BEFORE this one (fetch-tests pairs by branch name).

@marcin-kordas-hoc marcin-kordas-hoc changed the title HF-307: warn once when a typed key enters its notice window (5/6) HF-307: warn once when a typed key enters its notice window (5/8) Aug 20, 2026
Four findings from the spec-to-ship re-review (each cross-confirmed by at
least two independent review angles):

1. Message wording: the notice now uses rev 5 section 3.2's own subscription
   clause - "is valid until <last covered day> (UTC)" - instead of "will
   expire on". The pre-existing expired message names the first day NOT
   covered (+1 day, frozen convention), so "expires on Aug 25" followed by
   "expired on Aug 26" printed two different days for one boundary.

2. The notice read is gated on the key SHAPE (rev 5), not on the field's
   presence: on the shipped shape the terms come off the LICENSED product's
   entry - for a dual-product key, Handsontable's - so a stray `notice`
   field there must not switch HyperFormula's console output on. The
   expiryWithinNoticeWindow doc also no longer claims kind='usage' implies
   the date came from usage_until (the envelope-exp fallback is real and
   documented as accepted standalone; the entitlement re-port removes it).

3. rebuildWithConfig's transient serialization-only Config no longer prints
   license messages: replacing keyA with keyB used to print keyA's notice in
   the very call that discards keyA. Config gains an internal-defaulted
   notifyLicenseMessages parameter, same pattern as showDeprecatedWarns.

4. The warn-once identity is now trim + the trailing 128 chars (the key's
   own checksum): extractTypedKeyData trims, so 'KEY' and 'KEY\n' are one
   license and must be one identity; truncation bounds a long-lived
   process's memory to 128 chars per distinct warned key. CHANGELOG entry
   gains its PR link.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdHPZAjciZFWqGa19Yf7it
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.38%. Comparing base (e9863f2) to head (aa835bf).

Additional details and impacted files

Impacted file tree graph

@@                      Coverage Diff                       @@
##           hf-307-entitlement-gating-pr4    #1736   +/-   ##
==============================================================
  Coverage                          97.38%   97.38%           
==============================================================
  Files                                204      204           
  Lines                              16214    16236   +22     
  Branches                            3487     3493    +6     
==============================================================
+ Hits                               15790    15812   +22     
  Misses                               424      424           
Files with missing lines Coverage Δ
src/Config.ts 94.69% <100.00%> (ø)
src/HyperFormula.ts 99.76% <100.00%> (ø)
src/helpers/licenseKeyValidator.ts 95.74% <100.00%> (+1.15%) ⬆️
src/license/licenseResolution.ts 97.43% <100.00%> (+0.29%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants