Repository navigation
Commit 8d13c0b
docs(adr): ADR-0146 D3 — one
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoEkPw1xTkxsbBcd5WD7CXjo)_
Fixes #31014
Clause-②: no
Metadata-protocol: none
**Tier H** (`docs/adr/**`, Prime Directive #14): this PR stays a draft.
The spec seat runs the contract review at `CONTRACT_REVIEW_TIER`, then
hands it to the approver (`os-zhuang`); it lands by the maintainer's
hand or by an authorized APPROVED review followed by the seat's landing.
No seat readies, queues or arms it. Ruling-ref: 6691022506 and
6691217245 on #29594.
## 维护者速读
- 改了什么:只改 ADR-0146 D3 的文字(加状态行一句、Q4 一行、Consequences 与 D11
各一句)。定制单位从「每个只读包一个 `.custom`」改为「每个 App 一个」:HotCRM(1 个 App + 4 个模块,同一命名空间
`crm`、同一版本 6.1.0)只有一个
`app.objectstack.hotcrm.custom`,模块永远没有自己的定制包,ensure 门对 App
的任何成员都答这同一个包,不再 422。内核整体是一个平台套件,只有一个平台定制包
`com.objectstack.kernel.custom`,依赖平台版本 `^18`,不看各内核包 manifest 自己的
version;某个内核包没装时它的覆盖保留并标记,不拒装。按你 17:32 的裁决:这一版内核对象一律不可定制,下一版先开
Users、Organizations 白名单。`pnpm adr:index` 跑过,索引无变化。
- 为什么改:你 17:17 的裁决 ①「定制单位 = App;同意」(记录 6691022506)和 17:32 的 ③(记录
6691217245)。server 车道正在改 ensure 门(#29594 PR 1 已认领),改完要引用这段 ADR 文字。
- 风险与回滚:只有文档,不发布任何包;回滚即撤本 PR。真正的风险是三处裁决没说、本 PR 自己定的点(见下「Decided
here」8、9、10),你不同意哪条就点名。
- 先看:`docs/adr/0146-…md` 的 D3(新增「The unit is the App」段、「The kernel is
one platform suite」段、「Not taken」段);文末「Decided here」第 8–10 条。
- 两分钟验证:`node scripts/adr-index.mjs --check` 预期 exit 0 且 README 无
diff;`pnpm check:adr-symbol-anchors` 预期绿(本 PR 新引了 14 个 `path#symbol` 锚)。
- 契约复审第一轮(记录 6692724375,PASS,四条 should-fix):已在 `05ea9bbb78` 一次改完;第二轮(记录
6693213712,PASS,两条 should-fix):已在 `b13af10317` 改完;第三轮(记录
6693528804,PASS,两条边界 should-fix,席位定为最后一轮):已在 `2990a3dc26` 改完。见文末「Decided
here」第 11、12 条和「Contract review」三节;README 仍无变化。
- 需要你做的:Tier H,需要你(经 os-zhuang)审批;平台定制包 id
`com.objectstack.kernel.custom` 是我选的,备选见下,不同意就改。
## What changes
One file:
`docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md`
(+201 / −29 against the merge base, over four commits: `e2cc08eb52`, the
round-1 `05ea9bbb78`, the round-2 `b13af10317` and the round-3
`2990a3dc26`). `docs/adr/README.md` was regenerated with `pnpm
adr:index` and is byte-identical (the Status line's first sentence,
which the index reads, did not move).
**D3, amended in place** (house form: the 2026-10-31 rewrite and the
#30881 amendment), following the card's Expected 1–10:
1. **Status line**: one dated `**Amended in place** (2026-11-06, …)`
sentence quoting both rulings verbatim, 「① 定制单位 = App;同意」 and
「内核白名单,可以下一版本再处理,首批名单建议:Users、Organizations;其他同意。」, linking ruling
records 6691022506 and 6691217245.
2. **The unit is the App.** New paragraph and three bullets under D3: an
App is the `type: 'app'` package plus every package its artifact
delivers, whatever its type (ADR-0019 D1–D4; round 1, S4 nit), one
artifact at one version (ADR-0130 D1/D6). One pair per App,
`APP_ID.custom`; a module never owns a pair; a customization of any
member lands in the App's pair; the ensure door creates on the first ask
(201) and answers the existing pair after (200), never 422 for a member
of the same App; 422 `NAMESPACE_CONFLICT` stays for a namespace held
outside the artifact (`coOwnersOf` arms unchanged). The HotCRM example
is measured: `objectstack-ai/hotcrm` `6961ab1` ships
`app.objectstack.hotcrm` and **four** modules —
`app.objectstack.hotcrm.service`, `.revenue`, `.marketing`, `.o2c` — all
`namespace: 'crm'`, all `6.1.0`, so one pair
`app.objectstack.hotcrm.custom`. (The card and the ruling said three
modules; `.o2c` joined in hotcrm PR #2413.)
3. **The existing bullets re-worded for the App unit** — auto-created
(per-App target), namespace (`APP_NS_custom`; the `sys_` pass-through
close from ruling ① is stated, with the `validateObjectNamespacePrefix`
anchor), dependency range (`^MAJOR` of the App's `manifest.version`;
HotCRM `^6`), uninstall (of the App), "It receives" (from the App or any
of its modules). Walled postures unchanged. One new bullet records
ruling (b): the package list row and the ensure door serve a readable
`customizable` verdict and the pair a Customize lands in.
4. **The kernel is one platform suite with one platform pair.** New
paragraph: kernel packages (manifest `scope` `system` or `cloud`, the
`READ_ONLY_PACKAGE_SCOPES` reading) form one suite with one pair,
`com.objectstack.kernel.custom`, namespace `sys_custom`. Three bullets:
the range is the platform version (`^18` today; the `fixed` group of 109
packages at 18.3.0, never a kernel manifest's own 0.1.0–3.x `version`),
declared in `engines.platform`; orphan tolerance (② as recorded: full
kernel install is a goal, not today's `serve` behaviour — tier presets,
`requires`, the always-on slate, optional Security/Audit — so an absent
kernel package's overrides are kept and marked, the install is never
refused, the verdict is served for the packages present; the same
handling for a module a later App version drops); and ruling ③: no
kernel object is customizable in this version, the ensure door refuses a
kernel package with the readable verdict and never with 422, the next
version opens Users and Organizations only, with the two prerequisites
(the `sys_` prefix heuristics replaced by an object-level `isSystem` the
next version adds, with `hasPlatformObjectPrefix` named as the old
heuristic to retire — round 1, S1; `customizable` judged at every write
into the platform pair by the overridden object's package).
5. **Not taken**, after "Upgrade and audit": (a) a pair per package, (c)
N pairs sharing `NS_custom`, (e) an explicit split key; ADR-0019 and
ADR-0130 not amended.
6. **Q4 row**, **Consequences** "Cost, stated" (one per App, never one
per module) and **D11** follow the new unit. Every other `hotcrm.custom`
mention in the record stays as written on purpose: a new D3 bullet says
that `hotcrm` is the record's shorthand for `app.objectstack.hotcrm`, so
each of them names the App's pair.
7. **Decided here where the rulings were silent** gains items **8 to
12** (below; 11 and 12 from round 1), each also flagged inline. **Refs**
gains the card.
### The platform pair id — chosen here, alternatives weighed
**`com.objectstack.kernel.custom`** (base `com.objectstack.kernel`).
Constraints from the card, all measured on `objectstack-ai/objectstack`
`33bc8ae5` (the PR's merge base) and `objectstack-ai/hotcrm` `6961ab1`:
- satisfies `MANIFEST_ID_PATTERN` (two or more dot-separated segments of
lowercase letters, digits and hyphens, each starting with a letter or
digit): yes;
- held by no real package: `git grep -c -E "com\.objectstack\.kernel\b"`
→ 0 hits in both repositories (every kernel manifest id is
`com.objectstack.SOMETHING`, 29 distinct ids in non-test source; none is
`kernel`);
- `customizationBasePackageId('com.objectstack.kernel.custom')` →
`com.objectstack.kernel` (the pure inverse of `customizationPackageId`);
- namespace `sys_custom` (the kernel namespace `sys` + `_custom`, 10 of
the grammar's 20 characters);
- names the suite, not one package, in the family the kernel ids use.
Alternatives weighed and not taken:
- `com.objectstack.platform` — the ruling's own word for the suite, and
the strongest alternative. Not taken because **22 test files** at
`33bc8ae5` already use `com.objectstack.platform` as a stand-in id for
ONE kernel package (`PLATFORM_PKG`, `SYSTEM_SCOPED`, `KERNEL_ID` …).
With that base, the per-package pair the old
`customizationPackageId(base)` derives and the platform pair
`pairOf(base)` resolves to would be the same string in every one of
those fixtures, so none of them could tell the retired lookup from the
new one; the server lane's refactor tests would pass on either.
- `com.objectstack.sys` — names a namespace; a package is identified by
its id (ADR-0048), and `sys` is already the suite's namespace, not its
id.
- `com.objectstack` — names the vendor, whose own Apps (showcase,
HotCRM) are not the kernel; also a two-segment id that reads as a prefix
of every kernel id.
- `com.objectstack.platform-suite`, `com.objectstack.core` — `core` is
used by three spec/metadata tests and the `package-version.zod.ts`
example as a generic dependency id; `platform-suite` is free but coins a
word the record does not use.
If the maintainer prefers `com.objectstack.platform` despite the fixture
collision, the change is one identifier in the ADR; the fixtures would
then need their stand-in id renamed on the server lane's first PR.
### Decided here where the rulings were silent (new items, for the
approver)
- **8 — the platform pair's id**, above.
- **9 — where the platform range is declared and what "platform version"
means.** The range cannot be a `manifest.dependencies` entry: no package
holds `com.objectstack.kernel`, so ADR-0141 D2's
`checkDeclaredDependencies` would answer it `absent` at every install of
the pair. It is declared in `engines.platform` (`^18`), which the
install handshake already reads (`resolveDeclaredRange`) against
`PROTOCOL_MAJOR`, kept in lockstep with the platform major
(`protocol-version.ts`). The platform version is the release version the
`fixed` group ships (`@objectstack/runtime`'s own `package.json`), and ⛔
not whatever `resolveRuntimeVersion()` answers: that function prefers
the injected `OS_RUNTIME_VERSION` stamp (an image tag or a git sha) when
one is set, which is not a SemVer major. The card's Expected 4 named
that function as the reading of "one version"; the ADR names it as the
thing NOT to read for the range, with the reason.
- **10 — a package-less overlay row over a kernel item waits for the
whitelist.** D11 gains one sentence: while the ensure door refuses a
kernel package (ruling ③), the migration cannot create the platform
pair, so such a row is not migrated; it stays as it is, served as D8
item 1 says, and its package-less write stays open, exactly as
`customizationPairEnsureRefusal`'s docblock describes for any base whose
pair the door refuses today. Closing that write with no pair to name
would leave an administrator no way to change an existing kernel
customization (a view, a translation, an email template) until the next
version.
- **11 — the App of a package, and the package that declares no App**
(round 1, S4). Nothing in the tree persists which artifact delivered a
package (`InstalledPackageSourceSchema` is `code | marketplace |
authored`; `ArtifactInstallScope.packageIds` is an install-time
argument), so the ensure door reads the App of a package the way the
registry already reads a module's namespace co-ownership (ADR-0141
D1/D5; the `dependency` arm of `coOwnersOf`): a `type: 'app'` package is
its own App; any other package's App is the `type: 'app'` package it
directly declares in `manifest.dependencies` — the one holding its
namespace where it declares several, and the readable verdict (not
customizable: no single App) where that leaves none or several — never a
guess, never an id prefix. The reading walks declared parents (round 2,
S4b; made unambiguous in round 3, S4c): for a package that declares no
App directly, the door takes the closure of its declared dependencies,
each package visited once (a cycle terminates), stopping at a `type:
'app'` package (an App's own dependencies are another App's business,
ADR-0141 D1); only the Apps reached count, a kernel or own-unit package
on the way is skipped (a member declaring a module and
`com.objectstack.audit` is still that App's member); one App makes the
package its member, several take the direct rule's namespace tiebreak,
and the readable verdict where that leaves none or several — never 422
for a package of the same App; HotCRM has no such nested module today.
HotCRM's four modules each declare `app.objectstack.hotcrm` `^6.1.0`.
ADR-0141 D3's standalone module is a member for customization (a second
pair in `crm_custom` would be (c), not taken, and the namespace gate
would refuse it) and stays an App in its own right for install, open and
uninstall; uninstalling it alone keeps and marks its overrides. A
package that declares no `type: 'app'` package, directly or through its
declared parents (an operator-provisioned internal contribution, a
plugin installed alone, a code-registered package outside any App), is
its own unit, `PACKAGE_ID.custom` with `NS_custom`; a kernel package
never is — its pair is the platform pair. `pairOf` / `appOf` (PR #31026)
carries the reading; `appOf` is the identity until the ensure door's
change.
- **12 — a pair created under the per-package unit** (round 1, S3). D3
has been in force since 2026-10-31 and the ensure door is landed, so an
environment may hold `app.objectstack.hotcrm.service.custom` or the one
kernel pair today's door creates before its 422s. D11 and this item: the
migration ceremony **re-identifies** such a package as its App's pair
when it holds the App's own namespace — the installed record's id and
dependency rewritten to the App's, its rows re-bound to the new id (they
bind by `package_id`), its items and declared overrides kept (same base,
same `basedOn`). Round 3, S3c: a member may hold a namespace of its own
(ADR-0019 D4), so an App may also hold a pair in a member's namespace
(`crm_svc_custom`); that one is moved, not re-identified — rows re-bound
into the App's pair (created or re-identified first), the package
uninstalled once it owns nothing — never dropped; at most one pair per
namespace existed. Round 2, S3b: moving the items into a newly created
App pair cannot run against today's gates, because the old pair owns
`NS_custom` and both the ensure door (422 `NAMESPACE_CONFLICT`,
`customizationPairEnsureRefusal`) and the install door
(`NamespaceConflictError`) refuse a second owner, and uninstalling it
first would drop its `__c` fields with their data. Until the ceremony
runs the pair is served as it is and the ensure door serves the readable
verdict naming the ceremony, not 422; a kernel one waits with D11's
kernel rows until the whitelist version re-identifies it as the platform
pair and lists the rows it cannot admit.
## Contract review round 1 (record 6692724375, PASS with four
should-fixes) — fixed on `05ea9bbb78`
Each claim was verified against `origin/main` before the edit; all four
are in one commit, ADR file only, README byte-identical.
- **S1 — the next-version prerequisite anchored the wrong reading.**
`hasPlatformObjectPrefix` is `startsWith` over `sys_` / `cloud_` / `ai_`
(its own docblock calls it the OLD heuristic) and answers true for
`sys_custom_x`; no object-level `isSystem` exists in `packages/spec`
(the only `isSystem` keys are service-context flags). The ADR now names
an object-level `isSystem` the next version adds as the declared
reading, and names `hasPlatformObjectPrefix` as one of the heuristics to
retire (the anchor stays as the negative, so the next card finds the
symbol).
- **S2 — `engines.platform` must be the only `engines` key.**
`resolveDeclaredRange` reads `engines.protocol` first. The D3 bullet and
Decided-here 9 now say the platform pair's manifest carries
`engines.platform` as its only `engines` key, and that the ensure door's
existing-pair check — today `declaredRangeOn` over
`manifest.dependencies` in `customizationPairEnsureRefusal` — reads that
key for the platform pair: the one place the rule and today's gate
disagree, carried by the server lane's ensure-door change.
- **S3 — pre-amendment per-package pairs had no disposition.**
Decided-here 12 and one sentence in D11's migrate bullet, above.
- **S4 — the App of a package was not readable from the tree, and the
artifact-less package had no rule.** Decided-here 11, above, plus the
nit: the "unit is the App" paragraph now says "every package its
artifact delivers, whatever its type", not only `module` / `plugin`, and
the "module never owns a pair" bullet points at item 11.
## Contract review round 2 (delta record 6693213712, PASS with two
should-fixes) — fixed on `b13af10317`
Both verified against `origin/main` before the edit (ensure door:
`customizationPairEnsureRefusal`'s namespace-owner arm answers 422;
install door: `NamespaceConflictError` for a non-co-owner); one commit,
ADR file only, README byte-identical.
- **S3b — the fold could not run against today's gates.** Decided-here
12 and D11's migrate sentence now say the ceremony re-identifies the old
pair as the App's pair (id and dependency rewritten; namespace, items,
rows and declared overrides kept), why a fresh App pair cannot be
created beside it, and that until the ceremony runs the ensure door
serves the readable verdict naming the ceremony, not 422.
- **S4b — direct declarations only would 422 a nested member.**
Decided-here 11 now walks declared parents: all parents resolving to one
App makes the package that App's member; parents resolving to different
Apps get the readable verdict; never 422 for a package of the same App.
HotCRM has no such module today.
## Contract review round 3 (delta-2 record 6693528804, PASS with two
edge-case should-fixes; the seat's final fix round) — fixed on
`2990a3dc26`
Both are edge cases with no live instance; verified against ADR-0019 D4
(an App owns a set of namespaces) before the edit; one commit, ADR file
only, README byte-identical.
- **S3c — "at most one such pair per App" held only when every member
shares the App's namespace.** Decided-here 12 and D11 now re-identify
only the pair in the App's own namespace; a pair in a member's own
namespace is moved into the App's pair (rows re-bound; the package
uninstalled once it owns nothing), never dropped. Nit taken: rows are
re-bound to the new id, they do not "stay in place".
- **S4c — the parent walk made unambiguous.** Decided-here 11: (1) only
parents that resolve to an App count, kernel and own-unit parents are
skipped; (2) it is a closure over declared dependencies, each package
visited once, so a cycle terminates, and it stops at an App; (3) the
direct rule's namespace tiebreak applies to the result set.
## Why
Ruling 6691022506 on #29594 (maintainer, 2026-11-06T17:17Z 「① 定制单位 =
App;同意」) and ruling 6691217245 (17:32Z, the kernel whitelist). Today D3
gives one pair per read-only package; every kernel package shares
namespace `sys`, so only the first can get a pair and the rest answer
422 `NAMESPACE_CONFLICT`, and a suite like HotCRM would get five pairs
for one product. The server lane's ensure-door PR (`pairOf(base)` by
App) cites this text once merged; its first PR (the lookup refactor,
claim 6691163548) does not wait on it.
## Tests
None owed: the diff touches `docs/adr/**` only — no package, no test, no
generated artifact (local verification scope ①–②: no closure to build,
no package suite to run). The ADR's own gates are the verification
below.
## Acceptance notes
- `docs/adr/README.md` regenerated and unchanged: the index reads only
the first 40 header lines for `**Supersedes**`-style fields
(`scripts/adr-index.mjs` `HEADER_WINDOW`). A three-line version of the
status sentence pushed `**Supersedes in part**:` to line 42 and silently
dropped ADR-0146's Supersedes column from the index; the sentence is one
line so the field stays at line 39. Worth knowing for the next amendment
of this record: there is one header line of headroom left.
- The card and ruling ① count three HotCRM modules; `origin/main` of
hotcrm ships four (`.o2c`, hotcrm PR #2413). The ADR names the four as
measured.
- The ADR states the `cloud` scope as part of the kernel suite because
`READ_ONLY_PACKAGE_SCOPES` and the console's kernel-package reading both
say `system` or `cloud`; no `scope: 'cloud'` manifest exists in this
repository's `packages/**` (they live in the cloud repository), so the
sentence binds nothing here today.
- Commit `e2cc08eb52`'s author is spelled `objectstack-fleet[bot]` with
the generic noreply email rather than this checkout's configured author
(`Claude`, the anthropic noreply address) — my mistake on the commit
line. Not rewritten: the thread branch is not force-pushable under
Multi-agent discipline §3 (its name is not `claude/issue-*`), and the
squash merge replaces the author anyway. Deviation, declared. The
round-1, round-2 and round-3 commits (`05ea9bbb78`, `b13af10317`,
`2990a3dc26`) carry the checkout's configured author.
- Out of scope, not filed (carrier: the server lane's #29594 PRs): the
code spelling of the same rules in
`packages/spec/src/kernel/customization-package.ts`
(`customizationPackageId` / `customizationNamespace` /
`customizationDependencyRange`) is untouched here, as the card orders.
## Verification
Head `2990a3dc26` (= `origin/main` `33bc8ae5ff` + `e2cc08eb52` + the
round-1, round-2 and round-3 commits; 1 file, +201 / −29 against the
merge base, 230 changed lines, under the 3000 human-merge threshold).
The gate lines below are the round-3 run on `2990a3dc26`; the same 21
families were derived for each earlier head and were all green on each.
- `node scripts/adr-index.mjs --check` → exit 0, `adr-index: unchanged
docs/adr/README.md (237 lines)`.
- `node scripts/pm/check-governed-merges.mjs --test docs/adr/0146-…md` →
`docs/adr/**` Tier H by path.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived **21** families; every one run in
the foreground with stdin from `/dev/null`, exit code captured before
any pipe, landed in `gates-ran-2990a3dc26.list`; `--ran` reconciliation:
`21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN` (exit 0). Plus `pnpm
--filter '@objectstack/lint...' build` under the verify lock (exit 0) as
the prerequisite of `check:doc-formula-expressions`.
<details><summary>The 21 gate lines, all exit 0</summary>
```
node scripts/check-adr-links.mjs :: exit 0
node scripts/check-adr-links.mjs --self-test :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm check:adr-anchors :: exit 0
pnpm check:adr-index :: exit 0
pnpm check:adr-symbol-anchors :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-prior-rulings :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:watch-hint-literal :: exit 0
```
</details>
- Neighbours: of the 37 open PRs at the time of the first push, none
changes `docs/adr/0146-*` or `docs/adr/README.md` relative to its merge
base (11 mailbox PRs and the Version Packages PR carry the files only
because their base is old; #30986 edits ADR-0050 and the index's
ADR-0050 row, no overlap with this diff).
- Writes: `git push` (4: `e2cc08eb52`, `05ea9bbb78`, `b13af10317`,
`2990a3dc26`), relay `pr_create` (1, this PR, `skip-changeset` on the
create), `os-dev-report` comment (1, post-stamped), relay `issue_patch`
(3, this body after rounds 1, 2 and 3). `mcp_calls`: 0 writes (reads
only: issue/PR reads of #31014, #29594, #31026 and the open-PR list).
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(No schema touched.)
- [x] 2. Every name I added uses the casing for its kind. (One package
id, `com.objectstack.kernel.custom`, in the manifest id grammar.)
- [x] 3. No formatter ran; `pnpm lint` is CI's run — docs only.
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. Publishes nothing (`docs/adr/**` only) — `skip-changeset`; both
declaration lines are above.
- [x] 6. `packages/spec` not touched.
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`;
`docs/adr/README.md` regenerated, not hand-edited.
- [x] 8. Title, body and comments are in English; the 速读 and the quoted
rulings are in Chinese by rule.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
<!-- signed: domain:spec#1 · os-tesla · session_01L9qibxn8FPvL85i9w26qoq
-->
---------
Co-authored-by: objectstack-fleet[bot] <objectstack-fleet[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>.custom pair per App, and one platform pair for the kernel suite (#31027)1 parent 704efef commit 8d13c0b
1 file changed
Lines changed: 201 additions & 29 deletions
0 commit comments