Skip to content

[finding] The SCIM/identity ADR-0071 citation resolves to the dataset semantic-layer record — 39 files point at a decision about multi-hop joins #14361

Description

@claude

Filed by the #14150 measurement seat (read-only card, session session_01AUF1NoViznQK32gqpK8wS8, scratchpad key issue-14150-knife1). Out of scope for that card — recording only, unassigned, for the finding box to grade. Measured on origin/main at e854a531a.

The reading

Two unrelated meanings share the number ADR-0071 in this repo, and only one of them has a record.

The record that exists is docs/adr/0071-dataset-semantic-layer-depth.md"ADR-0071: Dataset semantic-layer depth — multi-hop joins", 128 lines about dataset joins and matrix pivoting. Grepping it for scim, admin, ban, deprovision, better-auth or organization plugin returns one hit, and it is the word "admin" inside the path metadata-admin/inspectors/ReportDefaultInspector.tsx.

The meaning most citations carry is the SCIM / identity coupling: "SCIM's deprovisioning path runs through the better-auth admin plugin; org-scoped tokens need the organization plugin — see ADR-0071." There is no such record anywhere under docs/adr/.

Counts, git grep -l "ADR-0071" with pnpm-lock.yaml excluded — 43 files:

  • 3 carry the dataset meaning and match the record correctly: content/docs/data-modeling/analytics.mdx, packages/lint/src/validate-dataset-references.ts, packages/lint/src/validate-dataset-references.test.ts.
  • 1 is the record itself.
  • 39 carry the SCIM / identity meaning against a record about dataset joins — packages/plugins/plugin-auth/src/{auth-manager.ts,auth-plugin.ts,auth-schema-config.ts}, nine packages/platform-objects/src/identity/sys-scim-*.object.ts plus sys-user.object.ts, docs/qa/platform-checklist/areas/identity-auth.json, two changesets, six CHANGELOGs, and the generated content/docs/references/system/auth-config.mdx (lines 105 and 215), which puts the wrong pointer in front of app authors.

The number is also load-bearing in prose a deployment reads at runtime: the #13816 construction-time refusal message in auth-manager.ts:353-367 names ADR-0071 to an operator as the reason their configuration is refused.

Why no gate catches it

scripts/check-adr-anchors.mjs checks, per its own header, that "every ADR-NNNN in a tracked file must name a record under docs/adr/" — added by #6634 after ADR-0079 was found cited by 77 files with no record at all. ADR-0071 resolves: the dataset record is right there. The gate has no way to ask whether the record it resolves to is about what the citation says, so all 39 sites are green.

This is the same silent-squatting failure that gate's header describes, one step further along: the number is not free-standing, it is already taken by a different decision, so a reader following the citation lands on a real page about the wrong subject.

Also relevant: KNOWN_NUMBER_COLLISIONS in that script freezes three genuine two-record collisions (0010, 0019, 0057) as a shrink-only allowlist. This case is not one of those — there is only one record — so it is invisible to that mechanism too.

ADR-0069 (Enterprise authentication hardening) is the nearest record and it explicitly disclaims the subject: line 18, "SCIM/bulk-provisioning is a separate ADR (directory sync != auth hardening)", and line 183, "SCIM / directory provisioning and bulk import — separate ADR (provisioning, not authentication); tracked in #2246." So the SCIM record was intended to exist and, in this repo, does not.

Why it matters now, beyond tidiness

#14150's ruled fork (#13816's 2026-09-01 director-batch-#21 ruling) says a FEASIBLE reading produces "an ADR-0071 revision card". Cut literally, that card would revise the dataset semantic-layer record. Whoever cuts it needs to know the target does not exist yet.

Candidate dispositions, none costed here

  1. Write the missing record (the SCIM / identity-lifecycle decision the 39 sites describe) under a free number and re-point them.
  2. If the decision lives in objectstack-ai/cloud, adopt the structural spelling the anchors gate already supports for sibling repos (a repo qualifier immediately before the id) so a bare ADR-0071 stops meaning two things.
  3. Leave the citations and accept that they point at an unrelated record — recorded here only so the choice is deliberate.

Unassigned and ungraded; triage decides. ⛔ Not fixed here: #14150 is read-only, and a 39-file re-pointing is a scoped edit with an owner, not a rider.

Boundary. Counted with git grep on e854a531a with pnpm-lock.yaml excluded; the split between the two meanings was read per file, not inferred from the path. Not measured: whether objectstack-ai/cloud holds an ADR-0071 of its own (that repository is outside this session's GitHub scope).

Refs: #14150 · #13816 · #6634 (the anchors gate) · ADR-0069 · #2246.

<!-- os-decision-facets -->
① 项目长远合理性(权重 ≥50%):一个编号同时指两件事,是最难自愈的一类文档腐烂 —— 读者顺着引用走到一页真实存在但讲错主题的记录,比走到 404 更糟:404 会让人去问,一页看起来像样的记录会让人直接相信。A 把「一个编号一个决定」这条规矩恢复原样(缩小特例);C 把「编号可以指两件事」固化成本仓惯例(扩大特例),而闸门的 KNOWN_NUMBER_COLLISIONS 白名单本来是只减不增的。
② 实际业务拉动:今天已有三处真实消费者撞上,不是假想 —— 生成的 auth-config.mdx 把错指针摆在应用作者面前;#13816 的构造期拒绝消息把这个编号念给正被拒绝的运营商听;#14150 的已裁分叉会开出一张「ADR-0071 修订卡」,照字面切就去改了数据集那一页。
③ 防 AI 犯错:闸门 check-adr-anchors.mjs 对这 39 处全绿——它只问「这个编号有没有记录」,不问「记录讲的是不是这件事」。一道不可能失败的闸门比没有闸门更危险,因为它被计入。B 的仓库限定拼写是三个选项里唯一让机器重新分辨得出来的形状;A 靠人再写一次,下一次仍靠人。
④ 创业阶段不扩散:A 新增一条需永久维护的记录;B 只动既有机制的既有拼写,零新增声明义务;C 零成本,但把这笔债永久化,并且每个后来的读者都要重付一次「读完才发现指错」的成本。

推荐:先量一格再裁——请先回一句「objectstack-ai/cloud 里有没有一条 ADR-0071?」。有 ⇒ B(仓库限定拼写,机械可派发,①③④ 同向);没有 ⇒ A(补写缺失记录)。⛔ 席位不代裁:A 属 ADR 类,人工地板恒交维护者;⛔ 并且无论哪一支,六个 CHANGELOG 与两个 changeset 都原样不动——它们是历史存档,改它们等于改历史。

置信缺口(本分析看不见什么):看不见 objectstack-ai/cloud(本会话 GitHub 授权面不含该仓),而三个选项里哪个成立恰恰取决于这个本席读不到的事实;也没有量出 39 处里除 CHANGELOG/changeset 之外还有多少属于不该改的存档面。

Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions