Repository navigation
Commit 5050442
fix(objectql,plugin-security): an update's organization_id re-point the Layer 0 wall admits is stored as sent (#25094)
Fixes #24822
Clause-②: yes (widening) — an update re-point of `organization_id` the
Layer 0 wall admits is now stored instead of silently dropped, and an
in-process `strictReadonlyWrites: true` update naming an organization
the wall admits is now stored instead of refused
`ERR_READONLY_FIELD_REJECTED`.
This is half 2 of the card: UPDATE. Half 1 (insert) landed as PR #25048
(`2b1382a5b3`). This half reuses its member,
`PostHookWriteImageCheck.judgesOrganization`, and its F4 provenance
rule, through one helper shared by both write verbs. The card's last
half, so this PR closes it.
## What was wrong
Under `group`, take a member whose active organization is A and whose
membership set includes C. It updates a row of an app object, which
carries the platform-injected tenant column, naming `organization_id:
C`.
- **Answer:** 2xx, and the row stayed in A, by id and by predicate
alike.
- **Mechanism:**
- The Layer 0 write wall (plugin-security step 3.7) judged C and
admitted it: on the payload as sent, and on the stored image (by id the
prior row merged with the final payload; by predicate every matched row
merged with it).
- The engine's static-`readonly` update strip then took the value,
because `TENANT_SCOPE_FIELD_DEF` declares `readonly: true`, and the row
kept its own organization.
- **Visibility:** a `droppedFields` `readonly` entry and a WARN;
`beforeUpdate` hooks were not shown the value.
- **The inconsistent half.** An object that declares its own writable
`organization_id` stored the same re-point, by id and by predicate
(premise U2, measured below), so honouring it on the injected column is
a fix, not a new capability.
The governing text is the organizations runtime's Middleware A comment:
a supplied value "goes on to the Layer 0 write wall … the same wall an
UPDATE that re-points `organization_id` meets, and gets the same answer:
admitted where the caller's organization scope … admits it, otherwise
refused `403 PERMISSION_DENIED`". The seat call `6305891812` carried the
UPDATE half on this card.
## What changed
- **`packages/objectql/src/engine.ts`.**
- `staticReadonlySparesOrganization(schema, wallJudgesOrganization)`,
new: the ONE answer both write verbs read. It spares the column only
when the wall's seam declares the member, the object is one the INSERT
strip judges (`staticReadonlyInsertSubject` holds the column: never
`sys_`, never a platform-internal `managedBy` bucket), and the column's
provenance is not `'author'` (F4).
- `insertStaticReadonlySubject` now reads it. Its behaviour is unchanged
(half 1's pins are green, and ablation B1-F4 turns its F4 pin red
through the shared helper).
- `updateStaticReadonlySubject(schema, wallJudgesOrganization)`, new:
the update strip's schema view, without `organization_id` where the
helper spares it; `schema` itself otherwise.
- In `update()`, `wallJudgesOrganization` is read ONCE, inside the
middleware chain's final handler (`!isSystem` and the seam's member `===
true`), and `readonlyUpdateSubject` is built once from it. Every
static-`readonly` pass reads that one view: the pre-hook hide pass (what
`beforeUpdate` is shown), the by-id strip and the predicate strip (what
is stored).
- `staticReadonlyStoredView` / `staticReadonlyStripTakes` (the views the
`readonlyWhen` strips and the master-detail settlement read) take the
same flag on their descriptor and apply the same helper, so a
`readonlyWhen` predicate reading `record.organization_id` reads the
organization the row is stored in.
- The `PostHookWriteImageCheck.judgesOrganization` doc now covers
updates. No member is added.
- `validate()` is unchanged.
- **`packages/plugins/plugin-security/src/security-plugin.ts`.**
- Step 3.7's setter: the `operation === 'insert'` conjunct is replaced
by `operation === 'insert' || (operation === 'update' &&
!Array.isArray(data))`, still ANDed with `tenantParts.length > 0`. The
array clause restates the enclosing condition on purpose: the member is
the seam's own claim about what it judges.
- The private `WriteImageCheckSeam` doc, the setter's comment, and step
3.7's "effectively immutable" paragraph are rewritten to state the
stored re-point (seat ruling 6).
- **Tests:**
- `objectql`: `engine-update-wall-judged-organization.test.ts` (new,
stand-in installer), and census rows in
`federated-injected-column-readers.test.ts` for the shared helper.
- `plugin-security`: `update-seam-judges-organization.test.ts` (new,
real ObjectQL + SqlDriver + SecurityPlugin, real grant tables); in
`insert-seam-judges-organization.test.ts` the cell "an update's seam
does not carry the member" flips to the update half's answer;
`tenant-wall-organization-removal.test.ts` header prose only.
- `organizations`: `update-repoint-organization-wall.test.ts` (new, the
real stack half 1 measured on).
- **Changeset:** `.changeset/24822-update-repoint-honoured.md`:
`@objectstack/objectql` minor, `@objectstack/plugin-security` patch.
## Public surface
Every change below is a widening. None admits a `(caller, organization)`
pair the wall does not already admit, and the engine's own gates (the
wall, the strip, the strict flag) refuse nothing they accepted before.
- `PostHookWriteImageCheck.judgesOrganization` (published,
`OperationContext.postHookWriteImageCheck`): its contract now covers
single-payload updates, and `ObjectQL.update` reads it. No new member.
- A walled update's admitted re-point is stored as sent, by id and by
predicate.
- It is no longer reported as dropped: not in `droppedFields`, not
through `onFieldsDropped`, not by the read-only WARN.
- An in-process `strictReadonlyWrites: true` update naming an admitted
organization is stored, where it used to be refused
`ERR_READONLY_FIELD_REJECTED`.
- `beforeUpdate` hooks see the caller's `organization_id` on a walled
update.
- Under `group`, a member with NO active organization re-points within
its membership set the same way (before: taken and reported).
- An on-behalf-of update by a crossing operator (ADR-0090 D10) is held
to the delegator's wall: stored as sent where it admits the re-point
(before: taken), refused where it does not.
- **N2, stated:** outcomes that depend on the stored organization now
follow the admitted value. An organization-scoped unique key, a
validation rule, a `readonlyWhen` / `requiredWhen` predicate and a hook
reading `organization_id` see the organization the row moves to. So a
re-point that collides with an organization-scoped unique key in its new
organization is refused there, exactly as on a declared-column object
today; before, the re-point was dropped and the write reported success.
- Unchanged, by ruling or by measurement: `sys_` and platform-internal
objects, an AUTHORED `readonly: true` `organization_id`, an emptied
value, an array payload, every no-wall path, `preserveAudit`,
`isSystem`, and the wall-blind `update` preview.
## Seam
- **Who sets the member on an update, and when.** Only step 3.7, on the
seam it composes for a single-payload update, and only with the wall's
own parts in it (`tenantParts` non-empty: the caller's Layer 0 and the
ADR-0090 D10 delegator's). That seam's loop then holds every stored
image's organization to the wall and refuses an emptied one; the payload
half of the same step has already refused every supplied value outside
the wall, and every emptied one, before the engine runs.
- **Left unset:** step 3.6's business-`check`-only update seam (how
`single` gets a seam with no wall); a crossing platform operator's
update (it gets no step 3.7 seam: `tenantParts` is empty and the
no-active-organization arm is insert-only); an array update payload
(step 3.7 composes nothing for it); `isSystem` (the middleware returns
before steps 3.6 and 3.7).
- **What the engine reads.** The member, once, and nothing else. It
never derives the answer from the posture or the context: that would be
a mirror of the wall, wider than the wall wherever the wall is not
mounted (half 1's measured P5). `tenantLayer0Verdict` is untouched.
## Boundary statement
The set of `(caller, organization)` pairs an update can move a row into
is the set the Layer 0 wall admits, before and after. A, C and D are
organizations: A is the active one and the row's own, C is in the
membership set, D is outside it.
- **Stacks.** Rows marked (org) are ObjectQL + SqliteWasmDriver + the
real `OrganizationsPlugin` + the real `SecurityPlugin`, the stack half 1
used. Rows marked (sec) are ObjectQL + SqlDriver + `SecurityPlugin` with
the real grant tables and a delegator rebuilt from stored `sys_user`,
`sys_member` and `sys_user_permission_set` rows.
- **Before** is measured twice: by a premise probe on base `2b1382a5b`,
and by the final pins with `main`'s two source files (`c67f244f5`)
restored over the tree (tree only; restored to blob == HEAD after).
**After** is the probe at `22e257dfe` and the pins at the final head.
| posture · caller | update on the injected column | before | after |
|:--|:--|:--|:--|
| `group` member (org) | re-point A→C, by id | 2xx, row stays **A**,
`droppedFields` readonly + WARN, hook sees none | 2xx, row moves to
**C**, nothing reported, hook sees C |
| `group` member (org) | re-point A→C, by predicate | 2xx, the matched
row stays **A**, reported + WARN | 2xx, the matched row moves to **C**,
nothing reported |
| `group` member (org) | re-point to D, by id / by predicate | 403
`PERMISSION_DENIED` | 403 `PERMISSION_DENIED` |
| `group` member (org) | names A (its own), by id | stays A, reported +
WARN | stays A, nothing reported |
| `group` member, `strictReadonlyWrites` (org, in process) | re-point to
C, by id / by predicate | `ERR_READONLY_FIELD_REJECTED` | stored C |
| `group` member with NO active organization (org) | re-point to C / to
D | C: stays A, reported; D: 403 | C: stored C; D: 403 |
| `isolated` member (org) | names A, by id / by predicate | stays A,
reported + WARN | stays A, nothing reported |
| `isolated` member (org) | re-point to C, by id / by predicate | 403 |
403 |
| `group` / `isolated` member (org) | emptied (`null`, `''`), by id / by
predicate | 403 (#22278) | 403 (#22278), nothing stored |
| `group` member (org, sec) | ARRAY payload | refused, no step 3.7 seam
| refused, no step 3.7 seam |
| `group` crossing operator for a delegator holding {A, C} (sec) |
re-point to C, by id / by predicate | stays A, reported | stored C |
| same (sec) | re-point to D | 403 (the delegator's wall) | 403 (the
delegator's wall) |
| `isolated` crossing operator for a delegator (sec) | names A /
re-point to C | A: stays A, reported; C: 403 | A: nothing reported; C:
403 |
| `group` member, AUTHORED `readonly: true` `organization_id` (org, F4)
| re-point to C, by id / by predicate | stays A, reported + WARN; strict
refuses | unchanged (the seam now declares the member; the author's
declaration keeps the strip) |
| `group` member, `sys_` object on the injected column (sec) | re-point
to C, by id / by predicate | stays A, reported; strict refuses |
unchanged (the seam declares the member; the engine keeps the strip) |
| `group` member, a `managedBy: 'system-data'` app object (sec probe) |
re-point to C | stays A, reported | stored C (an app object the insert
strip judges, as on insert) |
- **What the wall admits is unchanged:** `group` {A, C}, `isolated` {A},
a delegated update the delegator's own set. B2-WALL shows the refusals
are the wall's own.
- **Through an explicit re-point on the injected column of an app
object:** `group` goes from {A} to {A, C}, the wall's set; `isolated`
stays {A}.
- **Through a declared-column object, already {A, C} under `group`
before this change** (U2, the control cell in the organizations file).
- **No pair becomes writable that the wall does not admit.**
Unchanged before and after, measured at base and pinned at the head; on
each the re-point is taken, reported and refused under strict, or
refused earlier, as before:
| path | re-point | stored | seam |
|:--|:--|:--|:--|
| `single`, no organizations runtime, by id / by predicate | C | A,
reported | none |
| `single` with a business update `check`, by id / by predicate | C | A,
reported | installed, member unset |
| `single`, `strictReadonlyWrites` | C | refused
`ERR_READONLY_FIELD_REJECTED` | none |
| `group` / `isolated`, security plugin absent, by id / by predicate | C
| A, reported | none |
| platform operator crossing on a private object, `group` / `isolated`,
by id / by predicate | D | A, reported | none |
| `tenancy.enabled: false` object, authored read-only `organization_id`
| C | A, reported | none |
| `single`, `preserveAudit: true` | C | A, reported | none |
| system context, by id / by predicate | D | as sent | none |
| `sys_user_position` / `sys_user_permission_set`, a member | C |
refused 403 by the RBAC administration gate (ADR-0090 D12) | none |
| `sys_user_position` / `sys_user_permission_set`, a platform
administrator (walled there) | C (grantee a member of C) / D | C: stored
as sent (the column is declared WRITABLE; the strip never took it); D:
403 | installed |
| `managedBy: 'engine-owned'` / `'append-only'` object (sec probe; the
engine-level cell is pinned in oql) | C | refused 403 by the ADR-0103
engine-owned guard | none |
| a by-id update of a row outside the scope (org, `group`) | C | refused
`404 RECORD_NOT_FOUND` (step 2.7, #21771) | — |
| a falsy payload id beside `where.id` (org, `group`) | C | refused 403
(step 2.7) | — |
## Must-not-regress
Each point of both contract reviews' ③ lists for half 2, with its pin
and the ablation that turns that pin red (the Ablations table below has
the counts).
From `6308267963` ③:
1. **The setter stays on non-empty `tenantParts`; never on step 3.6's
check seam or the crossing operator's seam; the `insert` conjunct
replaced deliberately.** The setter ANDs `tenantParts.length > 0` with
`insert || (update && !Array.isArray(data))`. Pins: sec "`single` with a
business `check`: … UNSET", org "`single` with a business update
`check`, by id / by predicate" (B2-SET1b red); sec and org
operator-crossing cells, NO SEAM; the positive control B2-SETOFF.
2. **No wall seam for an ARRAY update payload, so no spare there.**
Pins: org and sec array cells (B2-ARR1 red). Removing the setter's own
array clause alone is an equivalent mutant (B2-ARR2, all green): the
enclosing condition never reaches the composition for an array update.
3. **#22278 on both halves, and the payload-half refusal of D.** Pins:
the org `[#22278]` block, eight cells (B2-E22278 red); the org D cells
and sec D cells (B2-WALL red).
`tenant-wall-organization-removal.test.ts` stays green in the full
suite.
4. **One read for the by-id and predicate seams, so the hook view and
the stored row agree; `isSystem` and update-mode `validate()` unchanged;
the census row.** One `wallJudgesOrganization` read, one
`readonlyUpdateSubject`. Pins: org "shown to beforeUpdate" by id / by
predicate and oql "SET, by id" (B1-HIDE red); oql `readonlyWhen` cell
(B1-VIEW red); system-context cells in all three files; the preview
cells in org and oql; census rows. The `!isSystem` conjunct is an
equivalent mutant (the strips never run for a system caller).
5. **The `honoured` fail-closed guard.** Untouched; its pin
`tenant-wall-post-hook-image.test.ts` "a host that never runs the
installed wall judgement …", both drivers (B2-HON red).
6. **Step 3.7's "effectively immutable" comment.** Rewritten.
From `6309495055` ③:
1. **Where the member is set: only where step 3.7 composes the wall's
parts into the by-id or predicate seam; never step 3.6's update seam, an
array payload, or `isSystem`.** As points 1, 2 and 4 above; sec "a
system context installs no seam".
2. **#22278: emptied refused, no stamp refills it; F3 does not carry
across.** The org `[#22278]` block (B2-E22278 red: with the gate off,
the spare stores the emptied value).
3. **F4: an authored `readonly: true` `organization_id` keeps the update
strip.** Org F4 by id / by predicate, oql "SET, but an AUTHORED …"
(B1-F4 red, which also turns half 1's insert F4 pins red through the
shared helper).
4. **`sys_` objects: measure and rule.** Measured as premise U3, ruled
by the seat (ruling 1: the update spare covers exactly the objects the
insert spare covers). Pins: oql `sys_` and `engine-owned` cells, sec
`sys_` cell (B1-SYS red). The grant tables declare a WRITABLE
`organization_id`, so the strip never took a re-point there: their cells
are controls, measured identical before and after (the before run with
`main`'s sources passes them), and no mutation of the spare can reach
them.
5. **The existing gates: the by-id falsy-id refusal (#19989), the step
2.7 pre-image selection, the predicate seam's judgement of every matched
row.** Org falsy-id cell (B2-PRE27 red); org out-of-scope row cell
(B2-PRE27P red: it needs step 2.7 AND the engine's scoped prior read
off, two independent gates); oql "SET, by predicate … the seam judges
every one" (B1-PRED red).
6. **`preserveAudit`'s update-only exemption must not widen to
`organization_id`.** Org `preserveAudit` cell, oql "preserveAudit does
not spare it" x3 (B1-PA2 red).
7. **One helper, and the preview.** `staticReadonlySparesOrganization`
is shared by insert and update. The preview: see Acceptance notes.
## Pins
- **`organizations/src/update-repoint-organization-wall.test.ts`** (real
stack; an innermost probe middleware records each update's seam and the
organizations it judged): every row of both tables above that is marked
(org), as `group` / `isolated`, by id and by predicate.
- **`plugin-security/src/update-seam-judges-organization.test.ts`**: the
member SET on a walled update (`isolated`, `group` by id and by
predicate, composed with a business `check`); UNSET on `single`'s check
seam; NO SEAM for a crossing operator, a system context and an array
payload; the `sys_` scope (a `sys_` object, both grant tables); the
delegated update under `group` and `isolated`.
- **`objectql/src/engine-update-wall-judged-organization.test.ts`**
(stand-in installer): with the member SET, by id and by predicate, the
re-point is stored, shown to `beforeUpdate`, handed to the seam on every
stored image, not reported, not refused under strict; `created_by` is
still taken; an AUTHORED column, a `sys_` object and an `engine-owned`
bucket keep the strip; a `readonlyWhen` lock reads the stored
organization. With the member absent, `false`, or no seam: taken,
withheld, reported, WARNed, refused under strict, and `preserveAudit`
does not spare it. A system context is unchanged. The update preview
still reports the drop.
## Ablations
Every leg went through `node scripts/ablation-replace.mjs` (WRAP mode)
inside a script carrying its own `trap … EXIT INT TERM` restore against
the absolute path, with the restore proven by blob == HEAD and an empty
`git diff HEAD`. Each ran the six pin files (org 88, sec 28, oql 42
cases), and each predicted direction was written down before the run.
objectql, plugin-security and driver-sqlite-wasm / driver-sql are vitest
source aliases in these suites, so there is no `dist/` leg.
| id | mutation | predicted red | observed (org / sec / oql failed) |
|:--|:--|:--|:--|
| B1-A4u | the update spares without the member (flag = `!isSystem`) |
every no-wall update cell | 14 / 2 / 12 |
| B1-A6u | the update ignores the member (positive control) | every
stored-as-sent update cell | 9 / 4 / 5 |
| B1-SYS | the spare ignores the insert subject's `sys_` / bucket
exclusions | the `sys_` and `engine-owned` cells only | 0 / 1 / 2 |
| B1-F4 | the provenance narrowing off | the F4 cells only, insert and
update | 3 / 0 / 2 |
| B1-VIEW | the stored view loses the flag | the `readonlyWhen` cell
only | 0 / 0 / 1 |
| B1-HIDE | the hide pass reads the whole schema | the "shown to
beforeUpdate" cells only | 2 / 0 / 1 |
| B1-PRED | the predicate seam judges only the first matched row | the
every-matched-row cell only | 0 / 0 / 1 |
| B1-PA2 | `preserveAudit`'s exemption widened to `organization_id` |
the `preserveAudit` cells | 1 / 0 / 4 (the 4th is the census test, which
sees the mutation's own `'organization_id'` literal in
`rule-validator.ts`) |
| B2-SET1b | step 3.6's update check seam declares the member | the
`single` + check cells | 2 / 1 / 0 |
| B2-SETOFF | step 3.7's update arm off (insert only; positive control)
| every stored-as-sent update cell and every update sighting | 11 / 7 /
0 |
| B2-ARR1 | step 3.7 composes for an array update too | the array cells
(sighting) | 1 / 1 / 0 |
| B2-ARR2 | the setter's own array clause removed alone | none:
equivalent mutant | 0 / 0 / 0 |
| B2-E22278 | `emptiesOrganization` always false | the eight `[#22278]`
cells | 8 / 0 / 0 |
| B2-WALL | `clearsWall` admits every row | every refusal outside the
scope, insert and update | 16 / 7 / 0 |
| B2-PRE27 | step 2.7's pre-image check skipped | the falsy-id cell (and
the out-of-scope cell, unless another gate holds it) | 1 / 0 / 0: only
the falsy-id cell; the engine's own scoped prior read still answered 404
|
| B2-PRE27P | B2-PRE27 plus the engine's prior read unscoped | the
falsy-id and out-of-scope cells | 2 / 0 / 0 |
| B2-HON | the `honoured` fail-closed guard off (run on
`tenant-wall-post-hook-image.test.ts` + the sec update file) | the
fail-closed cell, both drivers | sec 2 / 48 |
Two first attempts were no-ops that `ablation-replace` refused before
running anything (exit 1, "the anchor count moved 1 -> 1"): B1-PA and
B2-SET1, whose replacements still contained their anchors. Their re-runs
are B1-PA2 and B2-SET1b.
## Tests and gates (final head `784b1f9f3`)
- **Premises, measured before any edit** (temporary probe files in
`organizations/src` and `plugin-security/src`, run under the verify lock
and deleted, never committed; base `2b1382a5b`): U1 true (by id and by
predicate: 2xx, row stays A, `droppedFields` readonly + 1 WARN; D
refused 403). U2 true (the declared-column object stores C by id and by
predicate, the seam judging C; D refused 403). U3 measured (the update
strip runs on `sys_` objects and step 3.7 composes its wall there; the
grant tables declare a writable column; a member's update of them meets
the RBAC administration gate; `engine-owned` / `append-only` objects
meet the ADR-0103 guard). U4 true. U5 measured: every no-wall path takes
the re-point.
- **Suites** (one lock run, each exit captured before any pipe; `VERDICT
command-exit 0`):
- `objectql` (`vitest run --project local`): 458 files, 8610 passed.
- `plugin-security`: 205 files, 4193 passed, 45 skipped.
- `organizations`: 15 files, 233 passed.
- **Typecheck:** `typecheck` exits 0 for all three, and
`check:test-typecheck` is OK for each. `objectql`'s ledger is unchanged
at 39 files / 233 errors / 64 pinned signatures; no signature was added.
- **`@objectstack/spec` `check:generated`:** exit 0 (`packages/spec`
moved on `main`'s side of the merge).
- **Gates:** `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, no paths, derived 76 commands on
`784b1f9f3`. All 76 exit 0, each exit captured before any pipe, after a
full `turbo run build` of `./packages/*` and `./packages/*/*` (75
tasks). `--ran` reads "76 derived, 76 run, 0 NOT-MEASURED, 0 UNRUN" and
exits 0. That includes `check-engine-split-ratio` (98.6%; the shallow
clone's oldest visible commit predates the window),
`check:dual-build-cjs-loads`, `check:type-check-debt` and `check:i18n`.
- **`origin/main`:** merged twice before opening (`c67f244f5`, then
`f46ef4d70`, which brought #25066's `security-plugin.ts` region; no
conflict). Every number above is on the second merge. `main` has since
moved to `4feccc268` (#25076, #25081, #25080, #25064: driver-sql,
platform-objects, service-messaging, PM tooling), none sharing a file
with this PR.
- **CI:** not yet read; this PR is opened as a draft.
## Acceptance notes
- **The `update`-mode `validate()` preview is wall-blind** (seat ruling
7). It runs no middleware, so it holds no seam. After this change, a
`group` update preview naming C still reports `droppedFields:
organization_id readonly` while the write stores C; a preview naming D
answers the same drop while the write answers 403 (before and after).
Pinned in the org and oql files. #25062 carries the preview, insert and
update alike; this PR does not change it.
- **`sys_` objects on the injected column keep the update strip, by seat
ruling 1.** A source scan of this tree lists the `sys_` objects that
declare no `organization_id` of their own, and so carry the injected one
wherever they are tenant-scoped: `sys_attachment`, `sys_comment`,
`sys_comment_reaction`, `sys_business_unit_member` (`platform`),
`sys_email_template`, `sys_webhook` (`config`), `sys_user_preference`,
`sys_notification_template`, `sys_notification_preference`
(`system-data`), `sys_file`, `sys_upload_session`, `sys_inbox_message`.
Where the wall applies to one of them, a re-point is still taken and
reported, exactly as an insert's organization there is (pinned on a
`sys_` object in the sec file); the seam declares the member there
without effect.
- **An array update payload beside `where.id`** reaches the driver and
fails with a raw SQL error (`no such column: 0`), before and after this
change; measured in process only, no public door measured. Observation,
not filed (carrier: none).
- **N1 (half 1's review), not in this claim:** the insert-side comments
in step 3.7's ADR-0123 D2 arm ("the column is read-only to a session
payload") and the engine's insert post-image comment, and ADR-0123
amendment item 1, which is the maintainer's pointer.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent d0769bf commit 5050442
9 files changed
Lines changed: 1662 additions & 85 deletions
File tree
- .changeset
- packages
- objectql/src
- plugins
- organizations/src
- plugin-security/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
0 commit comments