Repository navigation
Commit 9f15939
fix(lint): the approval-approvers-may-resolve-empty remedy names the admin bulk import's manager_id column (#22703)
Fixes #22683
Clause-②: no
## What was wrong
On a node whose approvers are all `{ type: 'manager' }`, `os lint`
reports `approval-approvers-may-resolve-empty` (info). Its hint ended
the SCIM clause with "and its admin bulk import does not write it
either". That has been false since the import admitted a `manager_id`
column (PR #18046), so the remedy sent an author with a whole file of
reports away from a supported route. The guide
(`automation/approvals.mdx`, corrected by PR #22681) already names that
column and says `os lint` "carries the same remedy text", so the lint
string was one clause behind it.
## What changed (3 files, +69 / -15)
- `packages/lint/src/validate-approval-approvers.ts`
- `MANAGER_ONLY_ROUTES`: the false clause is gone. The bulk import
(`POST /api/v1/auth/admin/import-users`) is named as a route that works,
right after the endpoint and its refusals and ahead of the clause that
hands SCIM and directory sync to the deployment. It reads a `manager_id`
column holding the manager's email (or phone where phone sign-in is
enabled), links each row once every row in the file exists, through the
same refusals, and reports a link it cannot make on that row's `manager`
result without failing the user. The `idp_provisioned` clause keeps its
wording and now says the import's column is refused too.
- `MANAGER_ONLY_REMEDY`: names Set Manager (Setup → Users, row menu or
record header) beside the endpoint it posts to. The card's done-when
says "beside Set Manager and the endpoint"; the hint did not name Set
Manager at all before, so this is the one addition beyond dropping the
clause. The word "Console" is still used only inside the existing
denial.
- The file's own docblock graded the import "NOT here ... ruled but a
separate change"; that grade is replaced with the measured one, so no
comment in the file contradicts the string.
- Unchanged: what the rule fires on, its level (`info`),
`stackWiresManagerChain` as the one silencer, the fallback clause, the
closing sentences.
- `packages/lint/src/validate-approval-approvers.test.ts`: the pin on
"admin bulk import does not write it either" is replaced. The 'GRADES
the routes' test now asserts the import path, `reads a manager_id
column`, `once every row in the file exists`, the per-row report, that
the old clause is gone, and that the import is named before the clause
that hands the remaining routes to the deployment. The 'names the REAL
remedy' test asserts Set Manager.
- `.changeset/22683-approver-remedy-bulk-import.md`: `@objectstack/lint`
patch, `Clause-②: no`.
## Premise check (measured on origin/main cb3bb93 before writing a
sentence)
The import does what the new sentence says, read in
`packages/plugins/plugin-auth/src/admin-import-users.ts`:
`MANAGER_COLUMN = 'manager_id'`; `resolveManagerKey` reads the cell as
an email, or a phone number only when the phone plugin is wired; the
cell is deleted from the row before the identity write; the second pass
runs after `runImport` returns, resolves the key against this batch's
rows and then against `sys_user`, and calls `applyUserManagerLink` (the
endpoint's derivation); a failure goes to `noteManagerFailure` on the
row, never a whole-import failure; `dryRun` skips the pass. Behaviour:
`pnpm --filter @objectstack/plugin-auth exec vitest run --maxWorkers=2
src/admin-import-users-manager-pass.test.ts` after building
`@objectstack/plugin-auth^...`: `Test Files 1 passed (1)`, `Tests 20
passed (20)`, including a link to a manager created by a later row and
its control where the manager does not exist yet.
## Grep for the family (the card's done-when), on this branch at head
d63e3f6
```
$ git grep -n "bulk import does not write" -- packages/lint/src content/docs skills
(no output; exit 1)
$ git grep -n "bulk import does not write" cb3bb93 -- packages/lint/src content/docs skills # positive control, the base commit
cb3bb93:packages/lint/src/validate-approval-approvers.test.ts:313: expect(finding.hint).toContain('admin bulk import does not write it either');
cb3bb93:packages/lint/src/validate-approval-approvers.ts:199: `admin bulk import does not write it either — and where an identity carries ` +
```
A wider pass over `packages`, `content`, `skills` (CHANGELOGs excluded)
for "import does not write" and "does not write it either" has one hit:
a comment in the test file that quotes the retired clause. It also finds
no other claim that the import or anything else fails to write
`manager_id`; the only near-misses are two past-tense history notes
("had no product write surface") in `auth-route-ledger.ts` and
`admin-set-user-manager.test.ts`, true of the column before the endpoint
landed. With this card the enumeration covers `packages/lint/src`,
`content/docs` and `skills/`.
## Verification
- Pin test, before the change: `Tests 47 passed (47)`; after: `Tests 47
passed (47)` (`pnpm --filter @objectstack/lint exec vitest run
--maxWorkers=2 src/validate-approval-approvers.test.ts`).
- Reverse verification, run from the committed fix: the source file
restored to its parent version (working tree only), the same test:
`Tests 2 failed | 45 passed (47)`, `expected 'sys_user.manager_id is not
a profile …' to contain 'Set Manager'` and `... to contain
'/api/v1/auth/admin/import-users'`. Direction: red, as expected.
Restored with `git checkout HEAD -- path`; the file's blob hash read
`143561c356c5871ccbc2c42d082c1b854797171d` before and after, and `git
diff HEAD` was empty.
- Whole package: `pnpm --filter @objectstack/lint exec vitest run
--maxWorkers=2`: `Test Files 135 passed (135)`, `Tests 6231 passed
(6231)` (at b9731fc; the later commit changes one regex in the test
file, re-run on its own: 47 passed).
- `pnpm --filter @objectstack/lint run typecheck` (tsc --noEmit plus
`check:test-typecheck`): OK. `pnpm --filter @objectstack/lint run
build`: success, `check-dts-emitted: 6/6`. In the built `dist/index.js`
and `dist/index.cjs`: new clause 1, old clause 0, control string 1.
`validateApprovalApprovers` called from the built `dist/index.cjs` on a
manager-only flow returns one `info` finding whose hint carries the new
text.
- Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 62 commands from this diff at head
d63e3f6 (identical to the dispatch-time list); all 62 run on that
head, every one exit 0, reconciled with `--ran`: `62 derived, 62 run, 0
NOT-MEASURED, 0 UNRUN`. Two ratchet gates (`check:type-check-debt`,
`check:query-options-erasure`) hit this box's own 240 s runner cap under
load 17 on the first pass and passed on re-run (`re-measured in 522.7s,
26 raw tsc error(s) total, none above its recorded number`; `ratchet
holds`).
- Narrowed `eslint --no-inline-config --format json` on the two changed
files: 2 files, 0 errors, 0 warnings. The repo-wide `pnpm lint` is CI's.
Invariance: `eslint.config.mjs` never enables type-aware linting (no
`parserOptions.project`, line 328), so this diff cannot move the verdict
of a file it did not touch.
- Control-character scan over the three files: none.
## Acceptance notes
- Not done: AGENTS.md section 10's "pull main and run the full suite
once". `origin/main` moved to d8830c2 during the run; its only
difference from the base on `packages/lint` and `.changeset` is an
unrelated changeset, so this branch was not merged forward. The merge
queue validates the merged generation.
- Not run locally, CI's: the workspace type-check lanes, the sharded
`Test Core`, `Build Core`, dogfood and temporal jobs, repo-wide `pnpm
lint`.
- The `idp_provisioned` clause now says the import's column is refused
too. That is the import's `applyUserManagerLink` delegation (covered by
`admin-import-users-manager-pass.test.ts`, "directory-owned identity"),
not a new claim about the endpoint.
- No `rule-explanations.ts`, `content/docs` or `skills/` edits.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01S3aAf11JjbW1mSGL1EhfFj)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2fbe1fd commit 9f15939
3 files changed
Lines changed: 69 additions & 15 deletions
File tree
- .changeset
- packages/lint/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
267 | 267 | | |
268 | 268 | | |
269 | 269 | | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
270 | 274 | | |
271 | 275 | | |
272 | 276 | | |
| |||
306 | 310 | | |
307 | 311 | | |
308 | 312 | | |
309 | | - | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
310 | 334 | | |
311 | 335 | | |
312 | 336 | | |
313 | | - | |
314 | 337 | | |
315 | 338 | | |
316 | 339 | | |
317 | 340 | | |
318 | | - | |
319 | | - | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
320 | 344 | | |
321 | 345 | | |
| 346 | + | |
322 | 347 | | |
323 | 348 | | |
324 | 349 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
144 | 156 | | |
145 | 157 | | |
146 | 158 | | |
| |||
182 | 194 | | |
183 | 195 | | |
184 | 196 | | |
185 | | - | |
| 197 | + | |
| 198 | + | |
186 | 199 | | |
187 | 200 | | |
188 | 201 | | |
| |||
192 | 205 | | |
193 | 206 | | |
194 | 207 | | |
195 | | - | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
196 | 214 | | |
197 | 215 | | |
198 | | - | |
199 | | - | |
200 | | - | |
201 | | - | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
202 | 220 | | |
203 | 221 | | |
204 | 222 | | |
| |||
0 commit comments