Repository navigation
Commit 6c5bef5
docs(adr): ADR-0128 §4 dated note — the keyed-digest break did not carry D1, and why (#21343)
Fixes #21327
Clause-②: no
ADR-0128 §4 ("The trigger that would fund it") gets one dated sentence
under its third trigger, "`ICryptoProvider` is opened for another
breaking change". The sentence records three things. The keyed-digest
break (#21263, PR #21292) met that trigger and landed without D1, by the
maintainer's ruling A (comment 5945612493 on #21263). The reason is that
the director's census (comment 5945420994) measured zero out-of-repo
`ICryptoProvider` implementations in the organisation's repositories.
And D1 is scheduled on its own as #21326.
⛔ D1–D4, the status line and every other section are unchanged. No code
and no changeset: `docs/adr/**` publishes nothing.
## The change
- **File:**
`docs/adr/0128-producer-discriminated-aad-for-cryptocontext.md`, one
added line. Line count 130 → 131 (+1 / −0).
- **Placement:** an indented blockquote inside the third trigger's list
item. It renders under that bullet, and the fourth trigger stays a list
item. Checked by rendering lines 97–106 with micromark 4.0.2 from this
workspace: the note comes out as a `blockquote` inside the third `li`,
followed by the fourth `li`.
- **Form:** `> **Note (2026-10-02).** …`. ADR-0128 carried no dated note
before, so the form is the most common inline dated-note label in
`docs/adr/` at `222ecc27`: 5 blockquotes open with "Note (YYYY-MM-DD",
against 4 "Amended (", 3 "Revision note" and 1 "YYYY-MM-DD note".
"Amended" was not used, because the note amends no decision.
- **Links:** the two forms this ADR already uses, `[#N](…/issues/N)` and
`comment [id](…/issues/N#issuecomment-id)`, plus `PR
[#21292](…/pull/21292)`. All are absolute GitHub URLs, so
`check-adr-links` (relative links only) has nothing new to resolve.
The sentence as landed, links shown as plain text:
> **Note (2026-10-02).** This trigger was met by the keyed-digest break
(#21263, PR #21292: a required `keyedDigest` member on
`ICryptoProvider`), which landed without D1 by the maintainer's ruling A
(comment 5945612493) because the director's census (comment 5945420994)
measured zero out-of-repo `ICryptoProvider` implementations in the
organisation's repositories, so pulling D1 in would have saved a second
breaking-export change for no measured implementer population; D1 is
scheduled on its own as #21326.
## Premise check (against `origin/main` at `222ecc27`)
- **PR #21292 is merged as `222ecc27`**, a squash with one parent
(`bada8d35`). Its diff adds the required member `keyedDigest(plain:
string)`, an asynchronous method that yields a string, to
`ICryptoProvider` in `packages/spec/src/contracts/crypto-provider.ts`,
and `LocalCryptoProvider` implements it. That is the "opened for another
breaking change" the third trigger names.
- **It carries no D1.** In the 414-line `git show` of `222ecc27`, zero
added or removed lines match `aad|discriminant|CryptoContext|scope`
(case-insensitive). The positive control is 40 such lines matching
`keyedDigest`. On the merged tree, `CryptoContext` is still `{
namespace, key, tenantId? }`, and `LocalCryptoProvider.aadOf` still
joins `namespace` and `key` with an unescaped separator.
- **The sources the sentence cites:** comment 5945420994 (the census)
and comment 5945612493 (the ruling) are on #21263, and both read as the
card quotes them. #21326 is open.
## Verification
Everything ran at HEAD `0524a7d9`, the only commit on this branch, over
base `222ecc27`. `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` derived 19 commands from the
branch's change set, the same 19 as at dispatch. All 19 ran, and each
exit code was captured before any pipe.
| Command | Exit | The gate's own verdict line (excerpt) |
|:--|:--|:--|
| `node scripts/check-adr-links.mjs` | 0 | ✅ 695 relative link
destination(s) under docs/adr/ resolve |
| `node scripts/check-adr-links.mjs --self-test` | 0 | ✅ discrimination,
census, ADR-0046 pin and baseline staleness all verified |
| `node scripts/check-adr-symbol-anchors.mjs` | 0 | ✅ 2166 anchors
across 140 records resolve |
| `node scripts/check-adr-symbol-anchors.mjs --self-test` | 0 | ✅ every
finding class provoked, healthy anchors silent |
| `node scripts/check-ci-filter-parity.mjs` | 0 | OK: all 192 declared
cross-package glob(s) are covered |
| `node scripts/check-closing-keyword-parity.mjs` | 0 | OK (3 parsers
agree on all 9 keywords) |
| `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | ✓ 40
assertions, 5 mutations each driven to red |
| `node scripts/check-comment-mask-corpus.mjs` | 0 | ✓ 7914 files, 0
disagree, 0 unparseable |
| `pnpm --filter @objectstack/lint run check:doc-formula-expressions` |
0 | ✓ 22 record-scoped formula example(s) across 459 files judged clean
|
| `pnpm check:adr-anchors` | 0 | OK (57 anchored file(s), 134 decision
number(s)) |
| `pnpm check:cross-package-test-inputs` | 0 | OK: 30 package(s) read
outside themselves, all declared |
| `pnpm check:doc-authoring` | 0 | ✓ 17158 customer-facing string(s)
clean |
| `pnpm check:driver-memory-census` | 0 | OK — every declaration is
ledgered |
| `pnpm check:gitlink-declared` | 0 | OK (0 gitlink(s) at mode 160000) |
| `pnpm check:nul-bytes` | 0 | OK (9636 text file(s); no raw ASCII
control bytes) |
| `pnpm check:pm-governed-merges` | 0 | ✓ 454 assertions; the real
generator certified this tree |
| `pnpm check:pm-prior-rulings` | 0 | ✓ 155 cases pass |
| `pnpm check:refd-timer-probe` | 0 | OK, 7909 source file(s) swept |
| `pnpm check:watch-hint-literal` | 0 | ✓ 72 declaration(s) across 4
rostered name(s) |
- **Reconciliation:** `dispatch-gates.mjs --ran`, given the 19 commands
each with its exit code, printed "Run reconciliation — 19 derived, 19
run, 0 NOT-MEASURED, 0 UNRUN" and "a DERIVED zero — all 19 recorded an
exit code".
- **Build before the formula gate:** that gate imports the built
`@objectstack/lint` and `@objectstack/formula`. So `pnpm
--workspace-concurrency=2 --filter '@objectstack/lint...' build` ran
first under `scripts/pm/os-verify-lock.sh` ("VERDICT command-exit 0").
`git status --porcelain` was empty after the build.
- **NOT MEASURED locally, CI's to run:** the families `dispatch-gates`
lists outside its 19 commands, which are the artifact rosters, the
wide-population families, the path-scheduled `Test Core` job and the
type-check lanes. This diff touches no TypeScript and no package.
## Acceptance notes
- **Why the sentence is scoped as it is.** The census states its own
limit: implementers outside the organisation, who consume the published
`@objectstack/spec` from npm, cannot be measured from there. So the
sentence says "in the organisation's repositories" and "no measured
implementer population", not "no implementers".
- **Nothing filed** from this diff.
## Landing
This is Tier H (`docs/adr/**`). The PR stays a draft and is held for the
maintainer's own approval, as the ruling says. This seat does not mark
it ready, queue it or arm auto-merge.
## 维护者速读(草稿)
**改了什么**:ADR-0128 §4「触发条件」第三条(`ICryptoProvider`
再有破坏性变更)下面,加了一句带日期(2026-10-02)的注。注里说:密钥化摘要那次破坏性变更(#21263 / PR
#21292)已经触发了这一条,但没有顺带做 D1。只加了一行;D1–D4、状态行和其它章节一个字都没动。
**为什么改**:ADR 原文写着「再有破坏性变更时,应把 D1 一起带上」,而您批的裁决 A 让 #21292
单独落地了。不留这句注的话,以后读 ADR 的人会以为是漏了 D1。注里写明了理由:总监席普查了组织内的所有仓库,仓外的
`ICryptoProvider` 实现数为零,所以捆绑 D1 想省下的「第二次破坏」没有实际的承受方。D1 已经单独排期,在 #21326。
**风险与代价(含回滚)**:纯文档改动,只有一行。不发包,不影响任何运行时行为。普查只覆盖组织内的仓库,从 npm
引用的外部实现方是测不到的,所以注里的措辞限定为「组织内的仓库」和「没有实测到的实现方」。回滚就是 revert 这一行。
**席位意见**:(留空,由席位定稿时填写)
**你要做的**:读一下这句注的措辞;没问题的话,在本 PR 上点 Approve(Tier H,需要您本人批准)。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 04f0cc4 commit 6c5bef5
1 file changed
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| 104 | + | |
104 | 105 | | |
105 | 106 | | |
106 | 107 | | |
| |||
0 commit comments