Skip to content

chore(lint): org-identifier authoring guard for deprecated session.tenantId (#3280 follow-up) - #3289

Merged
os-zhuang merged 1 commit into
mainfrom
feat/org-identifier-gate
Jul 19, 2026
Merged

chore(lint): org-identifier authoring guard for deprecated session.tenantId (#3280 follow-up)#3289
os-zhuang merged 1 commit into
mainfrom
feat/org-identifier-gate

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Follow-up to #3280 (merged in #3284) and #3288. Makes the session.tenantId deprecation discoverable at build time for our own reference apps.

Why

#3280 made organizationId the blessed developer-facing name for the caller's active org in hook/action bodies; ctx.session.tenantId is now a deprecated alias. TSDoc @deprecated only nudges an author whose editor surfaces it — nothing stopped our own reference apps (examples/, apps/), which authors and AIs copy from, from re-introducing session.tenantId.

What

scripts/check-org-identifier.mjs — a hard-fail guard (authoring surfaces carry zero occurrences today, so any match is new), wired into the lint workflow next to check:nul-bytes / check:role-word. Deliberately narrow:

Proven red (防假绿)

  • Injected ctx.session.tenantId into a tracked example hook → guard fails (exit 1, points to organizationId).
  • Reverted → green (194 files scanned, 0 occurrences).
  • Same line with os-allow-tenant-idsuppressed.
  • New script carries no raw NUL byte (passes check:nul-bytes); ESLint clean.

Tooling-only (no package touched) → no changeset needed.

🤖 Generated with Claude Code

…n.tenantId (#3280 follow-up)
`organizationId` is the blessed developer-facing name for the caller's active
org in hook/action bodies (#3280); `ctx.session.tenantId` is a deprecated alias.
TSDoc `@deprecated` only nudges an author whose editor surfaces it — nothing
stopped our own reference apps (examples/, apps/), which authors and AIs copy
from, re-introducing `session.tenantId`.
scripts/check-org-identifier.mjs is a hard-fail guard (authoring surfaces carry
zero occurrences today) wired into the lint workflow. Deliberately narrow:
- scans author-facing reference code only (examples/, apps/) — internal packages
legitimately read `session.tenantId` (driver-layer alias, a #3280 non-goal);
- excludes skills/ + content/docs/, which teach the deprecated form on purpose;
- matches only the `session.tenantId` token, never `execCtx.tenantId` /
`opts.tenantId` / `DriverOptions.tenantId` (the generic tenancy knob);
- escape hatch: `os-allow-tenant-id` comment on the line.
Proven red on a new occurrence, green when reverted, suppressed by the marker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercelBot commented Jul 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 19, 2026 2:32pm

Request Review

@github-actionsgithub-actionsBot added ci/cd dependencies Pull requests that update a dependency file size/m labels Jul 19, 2026
@os-zhuang
os-zhuang merged commit 64e0bbd into mainJul 19, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the feat/org-identifier-gate branch July 19, 2026 14:34
lemonhub-io pushed a commit to OpenFork-org/objectstack that referenced this pull request Aug 8, 2026
…退 1 留 (objectstack-ai#5055) (objectstack-ai#6385)
* refactor(spec)!: retire the widget-registration + doorless i18n vocabularies, keep FieldWidgetProps (objectstack-ai#5055)
ADR-0049 enforce-or-remove for the 14 sites objectstack-ai#4001 批 16 measured as `no door`.
Disposed per site against a re-measurement on origin/main: 13 REMOVED, 1 KEPT.
Removed — 10 defs, 26 exported names:
ui/widget.zod.ts WidgetManifest, WidgetLifecycle, WidgetEvent,
WidgetProperty, WidgetSource (npm/remote/inline union)
ui/i18n.zod.ts I18nObject, PluralRule, NumberFormat, DateFormat,
LocaleConfig
None had a carrier key: nothing under packages/spec/src imported widget.zod at
all, every live import of i18n.zod names I18nLabelSchema or AriaPropsSchema, the
BFS from all 24 metadata-type roots plus defineStack reached none of them (with
PageSchema / ObjectListViewSchema resolving `direct` in the same run and a
synthetic carrier flipping all of them), and no repo ever parsed one. So a
published vocabulary described a widget-registration and locale-formatting
capability the platform does not have — the objectstack-ai#3950 shape.
Kept — FieldWidgetProps. Its evidence differs and had been overtaken one day
before 批 16 measured. It is a React props contract, never authorable (absent
from authorable-surface/ and json-schema.manifest/ — onChange is a z.function()),
so having no parse is its design; and objectui PR objectstack-ai#3289 (2026-08-03) renamed
@object-ui/fields' validation slot onto its `error` with no alias and pinned it
as a deliberate compile-time tripwire. Re-verified on objectui origin/main.
Route 3 ("nothing parses it → neither"), as objectstack-ai#4988 / objectstack-ai#4834: no retiredKey()
tombstone and no D2 conversion, because there is no shape to tombstone and no
source to rewrite. The declared record is the D3 SemanticMigration
ui-widget-i18n-family-retired plus 10 RETIRED_DEFS_BY_MAJOR entries, which the
objectstack-ai#4725 manifest-deletion gate reads. WidgetManifest.performance's own tombstone
(objectstack-ai#3896) is subsumed by the removal of the shape that carried it.
Baselines moved deliberately: json-schema.manifest/ui.json -10 (the objectstack-ai#2978
ratchet fires first), authorable-surface/ui.json -65 (adjudicated by the objectstack-ai#4650
gate's path 3), api-surface/ui.json -26. variant-docs.json's
`type:inline|npm|remote` entry goes with the union it described (objectstack-ai#5552's failure
mode). Reference docs, meta.json, skill indexes and the strictness-ledger counts
regenerated; the `no door` bucket goes 14 -> 1.
Pins are bidirectional: ui/widget-i18n-retirement.test.ts asserts absence across
every public entry by resolved symbol identity AND the survival of the three
shapes a too-wide sweep would take — FieldWidgetProps, AriaProps and I18nLabel,
all three of which live in the two files being emptied. The objectstack-ai#5056 clone-overlap
fixture is rebuilt locally so the instrument's measured 2-of-19 bound survives
its subject.
No runtime behaviour changes; that impossibility is the reason for the removal.
Refs objectstack-ai#5055, objectstack-ai#4001, objectstack-ai#4988, ADR-0049, ADR-0087
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUAV11R31jhzq6v1wb6SuJ
* chore(changeset): declare the ADR-0087 disposition on the objectstack-ai#5055 retirement (objectstack-ai#6148)
The new objectstack-ai#6148 gate requires every changeset that declares a breaking change to
answer the ledger question in writing. This one's answer is the first of the
four accepted forms — the entry exists: the retirement is registered as the D3
SemanticMigration `ui-widget-i18n-family-retired` in
packages/spec/src/migrations/registry.ts, alongside its ten
RETIRED_DEFS_BY_MAJOR entries.
Comment-only; no schema, artifact or test is affected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUAV11R31jhzq6v1wb6SuJ
---------
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cddependenciesPull requests that update a dependency filesize/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang