Skip to content

docs(adr): ADR-0135's two prose citations of the code name what the code now says - #18344

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-14361-adr-0024-citations
Sep 16, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-14361-adr-0024-citations

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Fixes #14361

Third and final segment. Segments 1 and 2 (PR #18228, last commit 0f95f4341) handled the 152 citations under packages/** and content/docs. This segment is the remainder: every unqualified ADR-0024 under docs/adr/.

Clause-②: no

The instrument is wrong in both directions

The dispatch handed me a population of 21 bare lines in 7 files, measured as "lines matching ADR-0024, minus lines containing cloud ADR-0024". I reproduced that 21 exactly. Then I re-measured per occurrence instead of per line:

instrument count
ADR-0024 occurrences under docs/adr/ 35
lines matching, minus lines containing cloud ADR-0024 21
occurrences whose preceding token is not cloud (backticks allowed) 18
  • 4 false positives. ADR-0135 lines 3, 31, 232, 271 spell the qualifier with backticks in the middle — `objectstack-ai/cloud` ADR-0024 and `cloud` ADR-0024. The literal-string filter does not see the qualifier. They are qualified and correct.
  • 1 false negative. ADR-0135 line 248 begins `ADR-0024 V1` and also contains `cloud ADR-0024` later in the same line, so grep -v discarded the whole line — hiding a bare citation. It is one of the two defects below.

21 − 4 + 1 = 18. A third artifact is invisible to any line filter: ADR-0135 line 79 begins ADR-0024 chose the other direction, and its qualifier cloud is the last word of line 78. Line-wrapped, therefore qualified.

Controls for every zero reported here are in the dev report.

Verdicts — 18 occurrences, each checked against the other end

The D-letter test that segments 1 and 2 used has zero resolving power here (0 of 18 carry a D clause letter), so every row is a read of the cited record.

Local docs/adr/0024-mcp-connectors.md — 10 sites, all correct

site claim made other end verdict
0023-openapi-to-connector-generator.md:148 "the complementary path — wrapping live MCP servers as connectors" explicit link ./0024-mcp-connectors.md; title is MCP Servers as Connectors correct
0024-mcp-connectors.md:1 the record's own H1 self correct
0025-plugin-package-distribution.md:7 Related list, labelled "(connectors)" explicit link correct
0025-plugin-package-distribution.md:395 "ADR-0024 (MCP connectors), any integration describable by OpenAPI/MCP is a declarative connector config" ADR-0024 TL;DR: one adapter, "no per-server code" correct
0025-plugin-package-distribution.md:529 Related list explicit link correct
0036-app-as-rest-api-and-mcp-server.md:5 "MCP as connectors — the inbound sibling: ObjectStack consuming external MCP servers" ADR-0024 section 1 ships @objectstack/connector-mcp, an adapter that connects to MCP servers — inbound correct
0097-declarative-connector-instances.md:5 Builds-on, "(MCP servers as connectors)" explicit link correct
0097-declarative-connector-instances.md:199 "sandboxed execution remains the enterprise tier (ADR-0024 §4)" ADR-0024 ### 4. tier table, enterprise row, reads "sandboxed stdio execution" correct — exact
0097-declarative-connector-instances.md:205 "MCP credentials ride the transport (ADR-0024)" ADR-0024 ### 3. "Credentials and config live with the MCP server… transport env/headers carry credentials" correct — exact
0101-mcp-stdio-principal-admission.md:5 "ADR-0024 §4 (trust model)" ### 4. is the open/enterprise boundary carrying the trust assumption correct

The two section citations are also structurally disambiguating: the local record numbers its sections ### 1. … ### 5., while cloud ADR-0024 letters its clauses D1…D10/V1. A §4 cannot be a cloud clause.

docs/adr/0135-identity-and-access-architecture.md — 8 sites, 6 correct, 2 fixed

line text kind other end verdict
54 "A bare ADR-0024 in this repository's code does NOT resolve to this record" mention 0024-mcp-connectors.md exists and is unrelated; 0071 here is Dataset semantic-layer depth as the same sentence claims correct — adding cloud inverts it
63 git grep -n -E "ADR-0024" -- packages/… literal re-ran the command verbatim: 14 lines, 0 unqualified. The sentence is explicitly scoped "on the commit that introduced it… measured 64", so it is historical and still true correct — editing it breaks the command
79 ADR-0024 chose the other direction use cloud is the last word of line 78 correct — line-wrap artifact
196 "the clause this repository's code cites as ADR-0024 ②" mention the live source cites ADR-0135 D6 — auth-manager.ts 2793/3667/6654, auth-plugin.ts 2796, register-sso-provider.ts 316, auth-route-ledger.ts 238–239. ADR-0024 ② survives only in CHANGELOGs fixed
246 "a bare ADR-0024 citation in this tree is not mechanically re-pointable" mention — correct
248 "auth-manager.ts cites ADR-0024 V1" mention auth-manager.ts:3661 reads cloud ADR-0024 V1 fixed
260 "Whether any individual bare ADR-0024 citation should move" mention — correct
265 "A reader who follows an ADR-0024 citation out of plugin-auth" mention — correct

The two fixes

Both are present-tense descriptions of what this repository's code says. Both were true when the record was written and were made false by segments 1 and 2 of this same card.

Line 196. Under either reading the line was wrong. Read as a quotation of the code, it quotes a string the live source no longer contains. Read as naming the cloud clause, it is a bare cloud citation, which Prime Directive #13 forbids and which resolves against this registry to 0024-mcp-connectors.md — a record numbered 1–5 with no clause ②. The fix names the cloud clause and the spelling the code now uses, so both readings land.

Line 248. A one-token insert. The same sentence already prescribes "those keep the cloud ADR-0024 spelling"; auth-manager.ts now does, and the quotation did not.

Everything else is untouched. No citation that was already correct was moved.

Left alone, deliberately

ADR-0135's Consequences bullet (line 265 ff.) reads "Until then the citation still resolves to docs/adr/0024-mcp-connectors.md". Its antecedent has now passed: the verbatim grep on line 63 returns 0 unqualified citations in plugin-auth/src and platform-objects/src/identity. The citation on that line is a correct mention, so it is not a defect of the kind this card is about; the surrounding tense is merely spent, and rewriting a mirror record's Consequences prose is a maintainer's call, not a per-site citation call. Flagged rather than edited — say the word and it moves in this PR.

维护者速读(草稿)

改了什么 —— docs/adr/0135-identity-and-access-architecture.md 两处散文里对「本仓代码怎么引用」的描述,改成代码现在真正写的样子。共 7 增 6 删,只动这一个文件。

为什么改 —— 这两句话在写下时是真的,是 #14361 前两段自己把它们变假的。196 行说域名验证子句「本仓代码引作 ADR-0024 ②」,而活代码七处已经引 ADR-0135 D6,ADR-0024 ② 只剩在 CHANGELOG 里;它同时还是一个裸的 cloud 引用,按 Prime Directive #13 会解析到本仓的 0024-mcp-connectors.md,而那份记录分节是 1–5,根本没有子句 ②。248 行把 auth-manager.ts 引述成 ADR-0024 V1,文件里写的是 cloud ADR-0024 V1 —— 恰是同一句话下半段要求保留的拼写。

风险与代价(含回滚) —— 纯散文,零代码、零发布物。docs/adr/** 不在任何包的 files[] 里(70 个声明了 files[] 的包全部为 0 命中),所以无 changeset。回滚 = revert 这一个 commit,没有任何下游。唯一的判断风险是 196 行的改写:它比 248 行多改了几个字,如果您认为镜像记录应当只记 cloud 的字母而不提本仓代码今天的拼写,把它退回成 `cloud ADR-0024` 的子句 ② 即可,一行的事。

席位意见 ——

你要做的 —— 这是治理面,需要您手工批准并合并;席位不入队、不武装 auto-merge。请特别看一眼「Left alone, deliberately」那一节:ADR-0135 Consequences 里的 "Until then" 已经过期,我没有动它,因为改镜像记录的 Consequences 散文不该由 dev 自己决定。您说改我就在本 PR 里改。

Acceptance notes

  • docs/adr/** is a governed surface. Draft, maintainer-merged. Not queued, auto-merge not armed.
  • Changeset: skipped, measured. 70 workspace packages declare files[]; 0 of them ship any docs/adr path, and docs/ contains no package.json, so docs/adr/** is not inside a workspace package at all. Fire control on the same scan: all 70 ship a dist entry. Nothing published moves.
  • Population after this PR: 35 occurrences, 19 qualified, 16 unqualified — all 16 verdicted correct above.
  • noted, not filed: the "Until then" tense in ADR-0135's Consequences, above. Carrier named: this PR's reviewer.
  • noted, not filed: the line-based grep -v 'cloud ADR-0024' recipe is quoted inside ADR-0135 line 63 itself and mis-bins 5 of 21 sites. It is correct as written there (that sentence counts citing lines at a past commit), so there is nothing to fix; but anyone reusing that recipe as a population filter will inherit the same 4 false positives and 1 false negative. Carrier: none — no open PR or queued card reuses it.

Verification

All 19 gate families derived by scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (which takes the change set from the merge base itself) are green at c4d13026b. check:doc-formula-expressions first exited 3 — PREREQUISITE NOT MET, which is not a finding; after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint it exits 0.

pnpm lint is not owed and is not narrowed — it is not measured because the population is empty. eslint's own verdict on the only file in this diff is File ignored because no matching configuration was supplied, eslint.config.mjs contains no markdown entry, and line 328 of that config records that no parserOptions.project and no typed rules are enabled, so this diff cannot move any untouched file's verdict.


🤖 Generated with Claude Code

https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk


Generated by Claude Code

…ode now says

The mirror record describes, in the present tense, how this repository's code
cites two cloud clauses. Both descriptions were true when the record was written
and are false against the tree today:

- D6 said the domain-verification clause is "the clause this repository's code
  cites as `ADR-0024 ②`". The live source cites `ADR-0135 D6` (auth-manager.ts
  2793/3667/6654, auth-plugin.ts 2796, register-sso-provider.ts 316,
  auth-route-ledger.ts 238-239); `ADR-0024 ②` now survives only in CHANGELOGs.
  The bare form was also a bare cloud citation, which Prime Directive #13 forbids
  and which resolves against this registry to `0024-mcp-connectors.md` — a record
  whose sections are numbered 1-5 and that has no clause ②.

- The #14361 consequence note quoted auth-manager.ts as citing `ADR-0024 V1`.
  That file reads `cloud ADR-0024 V1`, which is the spelling the same sentence
  goes on to prescribe.

Every other unqualified `ADR-0024` under docs/adr is correct and is left alone:
ten are the local MCP-connector record (verified against its own sections 3 and
4), and the rest are mentions of the bare string as a string, a line-wrapped
`cloud ADR-0024`, and a literal grep pattern.

Co-authored-by: Claude <noreply@anthropic.com>
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 16, 2026
@os-zhuang
os-zhuang removed this pull request from the merge queue due to a manual request Sep 16, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 16, 2026
Merged via the queue into main with commit 335e6ad Sep 16, 2026
37 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-14361-adr-0024-citations branch September 16, 2026 06:27
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
… gates read it (objectstack-ai#18346)

Fixes objectstack-ai#16421

Clause-②: no

A gate strengthens; no published runtime contract moves. Stated by the
ruling, and re-derived here: the declaration's accept set only grows
(the arm is optional and every existing spelling reads
byte-identically), and the three gates that read it become stricter,
never looser.

## The defect

A **narrowing** — "these spellings stop being accepted" — could ship to
customers with the release notes saying nothing, and every gate green.
`check-adr-0087-registration.mjs` decided breaking-ness from an author's
hand-written `**BREAKING**` prose banner; an author who did not type it
was classified non-breaking and was asked for no ADR-0087 disposition.

Measured, not hypothesised: **objectstack-ai#16296** narrowed `sys_job.timezone` /
`sys_report_schedule.timezone` to the IANA value domain and shipped with
no banner, no `major` and no `!`. **objectstack-ai#14238** did the same one surface
earlier.

## The ruling being executed

Director summon objectstack-ai#17, decision batch objectstack-ai#2 item 1, **option B**, maintainer
verbatim 「同意」 (comment `5572145955`, 2026-09-07T14:32:32Z). Options A
(keep the prose banner) and C (a static accept-set differ) are refused
there and are not reopened here.

## What landed

| # | deliverable | where |
| --- | --- | --- |
| 1 | the closed two-arm enumeration in the declaration format |
`AGENTS.md` item 3 |
| 2 | `readClause2Line` reads the arm — **once**, no second parser |
`scripts/pm/check-clause2-carriers.mjs` |
| 3 | signal (4): a declared `narrowing` is breaking |
`scripts/check-adr-0087-registration.mjs` |
| 4 | the level axis reads the arm |
`scripts/check-changeset-no-major.mjs` |
| 5 | **ONE** ADR-0087 ledger row, recording objectstack-ai#16296 |
`packages/spec/src/migrations/entries/semantic/` |

> ⚠️ **Row 5 is deliberately one row, not the two the ruling names —
corrected by the `domain:devx` seat (objectstack-ai#6023) on the dev's measurement.**
> The ruling lists objectstack-ai#14238 and objectstack-ai#16296 as the two already-shipped
narrowings. **objectstack-ai#14238 is not a narrowing**: its diff is 535 insertions
and 0 deletions across 11 files (two nullable columns ADDED, carrying
`valueDomain: 'iana_time_zone'` from their first release), and its own
shipped changeset says so in writing — *"A NON-BREAKING ADDITION,
registered here in writing because ADR-0087's registries have no
additive entry kind"*.
> A row claiming it narrowed something would be false data in the one
ledger this mechanism keeps true, which ADR-0087's objectstack-ai#13080 addendum
refuses by name. ⇒ One row is written, the second is **not fabricated**,
and the falsified premise is carried to the maintainer rather than
silently dropped.

> ⚠️ **The citation above was wrong in the dispatch order and is
corrected here.** The seat's dispatch word cited comment `5573372199`,
which answers **HTTP 404**; the real ruling is `5572145955` (HTTP 200,
verified by both the dev and the seat). The quoted ruling text itself is
unchanged — only the provenance id moved.
| 6 | pins for both arms, in both directions | the three gates'
self-tests |

### The shape

| spelling | reading |
| --- | --- |
| `Clause-②: yes` | a widening, declared through the value — unchanged |
| `Clause-②: yes (widening)` | the same, said out loud |
| `Clause-②: yes (narrowing)` | widens one surface, narrows another;
both facts are read |
| `Clause-②: no (narrowing)` | NOT a widening, but BREAKING — the point
of the arm |
| `Clause-②: no (widening)` | MALFORMED: the value and the arm
contradict each other |

(The rows are table cells on purpose: a line-initial second declaration
in this body would be a second answer to the same question.)

The arm is **optional**, and that is a measurement rather than a
kindness: all five declarations on the open board the day this landed
carry no parenthetical arm, and all five read byte-identically
afterwards (proof below).

Two shapes fail **closed** rather than reading as an absent arm, because
reading them as absent is the direction a declared narrowing silently
disappears in: a near-arm spelling (`(narrowed)`, `(Narrowing)`,
`(widen)`) and the unfilled template `(widening|narrowing)`. Both land
in `malformed`, the state this reader already owns for "the slot holds
something nobody can grade".

## Measurements

### Back-compat — the five in-flight declarations

Read from the live GitHub payload, before and after the change,
comparing the whole reading object:

| PR | reading | arm |
| --- | --- | --- |
| objectstack-ai#18344 | `declared no` — IDENTICAL | none |
| objectstack-ai#18268 | `declared no` (em-dash reasoning, parenthesised identifiers)
— IDENTICAL | none |
| objectstack-ai#18231 | `near-miss inline-key` — IDENTICAL | n/a |
| objectstack-ai#18227 | `declared no` — IDENTICAL | none |
| objectstack-ai#18096 | `declared no` — IDENTICAL | none |

**5/5 byte-identical** apart from the additive `arm: null` field.
Nothing in flight loses its reading.

### `AGENTS.md` — both ratchet axes

Its line ratchet has **zero headroom** (1075 lines, ceiling 1075), so
the format is carried at **net zero lines**, paid for by deleting
content rather than by re-wrapping:

- deleted: the widening-rationale clause (`the widening it declares is
what makes it more than a patch…`), 93 bytes;
- deleted: the CI step name the gate already prints in its own failure,
78 bytes.

| axis | before | after |
| --- | --- | --- |
| lines | 1075 / ceiling 1075 | **1075** — headroom 0, unchanged |
| widest line | ≤ 120 bytes | edited lines measure 119 / 118 / 120 / 119
/ 81 bytes |
| widest table row | 768 / pin 768 | **768**, untouched |

`check:pm-skill-ratchet` self-test and run both exit 0.

### Both arms, both directions

Every arm pin is a **pair**, because one direction alone cannot tell a
reading from a constant — a gate that classified both arms as breaking
would satisfy a `narrowing` test while telling a consumer nothing:

- `check-adr-0087-registration`: `narrowing` is in
`MUST_MATCH_BREAKING`, `widening` is in `MUST_NOT_MATCH_BREAKING`, both
on a banner-free `minor` changeset — the exact shape objectstack-ai#16296 shipped in.
- `check-changeset-no-major`: same tree, same levels, only the
declaration moves — `no (narrowing)` reaches `enforce`, bare `no`
reaches `not-declared`.
- `check-clause2-carriers`: both arms read; the contradiction, the
near-arm family and the unfilled menu are all `malformed`; and three
CONTROL rows pin the arm-less spellings unmoved.

## Two judgement calls, declared rather than made quietly

1. **The `**BREAKING**` banner signal is KEPT.** The dispatch word asked
for breaking-ness to stop being read from the prose banner. Removing
signal (2) would un-declare the **52 changesets in stock** that carry it
and nothing else — the gate's own docblock has refused that direction
("narrowing to any one of them would drop real declarations") since it
was written, and the ruling's own text asks only that the gate *read the
arm*. Signal (4) is added beside it, so breaking-ness no longer
**depends** on prose. If the maintainer wants (2) retired, that is a
second, deliberate card with its own stock count.
2. **`check-adr-0087-registration` reads the arm from the CHANGESET
body, not the PR body.** It has no pull-request payload by construction
— `cut-rc.yml` runs it on a `workflow_dispatch` over a whole snapshot
range with no PR at all. All three of its existing signals are
changeset-local, and the fourth is too.

## Acceptance notes

- noted, not filed: `readClause2Correction` does not carry the arm. A
correction comment can change a declaration's *value* but not its
*direction*. No half-state results today — the arm's three readers are
the changeset body (ADR-0087), the PR body (no-major) and this file's
own rows, and none of them reads corrections — so this is recorded
rather than filed. Carrier: `scripts/pm/check-clause2-carriers.mjs`, the
next card that touches `readClause2Correction`.
- noted, not filed: the I1/I2 fixture in
`check-adr-0087-registration.mjs` staged its import siblings from a
hand-written two-name list. Signal (4) added an edge into a nine-module
closure including `pm/dispatch-gates.mjs`, so the list is now
**derived** by walking real import statements. That is a guard extension
inside this card's own defect class, not a drive-by: without it, the
next import added over in `pm/` would kill this gate's fixture with an
error about neither file.

## 维护者速读(草稿)

**改了什么** —「本卡是否放宽契约」这条申报,现在可以再带一个方向:`(widening)` 或
`(narrowing)`,只有这两种拼法。声明 `(narrowing)` 的改动会被三个门禁当作破坏性变更处理:必须写 ADR-0087
处置、必须给到 `minor` 档。`AGENTS.md` 记下格式,行数一行没多。

**为什么改** — 一次「以后不再接受某些写法」的收紧,过去可以在发布说明里一个字都不提就发给客户,所有门禁照样亮绿:门禁是从作者手写的
`**BREAKING**` 横幅判断破坏性的,忘了写就当没有。objectstack-ai#16296 和 objectstack-ai#14238
就是这么发出去的。改完之后,判据是一个封闭的词,不是一段散文。

**风险与代价(含回滚)** — 风险面是「在飞的申报会不会一夜失效」。方向词是可选的,板上 5 个在飞 PR
的申报实测全部逐字不变,已列在上面的表里。代价是作者多写一个词,并且要把同一行抄进 changeset
正文。两条已申报的判断:`**BREAKING**` 横幅这条旧信号保留(库存里 52 个 changeset 只靠它),以及 ADR-0087
门禁从 changeset 正文读方向(它跑 RC 切版时根本没有 PR)。回滚是单笔
revert:三个门禁各自的自测都是新增用例,没有既有用例被改写。

**席位意见** — (留空,复核席定稿)

**你要做的** — 确认两件事:① 旧的 `**BREAKING**`
横幅信号保留,是否合你意(裁定原文只说「读分肢」,派发词的转述是「不再从横幅判断」);② 两条 ADR-0087
账本行记的是平台对象列的取值域收紧 —— 该账本服务的是元数据升级者,请确认这两行落在那里是你要的记录位置。

---

🤖 Generated with [Claude Code](https://claude.com/claude-code)

_Generated by [Claude
Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_

---
_Generated by [Claude
Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_

---
_Generated by [Claude Code](https://claude.ai/code)_

---------

Co-authored-by: claude[bot] <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
…s grep recipe's scope (objectstack-ai#18399)

Fixes objectstack-ai#18345

ADR-0135 carried two stale artefacts, and neither would have survived on
its own: both were
tied to work tracked by card objectstack-ai#14361, which PR objectstack-ai#18344 retired on
2026-09-16. This card exists
to outlive that retirement, and this PR is the whole of it — two
passages, nothing else in the
file touched.

## 1. The `Until then` bullet is MARKED as history, not rewritten

The Consequences bullet described a transition that has ended. Following
the seat's direction,
the four original lines are kept **byte-identical** — rewriting a mirror
record's Consequences
prose is the governance judgment the approver makes, not a dev edit. The
bullet gains a history
marker above them and the reading below them, so a reader cannot reach
the stale sentences
without first being told they are historical.

**One correction to the dispatch's suggested wording, measured rather
than assumed.** The
re-pointing did NOT land together with card objectstack-ai#14361's retirement on
2026-09-16. It landed on
2026-09-14 in PR objectstack-ai#18228 (merge commit `0f95f434`, merged
2026-09-14T23:02:43Z). Card objectstack-ai#14361
itself then stayed open two more days and was retired by PR objectstack-ai#18344 at
2026-09-16T06:27:30Z. The
text I added names **the landing**, not the card's retirement, because
the landing is what made
the `Until then` state end.

Reading, taken on `objectstack-ai/objectstack` at `8b81ab60` (the branch
point):

| measurement | count |
|:---|---:|
| `ADR-0024` occurrences in `packages/plugins/plugin-auth/src` +
`packages/platform-objects/src/identity` | 14 |
| of those, occurrences carrying the `cloud ADR-0024` qualifier | 14 |
| **bare, unqualified occurrences — the ones the bullet is about** |
**0** |
| firing control: `ADR-0135` occurrences in the same two trees | 62 |
| dark control: a string that must not exist there | 0 |

The card's own reading was `ADR-0024 ②` = 0 with `ADR-0135 D6` = 12
files as the firing control;
both reproduce here. The occurrence-level measurement above is stronger
than the marker count:
it shows there is no bare citation left at all, not merely that one
spelling is gone. Every one
of the 14 was checked with its left context, so the count does not rest
on a line filter — which
is exactly the instrument error item 2 is about.

## 2. The grep recipe is UNCHANGED and gains one sentence of scope

The recipe in Provenance point 3 is true in its own sentence and is not
edited. What it lacked
was its range, so it read like a per-site population filter and was
reused as one twice. One
sentence now states what it counts (LINES, on the one historical commit
that introduced this
record) and why the shape cannot be reused as a census of citation
sites: a line can carry two
citations and a citation can wrap across two lines, so sorting lines by
the `cloud ADR-0024`
spelling mis-sorts in both directions.

## Acceptance notes

- **The card declared one gap unmeasured; it is now measured.** The card
said it had never
checked whether a THIRD stale conditional sits elsewhere in this file.
Swept on `e29b3af7`
for transition-shaped prose — `Until then`, `for now`, `not yet`, `once
#`, `pending`,
`in the meantime`, `temporarily`, `soon` — with a dark control. The only
hits are the bullet
  this PR already marks. **There is no third occurrence in this file.**
- The card's other unmeasured item — where else the line-vs-occurrence
error has skewed
readings OUTSIDE `docs/adr/` — is still unmeasured, and this PR does not
touch it.
- `turbo ls --affected` was run and is NOT cited as evidence anywhere
here: it printed all 81
packages rather than narrowing, so it carries no information about this
diff.
- No other citation in the file is touched. The diff is 11 insertions, 1
deletion, one file.

## Verification

All 18 gate families derived for this diff, green, run with the exit
code captured before any
pipe. Derivation is mechanical, not copied from the dispatch:
`dispatch-gates.mjs --commands`
against this tree at `e29b3af7`, reconciled afterwards with `--ran`.

```
18 derived, 18 run, 0 NOT-MEASURED, 0 UNRUN  (a DERIVED zero - all 18 recorded an exit code)
```

check-adr-links · check-adr-links --self-test · check-adr-symbol-anchors
·
check-adr-symbol-anchors --self-test · check-ci-filter-parity ·
check-closing-keyword-parity ·
check-closing-keyword-parity --self-test · check-comment-mask-corpus ·
check:doc-formula-expressions ·
check:adr-anchors · check:cross-package-test-inputs ·
check:doc-authoring · check:driver-memory-census ·
check:nul-bytes · check:pm-governed-merges · check:pm-prior-rulings ·
check:refd-timer-probe ·
check:watch-hint-literal — all exit 0.

`check:doc-formula-expressions` first answered exit 3, PREREQUISITE NOT
MET, which its own text
declares measures nothing. It was re-run to exit 0 after building
`@objectstack/formula` and
`@objectstack/lint`, and only the re-run is recorded as a result.

Governed-surface assertion: `check-governed-merges.mjs --test` on the
file answers **exit 3,
GOVERNED** — `docs/adr/**`, rules layer.

**Repo-wide lint is not owed here, and that is a measurement rather than
a skip.** Three pieces:
1. Population, read from eslint's own config: every `files:` block in
`eslint.config.mjs`
declares only `{ts,tsx,mts,cts,js,jsx,mjs,cjs}`, and the config mentions
markdown zero times.
2. Count, read from eslint's own `--format json`: run against the one
changed file, eslint
answers `File ignored because no matching configuration was supplied` —
0 of 1 changed files
   are inside its population.
3. Invariance for untouched files: no `parserOptions.project` and no
`projectService`, so
type-aware linting is not enabled and this diff cannot move any
untouched file's verdict.

No package is affected: the workspace globs are `packages/*`, `apps/*`,
`examples/*` and
friends, and `docs/` is under none of them — so no build, no package
test and no typecheck is
owed, and this PR declares none.

`skip-changeset` is measured, not assumed: of 77 package manifests,
**0** ship `docs/` or `adr`
in `files[]`, against a positive control of 70 that ship `dist`. Nothing
published moves.

## 维护者速读(草稿)

**改了什么** — 一个文件、两段话、11 行加 1 行减。① Consequences 里那条描述"过渡期"的
bullet:原来的四行**一个字节都没动**,只在它上面加了一行历史标记、下面加了一句实测读数。
② Provenance 里那条 grep 配方:**配方本身一个字符都没改**,只在它后面补了一句说明它数的是什么。
文件里其它任何引用都没碰。

**为什么改** — 这两处都是 objectstack-ai#14361 完工之后留下的过期物,而且**留不住**:它们原本挂在
objectstack-ai#14361 上,那张卡已经被 PR objectstack-ai#18344 收掉了,不单独接出来就会一起消失。①的问题是读者会读到一个
今天已经不存在的过渡状态,并信以为真;②的问题更实:那条配方读起来像一个通用的"逐站点筛选器",
已经被两个席位、三份文档当成筛选器复用过,而它在这个文件上两个方向都会数错。

**风险与代价(含回滚)** — 风险极低。这是纯散文改动,不含任何代码、schema、行为或已发布内容;
77 个包里没有一个把 `docs/` 或 `adr` 放进 `files[]`,所以对 npm 消费者零影响。18 个门禁族全绿。
回滚就是 revert 这一个 commit,没有任何下游产物需要一起回退、也没有迁移要撤。唯一的判断题在①:
本 PR 选择"标注为历史"而不是"改写成现在时" —— 因为改写一份镜像记录的 Consequences 属于治理判断,
应当由批准人来做,不该由 dev 塞进来。若您认为应当直接改写成现在时,那是您的判断,不是本 PR 的缺口。

**席位意见** — (留空,待席位定稿)

**你要做的** — 读①的那条 bullet 和②的那句量程说明,确认措辞。**特别请确认一处事实修正**:
派发建议的措辞写的是"objectstack-ai#14361 于 2026-09-16 落地",实测是**不对的** —— 真正的重指工作是
2026-09-14 由 PR objectstack-ai#18228 落的地,objectstack-ai#14361 这张卡本身多开了两天、2026-09-16 才由 PR objectstack-ai#18344 收掉。
本 PR 的正文写的是**落地日**。确认无误后,这是治理面(`docs/adr/**`),需要您本人批准并由您合入;
⛔ 本席不翻 ready、不入队、不武装 auto-merge。

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Bz6hxDBqK62NP2W1LATvnt)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

3 participants