You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a94f3ba
Browse filesBrowse the repository at this point in the historyBrowse files
fix(objectql): refusals, log lines and metadata text state each decision in words instead of a tracker number (stage 3) (#20848)
Part of #20513
Clause-②: no
**Stage 3 of 5 of this lane (`objectql`), under the maintainer's A / A
ruling on the card.** The card stays open for stages 4-5, so this PR
carries no closing keyword. Text only: no error `code`, field name, HTTP
status, export or control flow moves. Every changed source line is a
string-literal line, except two single-line log calls
(`port.warn?.(...)` in the dangling-reference audit and
`ctx.logger.info(...)` in `plugin.ts`) whose only changed token is the
literal; stripping every string literal from the removed and the added
lines leaves the same code skeleton apart from `+` joins for re-wrapped
literals.
## What this does
The query engine's refusals, metadata text and log lines sent the reader
to a tracker number for the reason behind them. Each rewritten string
now says that reason in words (form D, as the migration-entry rewrite
and stages 1 and 2 applied it). Where the sentence already stated what
was decided, only the citation goes. Where it did not, the decision is
added in words:
| Where | Cited | The sentence now says |
|---|---|---|
| `engine.ts` bulk update and bulk delete row-scoping refusals (thrown,
`[Security]`) | 2982 | The missing seed is the AST seeded before the
middleware chain, the one RLS and sharing compose their row-scoping
onto, so a bulk write reaches only the rows this caller may edit. |
| `hook-target-rebind-errors.ts` by-id REBOUND branch (thrown) | 6752 |
`delete()` used to honour a rebind by re-resolving the new target; that
is retired too, because a handler that silently redirects which row gets
deleted is a trap. |
| `hook-target-rebind-errors.ts` unscoped-multi branch (thrown) | 9719,
9974 | The whole-operation dispatch goes to a shape guard registered
with `dispatchUnscopedMultiWrite`, on update and delete alike. |
| `engine.ts` non-atomic cascade warning (`warn`) | 7413 | The cascade
runs unwrapped, as every cascade did before a single-datasource cascade
was made one transaction. |
| `engine.ts` system-ledger write inside a transaction (`debug`) | 5351
| The ADR-0057 section 3.6 system ledger is the one class carved out of
the cross-datasource write refusal. |
| `integrity/dangling-reference-audit.ts` summary (`warn`) | 4551 |
Findings are reported, never rewritten: a system-context write is exempt
from the write-time reference check, so this audit is where such a
reference surfaces. |
| `registry.ts` legacy `apiMethods` warning (`warn`) | 3543 | The
authorable values are now the six primitives only, because every other
operation is derived from them or retired. |
| `validation/rule-validator.ts` predicate and when-predicate evaluation
failures (`warn`) | 4649 | Write rejected: a rule that cannot be
evaluated fails closed, it is never skipped. |
| everything else: the unknown-option, filter-array (two),
credential-aggregation, HAVING-operator, empty-hook-target, hook-target
CLEARED, strict read-only (two clauses) and system-write organization
refusals; the lifecycle `retention_overrides` setting description and
the search companion field description (metadata text); the eight
ADR-0104 value-shape gate lines; the delegated protocol-assembly line;
the read-only and runtime-owned strip warnings (eight clauses) | 4371,
5158, 3171, 7922, 4286, 4001, 5574, 5846, 3407, 3493, 8844, 5195, 2486,
3617, 3438, 4797, 4769, 2462, 5126, 5503, 2948 | The sentence already
said what was decided; only the citation goes. Where an ADR stood beside
the number (ADR-0100, ADR-0078, ADR-0104, ADR-0076 Step 2), the ADR
stays. |
Each claim was checked against today's code, not only against the cited
card: the bulk-write AST is seeded before `executeWithMiddleware` on
both verbs; `planCascadeAtomicity` returns `'atomic'` for a
single-datasource cascade and `delete()` then runs it inside
`transaction()`; a cross-datasource business write throws
`CrossDatasourceTransactionWriteError` while a system-ledger object runs
outside the transaction; the write-path reference check is non-system
writes only; `LEGACY_API_METHODS` holds the eight derived or retired
values; `dispatchUnscopedMultiWrite` is a registration option valid on
`beforeUpdate` / `beforeDelete`; an unevaluable rule returns
`unevaluableRuleError`. All 31 cited cards read closed as completed.
## One string held for a later stage
`engine.ts`'s `findOne` no-predicate refusal keeps its citation (4419, 1
occurrence). `@objectstack/metadata-core`'s
`engineFindOnePredicateRefusalMessage` is documented as byte-identical
to it, and this package's `engine-findone-predicate.test.ts` compares
the two (strict equality and `toThrow`). Moving the metadata-core copy
is another package's ledger row, which this stage may not touch. A
one-off ablation proves the hold: dropping the citation in `engine.ts`
alone turns 9 of 24 tests in that file red. Stage 5 (the other seven
packages, `metadata-core` among them) rewrites the pair together, and
its ledger diff will move this `objectql` row too.
## Order inside the stage
All 39 rewritten literals (42 occurrences) fit one PR, under the stop
line, so the stage lands whole in three ordered commits, each
recomputing the ledger so every commit is green on
`check:doc-authoring`:
1. `3432973ff` author-visible text: 16 literals (19 occurrences), the
thrown refusals and the two metadata texts, plus the one byte-exact
re-pin;
2. `bccd37a25` log lines: 23 literals (23 occurrences), plus the two
re-pinned tests;
3. `26848968c` the changeset.
`objectql` has no ledgered `src/`-shipped test string: the census's 3
test-facing strings sit in `engine-data-events.bench.ts`, which the
ledger excludes.
## Pins re-pinned: 6 assertion lines in 3 test files
- `integrity/dangling-reference-audit.test.ts` 377, 498, 715, 959 found
the summary warning by the number. They now find it by "reported, never
rewritten".
- `registry.test.ts` 1201 asserted the number in the legacy `apiMethods`
warning. It now asserts "derived from them or retired".
- `engine-dropped-fields-primary-key.test.ts` 318 is the byte-exact pin
on the strict read-only refusal; it moves with the text and stays
byte-exact.
A one-off mutation proves each moved pin can fail, run on the committed
head `26848968cc` with `scripts/ablation-replace.mjs` in wrap mode
(anchor hit once, disk-verified) under a shell trap that restores each
file from `HEAD`. The tests import `src` directly, so no build leg
applies. "reported, never rewritten" to "reported, never repaired": 4
failed / 35 passed. "derived from them or retired" to "derived from them
or dropped": 1 failed / 100 passed. "onFieldsDropped instead." to
"onFieldsDropped instead!": 1 failed / 15 passed. After each leg the
blob equals `HEAD` and `git diff HEAD` is empty; after the run `git
status --porcelain` has 0 lines.
No consumer outside the package pins a changed string. Every fragment of
every removed source line was searched in all test files of the
repository: the hits are comments, fragments the new text keeps, the
package's own tests above, and `plugin-security`'s
`auto-org-admin-grant.test.ts`, whose test double keeps its own copy of
the unknown-option sentence and is never compared with the engine's (see
Acceptance notes).
## Ledger burn-down
`scripts/doc-authoring-prose-id.baseline.json` was regenerated with
`--census-ledger`. Only `objectql` rows move; no other package's row
changes.
| File | Before | After |
|---|---|---|
| `src/engine.ts` | 18 | 1 (4419, held) |
| `src/validation/rule-validator.ts` | 10 | 0 |
| `src/hook-target-rebind-errors.ts` | 5 | 0 |
| `src/readonly-strict-errors.ts` | 2 | 0 |
| `src/tenancy/system-write-organization.ts` | 1 | 0 |
| `src/search-companion.ts` | 1 | 0 |
| `src/registry.ts` | 1 | 0 |
| `src/plugin.ts` | 1 | 0 |
| `src/lifecycle/lifecycle-settings.ts` | 1 | 0 |
| `src/integrity/dangling-reference-audit.ts` | 1 | 0 |
| `src/hook-binder.ts` | 1 | 0 |
| `src/having-filter.ts` | 1 | 0 |
| **objectql** | **43 in 12 files** | **1 in 1 file** |
| whole ledger | 811 occurrences, 546 pairs, 215 files | 769
occurrences, 514 pairs, 204 files |
The census's 38 messages for `objectql` are the 40 ledgered literals
minus the two metadata texts it bucketed separately; the 40 literals
carry 43 occurrences because three of them cite two numbers each.
## Verification (head `26848968cc`)
- Build: `turbo run build` over `@objectstack/objectql` and its closure,
14/14; then the whole workspace (`./packages/*`, `./packages/*/*`),
71/71; then `@objectstack/objectql` directly after the ablation run
touched its sources. The new sentences are in `dist/index.js`, and none
of the removed citations remains in a string there (the matches left are
comments).
- `@objectstack/objectql` tests (`vitest run --project local
--maxWorkers=2`, three shards): 115 + 115 + 114 files passed, 2253 +
2001 + 2515 tests passed, 0 failed.
- `@objectstack/objectql` typecheck: exit 0 (`tsc --noEmit`, the scripts
config, and `check:test-typecheck` holding its ledger).
- `node scripts/pm/dispatch-gates.mjs --commands`: 76 derived commands,
all run, all exit 0. `check:dual-build-cjs-loads` and
`check:type-check-debt` first answered exit 3 (prerequisite not met) and
were re-run after the full build and the direct `objectql` rebuild;
`check:dts-closure` and `check:lean-entry-closure` were re-run there
too. `--ran`: 76 derived, 76 run, 0 NOT-MEASURED, 0 UNRUN.
- `check:doc-authoring`: sibling-package prose ids hold the baseline, no
growth, no burn-down unrecorded (647 pinned sites across 204 files).
- Narrowed lint: `eslint --no-inline-config --format json` over the 15
touched `.ts` files: 15 files, 0 errors, 0 warnings. The resolved
`parserOptions` for `engine.ts` are `ecmaVersion: latest` and
`sourceType: module` only, with no `project` and no `projectService`, so
no type-aware rule can move an untouched file. Repo-wide `pnpm lint` is
CI's.
- Not measured locally (CI's): the `repo` vitest project's one file
(`action-owner-key-single-source.test.ts`, untouched by this diff), the
Test Core shards, Dogfood, and the workspace type-check lanes.
## Acceptance notes
- **Held for stage 5:** the `findOne` refusal pair (`objectql`
`engine.ts` and `metadata-core` `engine-findone-predicate.ts`), as
above. Stage 5's file surface needs `packages/objectql/src/engine.ts` as
well.
- **Noted, not filed:** `plugin-security`'s
`auto-org-admin-grant.test.ts` carries a test double of the engine's
unknown-option refusal with its own copy of the sentence, citation
included. It is a test file, outside the ledger and outside the ruling's
shipped-`src/` scope, and no test compares it with the engine's text, so
the two now differ by the citation only. Carrier: none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
port.warn?.('[integrity] stored references that resolve to nothing (#4551)',{
736
+
port.warn?.('[integrity] stored references that resolve to nothing — reported, never rewritten: a system-context write is exempt from the write-time reference check, so this audit is where such a reference surfaces',{
0 commit comments