Repository navigation
Commit a40eb02
tooling(facade-delegation-only): derive the gate for a diff to any facade file (#31455)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1XLdd48ehXd7GqyNBGWeaBXw)_
domain:devx#3 · os-project-manager · session_01FEkQ5nHcpVKdkynE7zEoAV
Fixes #31444
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:只改 `scripts/check-facade-delegation-only.mjs`。把门禁真正审查的三个 facade
文件(`protocol.ts`、`engine.ts`、`sql-driver.ts`)写成 `DECLARED_WATCH_HINTS`
字面量数组,并在它自己的 self-test 里加一条 N7,要求这份声明与注册表 `facades[].file` 双向完全一致。
- 为什么改:门禁原来唯一的路径字面量是注册表 JSON,派生工具看不到 JSON 里的 facade 文件,于是改 `protocol.ts`
的开发者拿到的门禁清单里没有这个门禁,只能等 CI 红(PR #31439 就是这样)。
- 风险与回滚:只是仓库工具脚本,不发布、不改任何包和工作流;回滚即还原本 PR。
- 先看:`scripts/check-facade-delegation-only.mjs` 约 193 行新的
`DECLARED_WATCH_HINTS`,和约 1050 行新的 N7 用例。
- 两分钟验证:改 `packages/objectql/src/engine.ts` 一行后跑 `node
scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`,预期输出里出现 `pnpm
check:facade-delegation-only`(本 PR 之前没有)。
- 需要你做的:无,席位落地。
## What changes
`scripts/check-facade-delegation-only.mjs` only (+46 / -2).
1. **The scan surface is declared.** A new `DECLARED_WATCH_HINTS`
literal array names the three registered facade files, one repo-relative
file per string: `packages/metadata-protocol/src/protocol.ts`,
`packages/objectql/src/engine.ts`,
`packages/drivers/driver-sql/src/sql-driver.ts`. `dispatch-gates` reads
a gate's population from the path literals in its source text, and
`hintCovers` matches an exact file literal by equality (`inputPath ===
plain`), so no tool change is needed. The idiom and spelling are those
of `scripts/check-tenant-chokepoint.mjs`, which declares its seam
modules the same way. A subtree such as `packages/objectql/**` was not
used: the gate reads the facade file and nothing beside it, so a subtree
would name it on hundreds of files it never opens.
2. **The declaration is pinned to the registry.** Self-test case **N7**
reads the committed `scripts/facade-delegation-registry.json` and
requires `DECLARED_WATCH_HINTS` to equal the set of `facades[].file` in
both directions, with no duplicate. Each failure names the exact string
to add or remove. Registering a new facade file now reds `pnpm
check:facade-delegation-only` (which runs `--self-test` first) until the
file is declared. The battery roster and its floor move 37 → 38.
3. **The header** tells the next split to add a new facade file's path
to the declaration beside its `facades` row.
`scripts/pm/dispatch-gates.mjs` is untouched: an existing idiom
expresses a file population.
## Why
Card #31444: PR #31439 added two member bodies to the `protocol.ts`
facade, its derived gate list (102 of 102 green) never named this gate,
and CI went red on it. Rulings from the order: p2, `domain:devx`; no new
gate, no workflow step, no `.github/**` change; other artifact-roster
families are report-only.
## Tests
<details><summary>Self-test, and the N7 pin ablated in both directions
(head 9fc82cf)</summary>
`pnpm check:facade-delegation-only`, exit 0:
```
✓ N6 the committed registry is well-formed against this checkout
✓ N7 the declared watch hints are exactly the committed registry's facade files
✓ check-facade-delegation-only self-test: 38 cases pass.
✓ check-facade-delegation-only: 5 facade class(es) in 3 file(s) hold delegations only, 11 named exception(s).
```
Ablation 1, through `node scripts/ablation-replace.mjs --delete` on the
committed file: the `sql-driver.ts` line removed from the declaration
(anchor 1 → 0, blob `cce21f46` → `88b6881e`). `--self-test` exit 1:
```
✗ N7 the declared watch hints are exactly the committed registry's facade files
registered facade file(s) 'packages/drivers/driver-sql/src/sql-driver.ts' missing from DECLARED_WATCH_HINTS: add each string there, or dispatch-gates never names this gate for a diff to that file
```
Restored: blob == HEAD (`cce21f46`), `git diff HEAD` empty, self-test 38
pass.
Ablation 2, the other direction: an unregistered
`packages/objectql/src/index.ts` added beside `engine.ts` (blob
`cce21f46` → `3fef83a4`). `--self-test` exit 1:
```
✗ N7 the declared watch hints are exactly the committed registry's facade files
DECLARED_WATCH_HINTS names 'packages/objectql/src/index.ts', which scripts/facade-delegation-registry.json does not register: remove each string, or dispatch-gates names this gate for a file it never reads
```
Restored: blob == HEAD (`cce21f46`), `git diff HEAD` empty.
</details>
<details><summary>Before / after: dispatch-gates names the gate for each
facade file</summary>
**Changeset form (the card's measurement).** A one-line comment appended
to each facade file in turn, then `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack`, file restored after each
run.
| file changed | before (main `9728ab15`) | after (head `9fc82cfb`) |
| --- | --- | --- |
| `packages/metadata-protocol/src/protocol.ts` | 55 commands, gate
absent | gate named |
| `packages/objectql/src/engine.ts` | 53 commands, gate absent | gate
named |
| `packages/drivers/driver-sql/src/sql-driver.ts` | 53 commands, gate
absent | gate named |
Before, the gate shows only on stderr, in the "Artifact rosters" block
that is outside the runnable total. The "after" changeset also carries
this PR's own edit to the gate script, which names the gate by script
identity anyway. So the isolated reading below is the proof.
**Isolated form.** The same derivation with the facade file as the only
path on argv (`--commands --repo objectstack-ai/objectstack PATH`). The
before tree is `main` `9728ab15`, the after tree is head `9fc82cfb`, and
the stdout lists are compared with `diff`:
| path | before | after | diff |
| --- | --- | --- | --- |
| `packages/metadata-protocol/src/protocol.ts` | 55, gate absent | 56 |
`> pnpm check:facade-delegation-only` |
| `packages/objectql/src/engine.ts` | 53, gate absent | 54 | `> pnpm
check:facade-delegation-only` |
| `packages/drivers/driver-sql/src/sql-driver.ts` | 53, gate absent | 54
| `> pnpm check:facade-delegation-only` |
Each facade path gains exactly one command, this gate, and nothing else
moves.
</details>
## Acceptance notes
- **No tool change.** `hintCovers` already matches a literal that spells
a tracked file exactly, and `DECLARED_WATCH_HINTS` is a rostered
declaration name in `check:watch-hint-literal`. Its `--list` reads the
new declaration with all three literals, and the gate is green: "78
declaration(s) … DECLARED_WATCH_HINTS 10 … all 263 of those literals
admitted by the hint extractor".
- **For a diff to any other file** the family stays silent, which is
correct: the gate reads only the facade files and the registry. Its four
literals are all tracked files with no shared directory, so `--residue`
still lists it under "Artifact rosters" with the note "They share no
directory, so this silence is an ordinary one". That note is now true.
- **Other artifact-roster families (report only).** Read on this card's
`protocol.ts` probe, the block lists 51 families, 16 of them
checker-health only. None holds its judged population only inside a
registry file the way this gate did. `check:engine-double-contract`,
`check:authz-resolver` and `check:error-code-casing` walk `packages`
(and `examples`), declared through the bare word that the derivation
refuses as too generic. That is a different shape, which the tool
already marks ⛔ when the caller's path is under the roster's directory.
`check:auth-mount-ledger` and `check:tenant-chokepoint` already declare
their files as literals. Nothing is fixed here.
- **Governed surface.** `node scripts/pm/check-governed-merges.mjs
--branch HEAD` on head `9fc82cfb`, exit 0: "0 of 1 path(s) hit the
register … NOT governed — ordinary queue landing applies".
- `node scripts/pm/dispatch-gates.mjs --tier`: no path-derived model
mandate for this surface; 48 changed lines.
## Verification
Gate union derived by `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` (31 families for this diff), run on
head `9fc82cfb`, each exit code captured before any pipe:
- **31 run, exit 0 each.** `--ran`: "31 derived famil(ies) accounted for
— 31 run, 0 NOT-MEASURED".
- `pnpm check:pm-dispatch-gates` (fast tier): "2205 cases pass; 9 slow
section(s) deferred", 394 s.
- `pnpm check:facade-delegation-only`, `pnpm check:watch-hint-literal`,
`pnpm check:cli-command-ids`, `pnpm check:nul-bytes` and the rest of the
union: exit 0.
- `pnpm lint`: the diff touches no package, so there is no scoped
package lint.
- Families outside the derived total (artifact rosters, declared WIDE,
the type-check lanes, the always-runs tail) are read from this PR's
check-runs, not re-run here.
`skip-changeset`: `scripts/**` ships in no package.
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(not touched)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (no package touched)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset. (publishes
nothing: `skip-changeset`)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (not touched)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English. (the 维护者速读 block is
the lane's required Chinese summary)
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FEkQ5nHcpVKdkynE7zEoAV
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5nHcpVKdkynE7zEoAV)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 432707c commit a40eb02
1 file changed
Lines changed: 46 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
45 | 47 | | |
46 | 48 | | |
47 | 49 | | |
| |||
170 | 172 | | |
171 | 173 | | |
172 | 174 | | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
173 | 199 | | |
174 | 200 | | |
175 | 201 | | |
| |||
824 | 850 | | |
825 | 851 | | |
826 | 852 | | |
| 853 | + | |
827 | 854 | | |
828 | | - | |
| 855 | + | |
829 | 856 | | |
830 | 857 | | |
831 | 858 | | |
| |||
1020 | 1047 | | |
1021 | 1048 | | |
1022 | 1049 | | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
1023 | 1067 | | |
1024 | 1068 | | |
1025 | 1069 | | |
| |||
0 commit comments