Skip to content

Commit 56bca91

Browse files
os-steveclaude
andauthored
docs(spec): TenantPlanSchema doc block states the entitlement-layer fold, not normalization (#9345) (#9492)
TenantPlanSchema's doc block claimed unrecognized plan codes fold to free via "the cloud distribution's normalization." That was wrong on the mechanism and the citation as of the cloud#1380 ruling (2026-08-16), landed in cloud PR #1417 (merged 2026-08-17): - The fold happens at the entitlement layer (isFreePlan), not in normalization -- sys_environment.plan keeps the raw value (case- normalized only), so an unrecognized tier stays distinguishable from the free tier to any reader, log line, or operator (cloud#1389's red line: normalize the spelling, never the vocabulary). - Before the ruling, only the control-plane planKey reader folded unknown to free; the tenant-runtime isFreePlan reader granted paid access. As of cloud PR #1417 both mirrors fold. - The two mirrors' vocabularies are not merged into one list (cloud#1380 lands over a pinned copy; unifying them is cloud#1418, ruled but not landed, and a SHA-pinned image can predate a vocabulary entry even after that lands). - Carries the ruling's operational premise -- new tiers are minted rarely, images roll before a new tier goes on sale -- consistent with cloud's isFreePlan docstring. Doc-block prose only. No schema, validation, or behaviour change -- TenantPlanSchema still accepts any string; acceptance is byte-identical. Fixes #9345 Claude-Session: https://claude.ai/code/session_01Fs18A2DdXLVN2h8PaaFBcP Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2c570f3 commit 56bca91

2 files changed

Lines changed: 53 additions & 4 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
docs(spec): `TenantPlanSchema` doc block states the entitlement-layer fold, not normalization (#9345)
6+
7+
`TenantPlanSchema`'s doc block claimed that an unrecognized plan code is folded
8+
to the free tier by "the cloud distribution's normalization." That was
9+
measured wrong on two counts as of the cloud#1380 ruling (2026-08-16, landed
10+
in cloud PR #1417, merged 2026-08-17):
11+
12+
- The fold happens at the **entitlement layer** (e.g. `isFreePlan`), never in
13+
normalization — `sys_environment.plan` keeps the raw value (case-normalized
14+
only), so an unrecognized tier stays distinguishable from the free tier to
15+
any reader, log line, or operator. Writing it as normalization is exactly
16+
what cloud#1389's red line forbids: normalize the spelling, never the
17+
vocabulary.
18+
- Before the ruling landed, only the control-plane `planKey` reader folded
19+
unknown codes to free; the tenant-runtime `isFreePlan` reader granted paid
20+
access to an unrecognized code. As of cloud PR #1417 both mirrors fold.
21+
22+
The corrected doc block also states, explicitly, what it must not say: the two
23+
mirrors' vocabularies are not merged into one list (cloud#1380 lands a
24+
pinned *copy*; unifying them is cloud#1418, ruled but not yet landed, and a
25+
SHA-pinned image can predate a vocabulary entry even after that lands), and
26+
it carries the ruling's operational premise (new plan tiers are minted
27+
rarely, images roll before a new tier goes on sale) so the spec text does not
28+
contradict cloud's `isFreePlan` docstring, which states the same premise.
29+
30+
Doc-block prose only — `TenantPlanSchema` still accepts any string and
31+
enforces no vocabulary; acceptance behavior is unchanged.

packages/spec/src/cloud/tenant.zod.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,28 @@ export type TenantDatabaseStatus = z.input<typeof TenantDatabaseStatusSchema>;
4444
* `planAllowsAiStudio`) interpret specific values, and they own that
4545
* interpretation independently of this schema.
4646
*
47-
* Convention (not enforced here): an empty or unrecognized value is treated
48-
* as the free tier by cloud-side readers. Spec accepts any string, including
49-
* the empty one — the free-tier fallback is the cloud distribution's
50-
* normalization, not a spec-level default.
47+
* Convention (not enforced here): as of the cloud#1380 ruling (2026-08-16,
48+
* landed in cloud PR #1417, merged 2026-08-17), an empty or unrecognized
49+
* value folds to the free tier on **both** cloud-side mirrors (the
50+
* control-plane `planKey` reader and the tenant-runtime `isFreePlan`
51+
* reader). The fold happens at the **entitlement layer**, not in
52+
* normalization: `sys_environment.plan` keeps the raw value (case-normalized
53+
* only), so an unrecognized tier stays distinguishable from the free tier to
54+
* any reader, log line, or operator — cloud#1389's red line is normalize the
55+
* spelling, never the vocabulary. Spec accepts any string, including the
56+
* empty one — the free-tier fallback is a cloud-side entitlement decision,
57+
* not a spec-level default.
58+
*
59+
* The two mirrors' vocabularies are **not** merged into one list: cloud#1380
60+
* lands A over a copy of the vocabulary, pinned to the source by an
61+
* element-for-element equality guard. Unifying them is cloud#1418 (ruled,
62+
* not yet landed) — and even once it lands, a SHA-pinned image can still
63+
* predate a vocabulary entry, so the two lists can disagree either way.
64+
*
65+
* The fold's premise is operational, not structural: new plan tiers are
66+
* minted rarely, and images roll before a new tier goes on sale. If that
67+
* discipline changes, this premise changes with it (see the cloud
68+
* distribution's `isFreePlan` docstring, which carries the same premise).
5169
*/
5270
export const TenantPlanSchema = lazySchema(() => z.string().describe(
5371
'Opaque plan/tier identifier. The vocabulary is control-plane config owned by the '

0 commit comments

Comments
 (0)