diff --git a/.changeset/20595-objectql-provenance-anchors.md b/.changeset/20595-objectql-provenance-anchors.md new file mode 100644 index 00000000000..28d27fce775 --- /dev/null +++ b/.changeset/20595-objectql-provenance-anchors.md @@ -0,0 +1,16 @@ +--- +'@objectstack/objectql': patch +--- + +Provenance comments in `@objectstack/objectql` cite the commits and ADRs that decided them, not tracker numbers that no longer resolve + +Clause-②: no + +Docblocks and comments across the package cited issue-tracker numbers that now answer 404 on GitHub. +Each one now cites the commit in this repository's history that made the decision it describes, or the +ADR that records it (ADR-0029 D9.2a, ADR-0104's 2026-09-05 addendum, ADR-0126 §7.2, ADR-0130 D3). +Some of these docblocks sit on exported members, so the reworded text appears in the published +`index.d.ts` / `index.d.mts`, `core.d.ts` / `core.d.mts` and the shared type chunk, and comments that +esbuild keeps appear in the JavaScript output. + +Comment only: no export, type, error code, status, message text or runtime behaviour changes. diff --git a/packages/objectql/src/action-activation.test.ts b/packages/objectql/src/action-activation.test.ts index 4234a40ce91..19147605586 100644 --- a/packages/objectql/src/action-activation.test.ts +++ b/packages/objectql/src/action-activation.test.ts @@ -20,7 +20,7 @@ // would switch off an entire installation's actions on its first boot. // 4. **The write is durable BEFORE it is local.** A store that throws must // leave the projection untouched, or the engine reports an activation state -// the ledger does not carry — the #10243 shape with persistence bolted on, +// the ledger does not carry — the env-wide toggle leak's shape with persistence bolted on, // which ADR-0126 §7.2 exists to remove. // 5. **Survives re-registration**, which is the in-process half of "survives a // restart": `resyncAuthoredActions` re-registers handlers on every diff --git a/packages/objectql/src/action-activation.ts b/packages/objectql/src/action-activation.ts index 851cfe2ee1a..1eb59976a8a 100644 --- a/packages/objectql/src/action-activation.ts +++ b/packages/objectql/src/action-activation.ts @@ -182,7 +182,7 @@ export class ObjectStoreActionActivationStore extends ObjectStoreMetadataActivat * written from exactly two places — {@link hydrate} (boot, from the ledger) and * {@link setActive} (which writes the durable row FIRST and updates the set only * after that write returns) — so it cannot drift into being an independent, - * process-local off-switch, which is the #10243 mechanism ADR-0126 retires. + * process-local off-switch, which is the env-wide toggle leak's mechanism ADR-0126 §7.2 retires. * * ⚠️ It is deliberately NOT re-read per `metadata:reloaded`: a reload * re-registers HANDLERS, and a re-registered handler must stay disabled. The diff --git a/packages/objectql/src/action-governance-keyed-identity.test.ts b/packages/objectql/src/action-governance-keyed-identity.test.ts index f12ae432703..e002d308c36 100644 --- a/packages/objectql/src/action-governance-keyed-identity.test.ts +++ b/packages/objectql/src/action-governance-keyed-identity.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #14423 — the audit and the router, defined on ONE identity and ONE set of + * Commit a56baa2bd — the audit and the router, defined on ONE identity and ONE set of * sources. * * --------------------------------------------------------------------------- diff --git a/packages/objectql/src/action-governance.ts b/packages/objectql/src/action-governance.ts index 720a6fa15ca..b33652b57e9 100644 --- a/packages/objectql/src/action-governance.ts +++ b/packages/objectql/src/action-governance.ts @@ -45,7 +45,7 @@ * undeclared only when EVERY source the router resolves through answered * nothing for it. * - * [#14423] EXISTENCE is settled now too, on both halves of the D5 bijection + * [commit a56baa2bd] EXISTENCE is settled now too, on both halves of the D5 bijection * and in both of the ways the two sides could disagree: * * - IDENTITY — the metadata plane is read KEYED @@ -264,7 +264,7 @@ export function reconcileActionRegistrations( /** * One declaration the engine can dispatch against. * - * ## [#14423] `storeKey` — the identity a body is not required to carry + * ## [commit a56baa2bd] `storeKey` — the identity a body is not required to carry * * `action` is the declaration BODY, exactly as its source hands it over. * `storeKey` is the key the metadata plane holds that body under, present @@ -317,7 +317,7 @@ export interface GovernanceLogger { * with the object-embedded copy winning, mirroring the execution layer's * artifact-wins rule. * - * ## [#14423] Two spellings for the metadata source, and why the keyed one wins + * ## [commit a56baa2bd] Two spellings for the metadata source, and why the keyed one wins * * `loadStandaloneActionsKeyed` reads the plane under the identity the STORE * holds each row by (`MetadataManager.loadManyKeyed`); `loadStandaloneActions` @@ -336,7 +336,7 @@ export interface GovernanceLogger { * So when the keyed source is present it REPLACES the unkeyed one — they read * the same population, and reading both would only re-admit the guess. The * unkeyed parameter stays for callers that have no keyed read to offer; it is - * the pre-#14423 behaviour verbatim, nameless rows dropped and all. + * the behaviour before commit a56baa2bd, verbatim, nameless rows dropped and all. */ export async function collectEngineActionDeclarations( objects: any[], @@ -394,7 +394,7 @@ export async function collectEngineActionDeclarations( /** * The router's BY-NAME rungs, applied to the handlers the declaration set did - * not cover — `registry.getItem('action', )` (rung 2) and, since #14423, + * not cover — `registry.getItem('action', )` (rung 2) and, since commit a56baa2bd, * `meta.loadDiagnosed('action', )` / `meta.load(…)` (rung 3) — each * accepted on the router's own ownership test. * @@ -403,7 +403,7 @@ export async function collectEngineActionDeclarations( * The router never enumerates either source: it asks for ONE name. Mirroring * it means asking for one name. And enumeration is not a substitute here even * where it exists — a plural read and a by-name read of the same plane can - * disagree, which is the whole subject of #14423: one loader fault is + * disagree, which is the whole subject of the card commit a56baa2bd closed: one loader fault is * swallowed by the plural read and served by the by-name read, so a handler * whose declaration lives on the faulted loader reads "undeclared" from the * enumeration alone. The keyed enumeration closes the IDENTITY half of that @@ -474,7 +474,7 @@ function fingerprint(r: ReturnType): string * (`metadata:reloaded` re-runs this; a re-sync that changed nothing should * not repeat the same warning). * - * ## [#14423] Both halves of the bijection read what the router reads + * ## [commit a56baa2bd] Both halves of the bijection read what the router reads * * The two findings used to stand on different sources, which is how the audit * could contradict the router about whether a declaration exists: @@ -522,7 +522,7 @@ export async function runActionGovernanceInventory(args: { */ loadStandaloneActions?: () => Promise; /** - * [#14423] The metadata plane's `action` rows KEYED by the store's own key + * [commit a56baa2bd] The metadata plane's `action` rows KEYED by the store's own key * (`meta.loadManyKeyed('action')`). This is the source the declaration * half of the bijection is defined on, so that the audit and the router * share ONE identity — the store key (#14205) — instead of the audit @@ -538,7 +538,7 @@ export async function runActionGovernanceInventory(args: { */ lookupRegistryAction?: (actionName: string) => unknown; /** - * [#14423] The router's rung 3, injected the same way: + * [commit a56baa2bd] The router's rung 3, injected the same way: * `meta.loadDiagnosed('action', name)?.data`, falling back to * `meta.load('action', name)` — the caller unwraps, so this returns the * declaration or nothing, exactly like {@link lookupRegistryAction}. diff --git a/packages/objectql/src/action-owner-key-single-source.test.ts b/packages/objectql/src/action-owner-key-single-source.test.ts index e965ad6ad2d..da94fd6f554 100644 --- a/packages/objectql/src/action-owner-key-single-source.test.ts +++ b/packages/objectql/src/action-owner-key-single-source.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * This package spells the standalone-action owner-key ladder ONCE (#14422). + * This package spells the standalone-action owner-key ladder ONCE (commit dc7c226b9). * * `ObjectQLPlugin` carried a private `actionObjectKey` that repeated * {@link standaloneActionOwnerKey}'s three rungs, and the only thing holding @@ -73,7 +73,7 @@ describe('standalone-action owner key — one spelling in @objectstack/objectql expect(plugin, 'plugin.ts is missing from the scan').toBeDefined(); // The negative that used to live here — "plugin.ts does not name the // deleted member" — moved to the TREE-scoped section at the bottom of - // this file (#14878). Its scope was the defect, not its subject. What + // this file (commit 29db3cd2a). Its scope was the defect, not its subject. What // stays here is the positive half: the plugin still derives owner keys, // it just does it through the canonical helper now. expect(plugin!.text).toContain('standaloneActionOwnerKey('); @@ -95,7 +95,7 @@ describe('standalone-action owner key — one spelling in @objectstack/objectql }); /** - * ── [#14878] The absence assertion is TREE-scoped, not FILE-scoped ────────── + * ── [commit 29db3cd2a] The absence assertion is TREE-scoped, not FILE-scoped ────────── * * The negative that used to sit in the plugin test above read `plugin.ts` and * nothing else, and THAT SCOPE was the defect. A pin written by the deleting PR @@ -165,7 +165,7 @@ describe('standalone-action owner key — one spelling in @objectstack/objectql */ /** - * The member PR #14667 deleted from `ObjectQLPlugin`. Held as DATA: naming a + * The member commit dc7c226b9 deleted from `ObjectQLPlugin`. Held as DATA: naming a * symbol in a string cannot resurrect it, and this file is excluded from its own * scan precisely so it may carry the name. */ diff --git a/packages/objectql/src/adr0104-file-columns-moved-supply.test.ts b/packages/objectql/src/adr0104-file-columns-moved-supply.test.ts index f5a88f7db1f..0bc05bfafd7 100644 --- a/packages/objectql/src/adr0104-file-columns-moved-supply.test.ts +++ b/packages/objectql/src/adr0104-file-columns-moved-supply.test.ts @@ -2,7 +2,7 @@ /** * [#15989] The kernel→driver supply seam for the ADR-0104 media arm, from the - * ENGINE's side — the ruling on #15041 step 2, as amended by the director + * ENGINE's side — sequencing step 2 of ADR-0104's 2026-09-05 addendum, as amended by the director * ruling (decision batch #120 item 1). * * The driver has accepted `SqlDriverConfig.fileColumnsMoved` since PR #17403, diff --git a/packages/objectql/src/core-boundary.ratchet.test.ts b/packages/objectql/src/core-boundary.ratchet.test.ts index 4723601872b..c2e64ecfe37 100644 --- a/packages/objectql/src/core-boundary.ratchet.test.ts +++ b/packages/objectql/src/core-boundary.ratchet.test.ts @@ -49,7 +49,7 @@ // What this file does NOT see, and what does (#15347) // // This is a SOURCE SCAN over two hard-coded names. Both limits are by -// construction, and #14680 is what they cost: a heavyweight arriving through +// construction, and the leak commit 3bd9b3498 closed is what they cost: a heavyweight arriving through // any other specifier is outside FORBIDDEN_PACKAGES, and a scan of this // package's own sources cannot follow one that arrives three packages deep — // which is how that one arrived, invisible to every gate for the whole time it diff --git a/packages/objectql/src/driver-fault-redaction.test.ts b/packages/objectql/src/driver-fault-redaction.test.ts index 3b47198b7e8..1b41453fdc3 100644 --- a/packages/objectql/src/driver-fault-redaction.test.ts +++ b/packages/objectql/src/driver-fault-redaction.test.ts @@ -106,7 +106,7 @@ describe('redactStatementFromMessage', () => { }); }); -// #8823 — the tail is kept because it names IDENTIFIERS, and on MySQL's +// Commit 4dfa369a9 — the tail is kept because it names IDENTIFIERS, and on MySQL's // duplicate-entry family it does not: `ER_DUP_ENTRY` prints the conflicting // VALUE in the diagnostic itself. These cases pin both halves of the remedy — // the value goes, the index name stays — because a fix that blanked the tail @@ -136,7 +136,7 @@ describe('#8823 — a caller value inlined in the diagnostic itself', () => { }); it('redacts a BARE diagnostic too — the shape that reaches us without a statement', () => { - // Before #9030 the shared leak predicate did not recognise this phrasing, + // Before commit 27a567dd8 the shared leak predicate did not recognise this phrasing, // so a bare `Duplicate entry …` was turned away at the door and kept its // value. That limb landed for a different reason; the two compose here. const out = redactStatementFromMessage(`Duplicate entry '${EMAIL}' for key 'crm_account.email'`); @@ -284,7 +284,7 @@ describe('#9160 — the value-bearing families the live probe measured', () => { }); describe('postgres invalid_text_representation (22P02) / invalid_datetime_format (22007)', () => { - // ⛔ The family the #8823 note was waiting for. Postgres' UNIQUE violation is + // ⛔ The family the commit 4dfa369a9 note was waiting for. Postgres' UNIQUE violation is // saved only because its value sits on `error.detail`, which // `ObjectLogger.write` never serializes — "coincidence, not a defence". This // family puts the caller's value on `error.message`, which IS serialized, so @@ -761,7 +761,7 @@ describe('#8682 half B — the write-path loggers', () => { } /** - * The one driver double in this file. #8823 needed a MySQL-shaped fault and + * The one driver double in this file. Commit 4dfa369a9 needed a MySQL-shaped fault and * the shape is a PARAMETER rather than a second double — one fake engine per * file keeps the contract the double implements reviewable in one place. */ @@ -864,7 +864,7 @@ describe('#8682 half B — the write-path loggers', () => { }); /** - * [#8823] The same write path, with the fault MySQL raises instead — where + * [commit 4dfa369a9] The same write path, with the fault MySQL raises instead — where * the caller's value is in the DIAGNOSTIC and not only in the statement, so * the statement cut alone never reached it. */ diff --git a/packages/objectql/src/driver-fault-redaction.ts b/packages/objectql/src/driver-fault-redaction.ts index 7b1728e8e31..9594cdd593c 100644 --- a/packages/objectql/src/driver-fault-redaction.ts +++ b/packages/objectql/src/driver-fault-redaction.ts @@ -44,7 +44,7 @@ * Nothing else about it moved: the same redacted `message`/`stack` reach the * same `error` key of the same meta bag (`ObjectQL.writeFailureLogMeta`). * - * ## [#8823] …but "the tail names identifiers" is not true of every dialect + * ## [commit 4dfa369a9] …but "the tail names identifiers" is not true of every dialect * * The paragraph above was written with a premise attached: that whatever the * database prints after the separator names IDENTIFIERS — a column, a table, a @@ -60,7 +60,7 @@ * ``` * * Three keep an identifier; the second keeps a caller's value. Measured through - * this function, not predicted — and re-measured byte-identical after #9030 + * this function, not predicted — and re-measured byte-identical after commit 27a567dd8 * taught the shared leak predicate this phrasing, which moves the VERDICT but * not the cut. * @@ -81,7 +81,7 @@ * * ## [#9160] The list is now MEASURED, and there is a way to notice a gap * - * #8823 left one entry and no instrument: nothing measured whether a diagnostic + * Commit 4dfa369a9 left one entry and no instrument: nothing measured whether a diagnostic * a driver produced carried a value, so the next entry needed the same accident * that found the first. `sql-driver-diagnostic-value-probe.test.ts` is that * instrument. It plants a canary value, raises each candidate family against @@ -108,7 +108,7 @@ * ``` * * ¹ on `error.message`. Both put the caller's row on `error.detail`, which - * `ObjectLogger.write` does not serialize — the coincidence #8823 recorded, and + * `ObjectLogger.write` does not serialize — the coincidence commit 4dfa369a9 recorded, and * it is still only a coincidence. **The three Postgres families marked VALUE put * the caller's value on `message`, the field that IS serialized**, so nothing * covers them but the entries below. That was the open question #9160 asked and @@ -140,7 +140,7 @@ * ``` * pg 22P02/22007 value runs to end of message → head-anchored cut (below) * mysql 1292 value runs to end of message → head-anchored cut (below) - * pg 22003 value "…" is out of range … → `tail`, the #8823 mechanism + * pg 22003 value "…" is out of range … → `tail`, the commit 4dfa369a9 mechanism * ``` * * `22003` was assumed unreachable on the reasoning that its value slot holds a @@ -266,11 +266,11 @@ const STATEMENT_SEPARATOR = ' - '; /** What replaces a statement that carried nothing but values. */ const REDACTED_STATEMENT = '[statement and bound values redacted]'; -/** [#8823] What replaces one caller value inlined in the database's own diagnostic. */ +/** [commit 4dfa369a9] What replaces one caller value inlined in the database's own diagnostic. */ const REDACTED_VALUE = '[value redacted]'; /** - * [#8823] MySQL/MariaDB `ER_DUP_ENTRY` (1062), whole: the template's own head, + * [commit 4dfa369a9] MySQL/MariaDB `ER_DUP_ENTRY` (1062), whole: the template's own head, * the conflicting VALUE, and the `for key ` tail that anchors it. * * `Duplicate entry '%-.192s' for key '%-.192s'` — the first slot is whatever the @@ -295,7 +295,7 @@ const REDACTED_VALUE = '[value redacted]'; const DUPLICATE_ENTRY = /(duplicate entry\s+)["'`][\s\S]*["'`](\s+for key\s+["'`][^"'`]+["'`])/gi; /** - * [#8823] The same template with its head already gone — what the statement cut + * [commit 4dfa369a9] The same template with its head already gone — what the statement cut * leaves behind when the conflicting VALUE itself contained ` - `. * * Measured: `insert into … values ('2026 - Q3 plan') - Duplicate entry '2026 - @@ -352,7 +352,7 @@ const MYSQL_INCORRECT_VALUE_TAIL = /'(\s+for column\s+'[^']*'\s+at row\s+\d+)/gi * invalid input syntax for type timestamp with time zone: "CANARY-notadate" * ``` * - * **This is the family the #8823 note was waiting for.** Postgres' unique + * **This is the family the commit 4dfa369a9 note was waiting for.** Postgres' unique * violation is saved only because its value sits on `error.detail`, which * `ObjectLogger.write` does not serialize — recorded there as "coincidence, not * a defence". Here the value is on `error.message`, the field that IS @@ -405,7 +405,7 @@ const PG_VALUE_OUT_OF_RANGE = /(value\s+)"[\s\S]*"(\s+is out of range for type [ * logged: Q3" is out of range for type integer ← `Q3` is caller data * ``` * - * This family keeps its right anchor, so it takes the #8823 recovery and NOT a + * This family keeps its right anchor, so it takes the commit 4dfa369a9 recovery and NOT a * `head`: everything before ` is out of range for type` is value residue by * construction and is dropped whole. ⛔ It must not be given a `head` — its * diagnostic continues past the value, which is exactly the shape the head @@ -678,7 +678,7 @@ export function redactStatementFromMessage(message: string): string { if (!message || !looksLikeInternalErrorLeak(message)) return message; const cut = statementCut(message); // No statement to cut — but a dialect may still have inlined a value in the - // diagnostic itself, and since #9030 taught the shared predicate this + // diagnostic itself, and since commit 27a567dd8 taught the shared predicate this // phrasing, a BARE `Duplicate entry …` now reaches this line instead of // being turned away above. if (cut === -1) return redactDiagnosticValues(message); @@ -716,7 +716,7 @@ function statementCut(message: string): number { } /** - * [#8823] Drop the caller values a dialect inlines into its OWN diagnostic, + * [commit 4dfa369a9] Drop the caller values a dialect inlines into its OWN diagnostic, * keeping every identifier around them. * * Runs on the tail the statement cut already produced, never on the whole diff --git a/packages/objectql/src/duplicate-record-error.ts b/packages/objectql/src/duplicate-record-error.ts index 6b214302e4b..1de209bf13c 100644 --- a/packages/objectql/src/duplicate-record-error.ts +++ b/packages/objectql/src/duplicate-record-error.ts @@ -3,7 +3,7 @@ import { isUniqueViolationError, uniqueViolationColumn } from '@objectstack/types'; /** - * The ADR-0112 envelope `engine.insert` (#14095) and `engine.update` (#14390) + * The ADR-0112 envelope `engine.insert` (#14095) and `engine.update` (commit 9d7f7259f) * raise when a driver refuses a row as a unique-constraint violation. * * ## The defect this retires @@ -36,7 +36,7 @@ import { isUniqueViolationError, uniqueViolationColumn } from '@objectstack/type * caller of `engine.insert` / `engine.update` (a hook, a flow node, a * script holding the engine) branches on, on every driver. ⛔ It is not * the WIRE spelling: every REST route — the single-record door, the - * whole-request bulk / import doors, and since #14723 the per-row reports + * whole-request bulk / import doors, and since commit 65846bc46 the per-row reports * of `POST /data/:object/batch` and the import runner alike — reports a * unique-constraint refusal as `UNIQUE_VIOLATION`, the standard-catalog * member the published protocol docs give for the 409 constraint-violation @@ -134,7 +134,7 @@ function buildDuplicateMessage(object: string, field?: string): string { } /** - * A write door's driver-error exit — `insert` (#14095) and `update` (#14390), + * A write door's driver-error exit — `insert` (#14095) and `update` (commit 9d7f7259f), * by-id and predicate alike: the platform envelope for a unique violation, or * the caller's own error unchanged for anything else. * diff --git a/packages/objectql/src/engine-author-state-query.test.ts b/packages/objectql/src/engine-author-state-query.test.ts index 5d51f4de362..bacdd15d72d 100644 --- a/packages/objectql/src/engine-author-state-query.test.ts +++ b/packages/objectql/src/engine-author-state-query.test.ts @@ -1,18 +1,18 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #6300 — `find`/`findOne` take the AUTHOR state (`z.input`), and the engine + * Commit 74155c735 — `find`/`findOne` take the AUTHOR state (`z.input`), and the engine * fills the defaults the schemas declare before the AST leaves it. * * ADR-0122's core argument is "the first key an author writes must default * correctly". `engine.find(obj, { orderBy: [{ field: 'updated_at' }] })` is * the natural spelling of "newest-ish first" — and until this card it did not - * compile: #6083 pinned `find`/`findOne` back to `EngineQueryOptionsParsed` + * compile: commit 53068c130 pinned `find`/`findOne` back to `EngineQueryOptionsParsed` * (`z.infer`) because the engine built its `QueryAST` by bare spread and * filled no default, so admitting the author state would have sent * `order: undefined` to the driver. * - * The measured driver-side status quo (part of #6300's own premise): every + * The measured driver-side status quo (part of commit 74155c735's own premise): every * driver coalesces a missing `order` to `'asc'` — `sql-driver.ts` * (`s.order || 'asc'`), `memory-driver.ts`, `mongodb-driver.ts`, * `mongodb-aggregation.ts`, `remote-transport.ts`. So the filled `'asc'` @@ -150,7 +150,7 @@ describe('find/findOne accept the author state and the engine fills the declared }); // ── (1) The contract flip, pinned by the compiler ──────────────────────── - // Every call in this block is UNCAST. Under #6083's `...Parsed` parameter + // Every call in this block is UNCAST. Under commit 53068c130's `...Parsed` parameter // none of them compiled — `orderBy[].order` was required to write. The // `IDataEngine`-typed alias pins the spec contract, not just the class. @@ -213,7 +213,7 @@ describe('find/findOne accept the author state and the engine fills the declared // ── (4) The schema's strictness rides with its defaulting parse ────────── // These callers bypass the type (`as unknown as EngineQueryOptions` — the // #4918 spelling for a DELIBERATELY off-contract probe), which is the only - // way these shapes can occur. Before #6300 the engine forwarded them + // way these shapes can occur. Before commit 74155c735 the engine forwarded them // verbatim and each driver decided alone: memory honored `direction`, // SQL/Mongo silently dropped it and sorted ascending — one query, two // orders (#4721's class). diff --git a/packages/objectql/src/engine-autonumber-resync.test.ts b/packages/objectql/src/engine-autonumber-resync.test.ts index ef6e196f56e..e19feb9209c 100644 --- a/packages/objectql/src/engine-autonumber-resync.test.ts +++ b/packages/objectql/src/engine-autonumber-resync.test.ts @@ -50,9 +50,9 @@ * * ⚠️ **Both of the two that do can now raise.** driver-mongodb raises a * single-field unique index's `E11000` when the field declares `unique`; since - * #13197 driver-memory refuses a declared-unique collision too, in the ADR-0112 + * commit 56c093c4d driver-memory refuses a declared-unique collision too, in the ADR-0112 * envelope (`code: 'UNIQUE_VIOLATION'`, `status: 409`), with `driver-sql`'s - * ADR-0120 D1/D3 scoping. Until #13197 it never could — `create` was a + * ADR-0120 D1/D3 scoping. Until commit 56c093c4d it never could — `create` was a * `table.push()` storing no constraints at all (#4065) — so a duplicate landed * SILENTLY and this branch was unreachable there. Section (3b) carries the * pin, INVERTED in place rather than deleted, so the change of fact stays @@ -65,7 +65,7 @@ * as `ruled-permanent` («#6664 A, maintainer 2026-08-08 — inherits #5704 * Q2 = B») — "InMemoryDriver declares `supports = {}`, so the ENGINE's * autonumber seeding owns the counter. No SQL backend can stand in". What - * #13197 moved is which store can REJECT, never who issues the number, so that + * commit 56c093c4d moved is which store can REJECT, never who issues the number, so that * ruling is untouched. Section (3b) pins the consequence rather than authoring * a second answer to the same question (#6832's one-contract-two-numbers * shape). Adoption still covers the drift no store can report, and still waits @@ -171,7 +171,7 @@ function matches(row: Row, where: any): boolean { * `uniqueViolationColumn` answers `undefined`. That combination is exactly why * the resync treats an unnamed column as attributable: neither in-repo fallback * driver names a column this predicate can read — MongoDB names the INDEX, and - * driver-memory (since #13197) raises a coded envelope with no dialect prose in + * driver-memory (since commit 56c093c4d) raises a coded envelope with no dialect prose in * it — so demanding a named column would make the resync unreachable on both. */ const mongoDuplicate = (field: string, value: string) => @@ -183,7 +183,7 @@ const mongoDuplicate = (field: string, value: string) => ); /** - * [#13197] `driver-memory`'s duplicate refusal — the ADR-0112 envelope, not a + * [commit 56c093c4d] `driver-memory`'s duplicate refusal — the ADR-0112 envelope, not a * dialect. It carries `code: 'UNIQUE_VIOLATION'` (the platform's own registered * code) and `status: 409`, and names no column in any spelling * `uniqueViolationColumn` parses. So, exactly like the MongoDB shape above, @@ -723,7 +723,7 @@ describe('ObjectQL autonumber resync (#6806)', () => { /* ====================================================================== * * (3b) The collision half is STORAGE-DEPENDENT — name which driver gives * which guarantee, rather than implying one that is not delivered. - * #13197 changed the ANSWER for driver-memory (it constrains now); the + * Commit 56c093c4d changed the ANSWER for driver-memory (it constrains now); the * question, and the duty to answer it by driver name, are unchanged. * ==================================================================== */ @@ -731,7 +731,7 @@ describe('ObjectQL autonumber resync (#6806)', () => { const SCHEMA = schemaWith('doc_no', 'D-{0000}'); it('the duplicate is REFUSED and the number re-issued — it used to land silently', async () => { - // ⚠️ INVERTED IN PLACE by #13197. Until then this test asserted the + // ⚠️ INVERTED IN PLACE by commit 56c093c4d. Until then this test asserted the // DEFECT as correct behaviour — `written.doc_no === 'D-0005'` and // `rows.filter(…D-0005).toHaveLength(2)`, over a comment calling two rows // carrying one business identifier "the honest outcome". It was honest: @@ -750,7 +750,7 @@ describe('ObjectQL autonumber resync (#6806)', () => { // `driver-sql`'s ADR-0120 D1/D3 scoping, and raises the ADR-0112 // envelope `code: 'UNIQUE_VIOLATION'` / `status: 409` — the shape // `memoryDuplicate` below reproduces. `isUniqueViolationError` reads that - // code (#13197 added the limb), so the collision branch is REACHABLE on + // code (commit 56c093c4d added the limb), so the collision branch is REACHABLE on // this driver for the first time: the stale counter is dropped, the // counter re-seeds from the store's real max, and the number is re-issued. // diff --git a/packages/objectql/src/engine-cascade-delete.test.ts b/packages/objectql/src/engine-cascade-delete.test.ts index fe81f59cff8..d259e862b57 100644 --- a/packages/objectql/src/engine-cascade-delete.test.ts +++ b/packages/objectql/src/engine-cascade-delete.test.ts @@ -634,13 +634,13 @@ describe('cascadeDeleteRelations — [#9689] authored set_null on master_detail }); }); -// [#13644] The DECLARED referential-cleanup marker — `HookContext. +// [commit 34ce8e7db] The DECLARED referential-cleanup marker — `HookContext. // referentialFieldClear` — populated on EVERY reference-cleanup write the // engine issues, as the read-only projection of the operation-private // `__referentialFieldClear` the #3023 pin above holds on the envelope. // // Why this pin exists, and why its caller context carries a full identity: the -// filer's corrected measurement (#13644) showed the engine builds the cleanup +// filer's corrected measurement (on the card commit 34ce8e7db closed) showed the engine builds the cleanup // write as `{ ...callerContext, transaction, __referentialFieldClear: true }` // — it INHERITS whatever identity the caller supplied — so on the path a real // request takes (a REST DELETE carrying a userId) `ctx.user`, `ctx.session` diff --git a/packages/objectql/src/engine-file-hydrate-outage.test.ts b/packages/objectql/src/engine-file-hydrate-outage.test.ts index 808cc79cf61..702e9ce49cf 100644 --- a/packages/objectql/src/engine-file-hydrate-outage.test.ts +++ b/packages/objectql/src/engine-file-hydrate-outage.test.ts @@ -18,7 +18,7 @@ * `the generic line separates the two causes but still cannot name the loss` * block below pins why it does not satisfy the acceptance: it describes the * sub-read only — never the parent object, the fields left un-hydrated, or the - * consequence. ⚠️ [#13273] That block was rewritten when the generic frame + * consequence. ⚠️ [commit 3a86a65e7] That block was rewritten when the generic frame * stopped being `error` for every cause: it is `debug` for the benign * "table was never provisioned" class now, and — [#17212], because `find` * rethrows and so tells its caller — `warn` for everything else. @@ -296,7 +296,7 @@ describe('sys_file hydrate read fault — distinguishable from "no file" (#6116) * failed `sys_file` sub-read before rethrowing into this catch. That line is * real and this fix neither removes nor duplicates it. * - * ⚠️ [#13273] What HAS moved since #6116, and why this block was rewritten + * ⚠️ [commit 3a86a65e7] What HAS moved since #6116, and why this block was rewritten * rather than deleted. That generic frame used to be `error` for every cause * — which is what made it useless as a discriminator, and is the sentence * this block used to pin. `engine.ts` now asks `isMissingTableError` and puts @@ -304,7 +304,7 @@ describe('sys_file hydrate read fault — distinguishable from "no file" (#6116) * line. The re-pinned facts below are therefore: * * 1. the generic frame DOES now separate the two causes by channel — the - * benign read reaches `debug` only (#13273's own acceptance, + * benign read reaches `debug` only (commit 3a86a65e7's own acceptance, * re-measured from this file's fake driver), the outage the loud * branch, which is `warn` since [#17212] (`find` rethrows into this * seam's catch, so its caller was told) — and neither reaches `error`; diff --git a/packages/objectql/src/engine-filter-alias.test.ts b/packages/objectql/src/engine-filter-alias.test.ts index 3e7e02a81a8..b993ab04d87 100644 --- a/packages/objectql/src/engine-filter-alias.test.ts +++ b/packages/objectql/src/engine-filter-alias.test.ts @@ -217,7 +217,7 @@ describe('filter → where folds on every engine method (#4346)', () => { const repo = ctx.object('task'); const viaWhere = await repo.findOne({ where: { status: 'done' } }); const viaFilter = await repo.findOne({ filter: { status: 'done' } }); - // [#16786] `repo.findOne` declares `Record | null`, so the + // [commit 5c8f5af50] `repo.findOne` declares `Record | null`, so the // null both spellings could return is asserted away rather than read // through — the same `expect(row).not.toBeNull()` / `row!` idiom this // file already uses above. Under the old `Promise` this pair diff --git a/packages/objectql/src/engine-filter-array-lowering.test.ts b/packages/objectql/src/engine-filter-array-lowering.test.ts index 94f7c641244..9c2bc627b02 100644 --- a/packages/objectql/src/engine-filter-array-lowering.test.ts +++ b/packages/objectql/src/engine-filter-array-lowering.test.ts @@ -42,7 +42,7 @@ import { ObjectQL } from './engine.js'; * (#5285). So a test that hands the engine one has to say so, and * `as unknown as EngineQueryOptions` is how: it names the contract being * bypassed, keeps the rest of the call type-checked, and greps as an - * intentional act — none of which a bare `as any` does. (#6300 flipped the + * intentional act — none of which a bare `as any` does. (Commit 74155c735 flipped the * find/findOne parameter from `EngineQueryOptionsParsed` to the author-state * `EngineQueryOptions`; the cast target follows the contract it names.) * @@ -90,7 +90,7 @@ interface SeenRead { ast: DriverQuery } * signature moves. * * `aggregate` included: the engine reaches it by duck-typing - * (`typeof drv.aggregate === 'function'`, `engine.ts`), and until #14345 the + * (`typeof drv.aggregate === 'function'`, `engine.ts`), and until commit e89fa9233 the * interface did not declare it, so this file carried a local extension for * the one verb. `IDataDriver.aggregate?` now spells the signature the engine * calls, so the double's `aggregate` is checked by the same annotation as diff --git a/packages/objectql/src/engine-find-missing-table-log-level.test.ts b/packages/objectql/src/engine-find-missing-table-log-level.test.ts index 173e606ace0..9d761db15fd 100644 --- a/packages/objectql/src/engine-find-missing-table-log-level.test.ts +++ b/packages/objectql/src/engine-find-missing-table-log-level.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #13273 — a `find` that failed because the table was never created is not the + * Commit 3a86a65e7 — a `find` that failed because the table was never created is not the * same fact as a `find` that FAILED, and the two must not share a log level. * * ## What was measured, and where diff --git a/packages/objectql/src/engine-insert-duplicate-record.test.ts b/packages/objectql/src/engine-insert-duplicate-record.test.ts index ad3934a5a31..bb810f77971 100644 --- a/packages/objectql/src/engine-insert-duplicate-record.test.ts +++ b/packages/objectql/src/engine-insert-duplicate-record.test.ts @@ -101,7 +101,7 @@ const mysqlDuplicate = () => errno: 1062, }); -/** driver-memory (#13197): already an ADR-0112 envelope, in the platform's own vocabulary. */ +/** driver-memory (commit 56c093c4d): already an ADR-0112 envelope, in the platform's own vocabulary. */ const memoryDuplicate = () => Object.assign( new Error('Unique constraint violated on `doc.email`: a record with that value already exists.'), @@ -264,7 +264,7 @@ describe('engine.insert — a driver unique violation is a DUPLICATE_RECORD enve }); it('normalises a driver that already speaks an envelope — one code, not two', async () => { - // driver-memory raises `UNIQUE_VIOLATION` / 409 (#13197). It is a platform + // driver-memory raises `UNIQUE_VIOLATION` / 409 (commit 56c093c4d). It is a platform // envelope, but it is a DIFFERENT one, so an application branching on the // insert door would still need two spellings. The door answers one. const raw = memoryDuplicate(); diff --git a/packages/objectql/src/engine-kind-registration-log.test.ts b/packages/objectql/src/engine-kind-registration-log.test.ts index c8dede5d31c..81618b754d0 100644 --- a/packages/objectql/src/engine-kind-registration-log.test.ts +++ b/packages/objectql/src/engine-kind-registration-log.test.ts @@ -1,5 +1,5 @@ /** - * [#10729] `contributes.kinds` — the registration site's debug line must name + * [commit 10485009a] `contributes.kinds` — the registration site's debug line must name * fields that EXIST. * * `registerApp()` logs one `'Registered Kind'` line per contributed kind. It diff --git a/packages/objectql/src/engine-post-hook-undeclared-field.test.ts b/packages/objectql/src/engine-post-hook-undeclared-field.test.ts index 31552e297e0..dd224dea854 100644 --- a/packages/objectql/src/engine-post-hook-undeclared-field.test.ts +++ b/packages/objectql/src/engine-post-hook-undeclared-field.test.ts @@ -1,6 +1,6 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. // -// #13657 — the declared-field door's POST-HOOK half. +// Commit b003cf2e8 — the declared-field door's POST-HOOK half. // // #8682 / #8738 put the door in and PR #8737 moved it AHEAD of the `before*` // hooks and ahead of statement construction, so that no work (above all, no diff --git a/packages/objectql/src/engine-readonly-hook-input.test.ts b/packages/objectql/src/engine-readonly-hook-input.test.ts index 81865776994..cadebb3ecad 100644 --- a/packages/objectql/src/engine-readonly-hook-input.test.ts +++ b/packages/objectql/src/engine-readonly-hook-input.test.ts @@ -409,7 +409,7 @@ describe('#16344 — caller-forged readonly values are hidden from beforeUpdate' }); /** - * [#17219] The OTHER half of the same hide pass: what an author is told when a + * [commit 706ad0fcc] The OTHER half of the same hide pass: what an author is told when a * hook reaches THROUGH a key #16344 withheld. * * ⛔ The refusal itself is not under test here and is not moved: a body's diff --git a/packages/objectql/src/engine-readonly-when-derived-writes.test.ts b/packages/objectql/src/engine-readonly-when-derived-writes.test.ts index 5bf7397a447..e4792812735 100644 --- a/packages/objectql/src/engine-readonly-when-derived-writes.test.ts +++ b/packages/objectql/src/engine-readonly-when-derived-writes.test.ts @@ -241,7 +241,7 @@ describe('readonlyWhen strips CALLER-submitted values only (#9107)', () => { // frozen paid-invoice lines). That same blindness would let this exact // line — or a normalisation that is the identity for canonical input — // hand the CALLER's value hook ownership and silently unlock the lock. - // So this seam keeps VALUE EQUALITY, on purpose. Measured on #14472's + // So this seam keeps VALUE EQUALITY, on purpose. Measured on commit 00ff228fe's // branch: threading the record into `isCallerSuppliedValue` turned this // very test red (`closed_note` committed the forgery where the lock had // stripped it to `null`). diff --git a/packages/objectql/src/engine-seed-required-deferral.test.ts b/packages/objectql/src/engine-seed-required-deferral.test.ts index b7dfe02810b..a710be59110 100644 --- a/packages/objectql/src/engine-seed-required-deferral.test.ts +++ b/packages/objectql/src/engine-seed-required-deferral.test.ts @@ -7,7 +7,7 @@ import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts' /** * Seed deferral vs `required: true` — measured against the REAL engine - * (#11674, the card's "Second, NOT measured" question). + * (the "Second, NOT measured" question on the card commit 9a884c6e4 fixed). * * The seed loader defers an unresolvable reference to pass 2 by DELETING the * column from the row. The seed-loader suite's engine double does not @@ -22,7 +22,7 @@ import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts' * 1. REQUIRED id half (`sys_approval_request` / `sys_record_share` / * `sys_share_link` shape): the deferred insert — its required `record_id` * deleted — is REJECTED by required-validation. Loud, counted, the row - * never lands, and pass 2 has nothing to write back onto. So #11674's + * never lands, and pass 2 has nothing to write back onto. So commit 9a884c6e4's * internal-id write-back does NOT make these three objects * order-independent: their datasets must still seed the target first. * 2. Same object, target seeded FIRST: the pointer resolves in pass 1, the @@ -32,7 +32,7 @@ import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts' * 3. OPTIONAL id half (`sys_audit_log` shape), keyless dataset, target * seeded after: pass 1 inserts without the column (nothing requires it), * and pass 2 back-fills through the internal id captured at insert time — - * #11674's fix, holding end-to-end against the engine that really + * commit 9a884c6e4's fix, holding end-to-end against the engine that really * validates. This is what makes `sys_audit_log` genuinely * order-independent while its three required-half siblings are not. */ @@ -136,7 +136,7 @@ function silentLogger() { /** * Every line in the ORDER it was emitted, across levels — which is how the * author reads a seed run, and the only shape in which "the loader said it - * BEFORE the engine did" (#11674's B half) is a measurable claim rather than + * BEFORE the engine did" (commit 1cba33f16, the B half) is a measurable claim rather than * an assertion about two unrelated arrays. */ const lines: Array<{ level: string; message: string }> = []; diff --git a/packages/objectql/src/engine-undeclared-update-field.test.ts b/packages/objectql/src/engine-undeclared-update-field.test.ts index f3bc28a9478..d3e64757bf5 100644 --- a/packages/objectql/src/engine-undeclared-update-field.test.ts +++ b/packages/objectql/src/engine-undeclared-update-field.test.ts @@ -328,7 +328,7 @@ describe('#8738 — the declared-field door on update()', () => { // inject `created_at` / `updated_at` itself and the case would prove // nothing about the door. `id` is the one name the registry does NOT // inject, so it is the door's tolerance being read here, and only its. - // [#13657] `description` is declared alongside `name` because this + // [commit b003cf2e8] `description` is declared alongside `name` because this // harness's own `beforeUpdate` hook STAMPS it (`derived-for-…`), and the // post-hook door now judges the hook's output too. Without the // declaration the fixture would be refused for the hook's key and this diff --git a/packages/objectql/src/engine-update-duplicate-record.test.ts b/packages/objectql/src/engine-update-duplicate-record.test.ts index 1051914d894..653371e2ee4 100644 --- a/packages/objectql/src/engine-update-duplicate-record.test.ts +++ b/packages/objectql/src/engine-update-duplicate-record.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #14390 — the update door's ONE error contract for a driver's unique-constraint + * Commit 9d7f7259f — the update door's ONE error contract for a driver's unique-constraint * refusal: the insert door's (#14095), one verb over. * * ## What was measured, and why it is a defect rather than a preference @@ -109,7 +109,7 @@ const mysqlDuplicate = () => }); /** - * driver-memory (#13197 / #13239): already an ADR-0112 envelope, in the + * driver-memory (commit 56c093c4d / #13239): already an ADR-0112 envelope, in the * platform's own vocabulary — the declared-index sentence measured on a real * `InMemoryDriver` for this card, which names the KEY COLUMNS in parentheses * and no single column, so `uniqueViolationColumn` answers `undefined` for it. diff --git a/packages/objectql/src/engine.test.ts b/packages/objectql/src/engine.test.ts index 7ff7307060a..a8858480fb1 100644 --- a/packages/objectql/src/engine.test.ts +++ b/packages/objectql/src/engine.test.ts @@ -411,7 +411,7 @@ describe('ObjectQL Engine', () => { beforeEach(async () => { engine.registerDriver(mockDriver, true); await engine.init(); - // [#13657] `stamped` is declared because this suite's own + // [commit b003cf2e8] `stamped` is declared because this suite's own // `beforeInsert` hook writes it, and the post-hook door now judges // the hook's output against this map. The subject — one dispatch // per row, single-record context shape — is untouched. diff --git a/packages/objectql/src/engine.ts b/packages/objectql/src/engine.ts index 02fe46a5248..71f6c9268ae 100644 --- a/packages/objectql/src/engine.ts +++ b/packages/objectql/src/engine.ts @@ -2,7 +2,7 @@ import { AsyncLocalStorage } from 'node:async_hooks'; import { QueryAST, QueryInput, HookContext, ServiceObject } from '@objectstack/spec/data'; -// [#6300] The defaulting node schema `fillQueryAstDefaults` runs author input +// [commit 74155c735] The defaulting node schema `fillQueryAstDefaults` runs author input // through — the declared `.default()` stays in `packages/spec`, the engine // only invokes it. import { SortNodeSchema } from '@objectstack/spec/data'; @@ -22,7 +22,7 @@ import { type DroppedFieldsEvent } from '@objectstack/spec/data'; import type { WriteObservabilityOptions } from '@objectstack/spec/contracts'; -// The validate-only result IS the protocol's response shape (#6037): the +// The validate-only result IS the protocol's response shape (commit 18189983d): the // engine is what `metadata-protocol.validateData` returns, so letting the two // drift would put a translation layer between a verdict and its contract. import type { ValidateDataIssue, ValidateDataResponse } from '@objectstack/spec/api'; @@ -247,9 +247,9 @@ import { AssembledViewArtifactSchema, isViewContainerShaped, } from '@objectstack/spec'; -// [#14399] The ONE spelling of "which object does an aggregated `defineView` +// [commit 3c1bbd2a8] The ONE spelling of "which object does an aggregated `defineView` // container bind to", imported rather than re-spelled — from the LEAF subpath, -// for the reason the `/errors` import above states (#14680). See +// for the reason the `/errors` import above states (commit 3bd9b3498). See // `resolveMetadataItemName` below for why this registrar lost its fourth copy. import { deriveViewContainerObject } from '@objectstack/metadata/view-container'; // [#20331] The divergent view-container `name` refusal — the ONE judge this @@ -265,7 +265,7 @@ import { collectPredicateRelationships, evaluateValidationRules, optionVisibilit // SAME value. Armed and sealed in `update()`; the module owns the argument for // why neither end may move. import { recordHookPayloadWrites } from './hook-write-provenance.js'; -// [#17219] The hide pass's other half: when a hook faults reaching THROUGH a +// [commit 706ad0fcc] The hide pass's other half: when a hook faults reaching THROUGH a // key that pass withheld, this names the key, says the platform withheld it, // and points at `ctx.previous` — the module owns the measurement and the // reason the explanation cannot be composed any further downstream. @@ -1640,7 +1640,7 @@ function assertOrderByIsMaterializable( // doors: a caller refused at the REST boundary and a caller refused here // must not be sent two different ways. // - // [#8648] With the SEARCH axis the agreement is in SUBSTANCE, not in + // [commit e5eeb499c] With the SEARCH axis the agreement is in SUBSTANCE, not in // words, and saying otherwise here was simply false — measured from the // running doors, #6673's correction emits "Mirror the computed value onto // a stored text field on '' and search that instead." All three @@ -2370,7 +2370,7 @@ export interface HookEntry { * ⚠️ That idiom is deliberately stated WITHOUT naming a live registration. * It used to name one: `sys_attachment` declared #4757's delete refusal on * `beforeDelete` and on no update registration — true when this paragraph was - * written (#9974), false since #10091 gave that guard's update verb a refusal + * written (#9974), false since commit da891e0ef gave that guard's update verb a refusal * of its own. A replacement exemplar would only be the next referent free to * move, so none is named: the past-tense sentence cannot be falsified by the * tree moving on, because it is a claim about what those two cards did rather @@ -2430,7 +2430,7 @@ function hookTargetList(target: string | string[] | undefined): string[] { * The allow half keeps the TRUTHINESS test both copies used verbatim, rather * than the `!== undefined` that reads more precisely. They differ on exactly one * input, `object: ''`, which reads here as a GLOBAL hook (falsy ⇒ no filter). - * That read is deliberately UNCHANGED, and #6573 is why: flipping it would turn + * That read is deliberately UNCHANGED, and commit 708431313 says why: flipping it would turn * a hook firing on everything into one firing on nothing, silently — the same * class of defect pointing the other way. The shape is closed at the * registration door instead ({@link assertValidHookObject}), so no live entry @@ -2514,7 +2514,7 @@ function assertValidHookExcludeObjects( } /** - * [#6573] Registration-time refusal for the `object` (ALLOW) face, closing + * [commit 708431313] Registration-time refusal for the `object` (ALLOW) face, closing * #4281 / #4001's "an empty target is not *no* target" ruling on the path that * ruling never reached. * @@ -2568,7 +2568,7 @@ function assertValidHookObject( } /** - * [#6573] Refuse a scope whose two faces cancel each other out — + * [commit 708431313] Refuse a scope whose two faces cancel each other out — * `{ object: 'account', excludeObjects: 'account' }` and its list forms. * * The exclusion face subtracts from the allow face, so when the allow face is a @@ -2797,7 +2797,7 @@ export interface OperationContext { */ tenantLayer0Verdict?: TenantLayer0Verdict; /** - * [#16608] The INSERT post-image seam — where an enforcement layer gets to + * [commit a016f08b8] The INSERT post-image seam — where an enforcement layer gets to * judge the row that will actually be stored. * * An `insert` has no pre-image, so a middleware's only image of the write is @@ -2838,7 +2838,7 @@ export interface OperationContext { } /** - * [#16608] The judgement {@link OperationContext.postHookWriteImageCheck} + * [commit a016f08b8] The judgement {@link OperationContext.postHookWriteImageCheck} * carries, and the acknowledgement its installer reads back. * * `evaluate` receives the images the driver is about to store, and REFUSES by @@ -2910,7 +2910,7 @@ export type EngineMiddleware = ( /** * "Which of these tombstoned `sys_file` rows is something still holding?" - * (#11427). + * (commit c3c72a4bc). * * Takes the whole tombstoned set from ONE record read and returns the subset * still held, as a set of stringified ids. Batched rather than per-row on @@ -3022,7 +3022,7 @@ const METADATA_ARRAY_KEYS = [ * `/api/v1/meta/views/:object`, `getViewsByObject()` and * `GET /meta/view?object=` all address it by. * - * ⚠️ [#14399] The sentence that used to stand here — "per spec, `ViewSchema` + * ⚠️ [commit 3c1bbd2a8] The sentence that used to stand here — "per spec, `ViewSchema` * does NOT have a top-level `name` field" — is measurably false and was the * premise for consulting `item.name` first. `ViewSchema` declares an optional * `name` (`view.zod.ts`), described there as "supplied by the metadata door; @@ -3033,7 +3033,7 @@ const METADATA_ARRAY_KEYS = [ */ function resolveMetadataItemName(key: string, item: any): string | undefined { if (!item) return undefined; - // [#14399] The aggregated `views` CONTAINER branch, taken FIRST and answered + // [commit 3c1bbd2a8] The aggregated `views` CONTAINER branch, taken FIRST and answered // by the shared derivation. Everything below is unchanged. // // This registrar used to consult `item.name` before anything else, for every @@ -3775,9 +3775,9 @@ export class ObjectQL implements IObjectQLEngine { // first, so the combined check below can assume well-formed names. // [#5928] An exclusion face that subtracts nothing (`''`) or everything (`'*'`). assertValidHookExcludeObjects(options?.excludeObjects, event); - // [#6573] An allow face that names nothing (`''` → global, `[]`/`['']` → never fires). + // [commit 708431313] An allow face that names nothing (`''` → global, `[]`/`['']` → never fires). assertValidHookObject(options?.object, event); - // [#6573] Two well-formed faces that cancel out (`'account'` minus `'account'`). + // [commit 708431313] Two well-formed faces that cancel out (`'account'` minus `'account'`). assertHookScopeNotSelfCancelling(options?.object, options?.excludeObjects, event); // [#9719/#9974] The unscoped-multi-write flag on an event whose dispatch never reads it. assertValidUnscopedMultiWriteFlag(options?.dispatchUnscopedMultiWrite, event); @@ -4642,7 +4642,7 @@ export class ObjectQL implements IObjectQLEngine { /** * "Which of these tombstoned `sys_file` rows is something still holding?" - * (#11427) — supplied by the storage plugin, never derived here. + * (commit c3c72a4bc) — supplied by the storage plugin, never derived here. * * File-field hydration must answer the same question the download path * answers (#10246) or one row gets two answers. That question has exactly one @@ -4658,7 +4658,7 @@ export class ObjectQL implements IObjectQLEngine { private _heldFileResolver?: HeldFileResolver; /** - * Wire the batched holder question (#11427). Last registration wins; leaving + * Wire the batched holder question (commit c3c72a4bc). Last registration wins; leaving * it unwired keeps tombstoned files un-hydrated, which is what this engine * did before the seam existed. */ @@ -5268,7 +5268,7 @@ export class ObjectQL implements IObjectQLEngine { } /** - * [#13644] Build the declared `HookContext.referentialFieldClear` marker — + * [commit 34ce8e7db] Build the declared `HookContext.referentialFieldClear` marker — * the read-only hook-context projection of the operation-private * `__referentialFieldClear` that {@link ObjectQL.cascadeDeleteRelations} * stamps on the cleanup write's ExecutionContext (#3023). @@ -5447,7 +5447,7 @@ export class ObjectQL implements IObjectQLEngine { // reading (2026-08-31 ruling, execution point 1). // // It used to mute EVERY elevated write, whatever the object was. The - // #13178 census measured what that cost: 135 of 175 write call sites + // census cited in commit e49d98896's message measured what that cost: 135 of 175 write call sites // (77%) were silenced here — at the control's LARGEST gate, sitting // ahead of the condition the control is about — and the control has // never produced a finding, while all five known instances of the defect @@ -5625,7 +5625,7 @@ export class ObjectQL implements IObjectQLEngine { // [#13491] Platform-namespace objects are excluded PER OBJECT, not // wholesale. The 2026-08-31 ruling withdrew the blanket // `isPlatformNamespaceObject(object)` exemption that used to stand here: - // #8672's "an org-less row is defensible for `sys_permission_set`" + // commit ff08691e6's "an org-less row is defensible for `sys_permission_set`" // inherits per object, and the namespace also holds objects whose org-less // rows are a defect — five instances of that class, all found by hand. // `unclassified` keeps the old exclusion so an unadjudicated object's @@ -6330,14 +6330,14 @@ export class ObjectQL implements IObjectQLEngine { * * | driver | `supports.autonumber` | fallback path? | uniqueness on the column | a collision appears as | * |:---|:---|:---|:---|:---| - * | driver-memory | `supports = {}` | **yes** | field-level `unique`, since #13197 (ADR-0120 D1/D3 scoping) | `UNIQUE_VIOLATION` / 409 → re-seed + re-issue, here | + * | driver-memory | `supports = {}` | **yes** | field-level `unique`, since commit 56c093c4d (ADR-0120 D1/D3 scoping) | `UNIQUE_VIOLATION` / 409 → re-seed + re-issue, here | * | driver-mongodb | absent (`{ batchSchemaSync: true }`) | **yes** | single-field unique index when the field declares `unique` | `E11000 duplicate key` → re-seed + re-issue, here | * | driver-sql | `autonumber: true` | no | — | — | * | driver-sqlite-wasm | inherited (`extends SqlDriver`, no `supports` override) | no | — | — | * | driver-turso | inherited (`...super.supports`) | no | — | — | * * So the retry protects the TWO fallback backends — and it protected only one - * of them until #13197, because `driver-memory` enforced no uniqueness at all + * of them until commit 56c093c4d, because `driver-memory` enforced no uniqueness at all * and had nothing to reject with. Which driver ISSUES the number is a * separate question and is unmoved by that: it is the reading the repo * already ruled and gates, in @@ -6351,12 +6351,12 @@ export class ObjectQL implements IObjectQLEngine { * a second answer to "who owns the autonumber counter" is the same * one-contract-two-numbers defect this lane keeps closing (#6832). * - * ⚠️ **This paragraph used to record a live defect; #13197 closed it, and the + * ⚠️ **This paragraph used to record a live defect; commit 56c093c4d closed it, and the * ⛔ below is why the closure went where it did.** `InMemoryDriver.create` was * a `table.push()` storing no constraints of any kind (#4065's WEAK-oracle * docstring), so an out-of-process duplicate raised nothing for this method to * catch and the number landed twice in the rendered field with no error - * anywhere. Since #13197 that driver enforces field-level `unique` + * anywhere. Since commit 56c093c4d that driver enforces field-level `unique` * (`driver-memory`'s `memory-unique-constraint.ts`, with `driver-sql`'s * ADR-0120 D1/D3 scoping) and refuses the collision in the ADR-0112 envelope, * which `isUniqueViolationError` reads — so the branch below is reachable @@ -6372,7 +6372,7 @@ export class ObjectQL implements IObjectQLEngine { * driver, NOT a pre-issue existence probe here: a probe costs a query on every * insert (the cost this resync was designed to avoid) and is still racy, so it * would trade a silent duplicate for a rarer silent duplicate at double the - * read cost. That argument is UNCHANGED by #13197 and is not a historical + * read cost. That argument is UNCHANGED by commit 56c093c4d and is not a historical * note — it is the standing reason no probe is added here, and it is what the * driver-side fix was chosen over. (`packages/drivers/**` was under the #5499 * investment freeze when this comment was first written, which is why the work @@ -6672,7 +6672,7 @@ export class ObjectQL implements IObjectQLEngine { // widens its values to `unknown`. State the contract once, on the // entries, rather than casting the argument at the call: the map // values ARE authored `ServiceObject`s — the INPUT shape, which is - // what `registerObject` takes since ADR-0122 phase 2 (#6083). + // what `registerObject` takes since ADR-0122 phase 2 (commit 53068c130). for (const [name, objDef] of Object.entries(manifest.objects) as [string, ServiceObject][]) { // Ensure name in definition matches key objDef.name = name; @@ -6762,7 +6762,7 @@ export class ObjectQL implements IObjectQLEngine { this.logger.debug('Registering kinds from manifest', { id, kindCount: manifest.contributes.kinds.length }); for (const kind of manifest.contributes.kinds) { this._registry.registerKind(kind); - // [#10729] Name the kind by its declared `id`. `contributes.kinds` + // [commit 10485009a] Name the kind by its declared `id`. `contributes.kinds` // items are `{ id, description? }` (`manifest.zod.ts`; `globs` was // retired unread, #11169) and // `registerKind` keys the item on `id` (`registerItem('kind', kind, 'id')`), @@ -6940,7 +6940,7 @@ export class ObjectQL implements IObjectQLEngine { this.logger.warn(`Skipping ${pluralToSingular(key)} without a derivable name`, { id: ownerId }); continue; } - // [#14666] The DIVERGENT-container refusal (maintainer ruling + // [commit d0ee598e6] The DIVERGENT-container refusal (maintainer ruling // 2026-09-03, direction 2). This seam used to reconcile a // container's own `name` to the derived key silently, one line // below: the author's field discarded with no diagnostic, while @@ -7161,7 +7161,7 @@ export class ObjectQL implements IObjectQLEngine { /** * Hand a freshly-registered driver the ADR-0104 media arm — the kernel→driver - * supply seam (#15989, the ruling on #15041 step 2). + * supply seam (#15989, sequencing step 2 of ADR-0104's 2026-09-05 addendum). * * ## Why here, and why a closure rather than a value * @@ -9857,7 +9857,7 @@ export class ObjectQL implements IObjectQLEngine { /** * Have this deployment's file-family COLUMNS moved to the bare-id encoding - * (#15989 — the ruling on #15041, step 2)? + * (#15989 — sequencing step 2 of ADR-0104's 2026-09-05 addendum)? * * The kernel-side half of the arm a SQL driver writes on. The driver cannot * ask this itself: the fact lives in a `sys_migration` row, which is a row @@ -11099,7 +11099,7 @@ export class ObjectQL implements IObjectQLEngine { referenceObject, { where, - // [#6300] The `as any` these two carried is gone: `find` takes the + // [commit 74155c735] The `as any` these two carried is gone: `find` takes the // author state now, and the parsed nodes a `QueryAST` holds are // valid author input (a present `order` is legal to write). ...(nestedAST.fields @@ -11282,7 +11282,7 @@ export class ObjectQL implements IObjectQLEngine { } const fileMap = new Map(); - // [#11427] `committed` is servable and always was. A TOMBSTONE + // [commit c3c72a4bc] `committed` is servable and always was. A TOMBSTONE // (`status: 'deleted'` + `deleted_at`) is recoverable state, not a delete: // it is a claim about the future (this row is reapable once the grace // window ends) that the sweep re-checks and often withdraws. #10246 already @@ -11318,7 +11318,7 @@ export class ObjectQL implements IObjectQLEngine { } } catch (error) { // Unreadable evidence is not evidence of a holder. Keep the ids - // un-hydrated — the answer this pass gave before #11427, and the same + // un-hydrated — the answer this pass gave before commit c3c72a4bc, and the same // direction the download path fails in (`isServableForDownload`) and // the reap guard fails in (it vetoes rather than reaps when it cannot // tell). Distinct from the #6116 catch above, which covers the @@ -11624,13 +11624,13 @@ export class ObjectQL implements IObjectQLEngine { } /** - * [#6300] Fill the author-state defaults the query schemas declare, so the + * [commit 74155c735] Fill the author-state defaults the query schemas declare, so the * AST handed to middlewares, hooks and drivers is the PARSED state * `QueryAST` (a `z.infer` type) promises. * * ADR-0122 made `EngineQueryOptions` the author state (`z.input`): a key * with a declared `.default()` is optional to write. `find`/`findOne` kept - * demanding the parsed state anyway (#6083 pinned them back) because the + * demanding the parsed state anyway (commit 53068c130 pinned them back) because the * engine built its AST by bare spread and filled no default — `order: * undefined` would have ridden straight to the driver. This is the filling. * Each defaulting node is run through ITS OWN schema rather than @@ -11763,7 +11763,7 @@ export class ObjectQL implements IObjectQLEngine { // ADR-0122 the caller-supplied `context` is the AUTHOR state (every key // optional) while `QueryAST` carries the parsed one, so spreading it in and // removing it a line later would type the AST with a context it never holds. - // [#6300] The rest of the bag is author state too now — the defaults its + // [commit 74155c735] The rest of the bag is author state too now — the defaults its // schemas declare are filled here, before anything downstream reads the AST. const { context: _findContext, ...findQuery } = query ?? {}; const ast: QueryAST = { ...this.fillQueryAstDefaults(findQuery), object }; @@ -11925,7 +11925,7 @@ export class ObjectQL implements IObjectQLEngine { * ## The two facts this frame used to merge * * "The table has not been created yet" and "the read failed" are different - * facts, and until #13273 this line reported both at `error`, with a stack. + * facts, and until commit 3a86a65e7 this line reported both at `error`, with a stack. * The first one is the ordinary state of a database nobody has migrated yet, * and every caller on that path already treats it as a normal answer and says * so in its own code: {@link readMigrationFlagVerified} ("an unreadable table @@ -12057,7 +12057,7 @@ export class ObjectQL implements IObjectQLEngine { // last — findOne is single-row by contract. // Same reason as find(): the caller's `context` is the author state and the // AST carries the parsed one, so it leaves before the AST is typed. - // [#6300] And the same default-filling as find(), for the same reason. + // [commit 74155c735] And the same default-filling as find(), for the same reason. const { context: _findOneContext, ...findOneQuery } = query ?? {}; const ast: QueryAST = { ...this.fillQueryAstDefaults(findOneQuery), object: objectName, limit: 1 }; @@ -12302,7 +12302,7 @@ export class ObjectQL implements IObjectQLEngine { // site under its own `computed` reason (`insertDrops`) — in every context, // `isSystem` included, since a `formula` value has no column to land in. /** - * Validate-only (#6037, #4633 ruling D) — run the write path's own verdict + * Validate-only (commit 18189983d, #4633 ruling D) — run the write path's own verdict * over candidate rows and report it, WITHOUT persisting anything. * * ## Why this exists @@ -12941,7 +12941,7 @@ export class ObjectQL implements IObjectQLEngine { rowHookWrittenKeys[i] = sealed?.hookWrittenKeys; } - // ── [#13657] The POST-hook half of the declared-field door ─────────── + // ── [commit b003cf2e8] The POST-hook half of the declared-field door ─────────── // // #8737 moved the door above ahead of the hooks so that no work — no // autonumber, no secret row — is done for a payload about to be refused. @@ -13008,10 +13008,10 @@ export class ObjectQL implements IObjectQLEngine { if (postRefusal) throw postRefusal; } - // ── [#16608] EVERY VALUE-CHANGING PASS, AHEAD OF THE SEAM ────────── + // ── [commit a016f08b8] EVERY VALUE-CHANGING PASS, AHEAD OF THE SEAM ────────── // // The two strips below used to run AFTER the seam, and the contract - // review of PR #16805 measured what that cost: a static-`readonly` + // review commit a016f08b8 records measured what that cost: a static-`readonly` // scoping field — the natural shape for a server-stamped column, and // exactly what an RLS `check` compares (ADR-0055) — was judged by the // seam with the CALLER’s value still on the row, then stripped and @@ -13196,7 +13196,7 @@ export class ObjectQL implements IObjectQLEngine { } } - // ── [#16608] The INSERT POST-IMAGE seam ────────────────────────────── + // ── [commit a016f08b8] The INSERT POST-IMAGE seam ────────────────────────────── // // The enforcement layer's write `check` used to be evaluated in its // middleware, against `opCtx.data` — the caller's payload as it arrived. @@ -13207,7 +13207,7 @@ export class ObjectQL implements IObjectQLEngine { // the same objects `rows` is built from below and the driver is handed. // // Placement obeys the rule #8682 wrote for the declared-field door and - // #13657 restated for its post-hook half: a refusal must cost nothing. + // commit b003cf2e8 restated for its post-hook half: a refusal must cost nothing. // This sits after that door and BEFORE every producer — // `resolveSystemInsertOrganization`, `encryptSecretFields` (which writes // a `sys_secret` row), `applyAutonumbers` (which CONSUMES a sequence @@ -13215,7 +13215,7 @@ export class ObjectQL implements IObjectQLEngine { // // ## What runs between here and the driver — stated, not waved at // - // The contract review of PR #16805 measured the version of this comment + // The contract review commit a016f08b8 records measured the version of this comment // that said "nothing between here and the driver adds a value the caller // could have steered" and then let TWO caller-steerable passes run after // the seam. Both now run ABOVE (`stripRuntimeOwnedFields` and the static @@ -13706,7 +13706,7 @@ export class ObjectQL implements IObjectQLEngine { /** * Update one record by id, or every record a predicate selects. * - * # The error contract on a unique violation (#14390) + * # The error contract on a unique violation (commit 9d7f7259f) * * A driver's unique-constraint refusal leaves this door as the ADR-0112 * envelope `DuplicateRecordError` — `code: 'DUPLICATE_RECORD'`, `status: 409`, @@ -14183,7 +14183,7 @@ export class ObjectQL implements IObjectQLEngine { submitted: Object.freeze({ ...suppliedValues }) as Record, session: this.buildSession(opCtx.context), provenance: this.buildProvenance(opCtx.context), - // [#13644] The declared referential-cleanup marker. Conditional + // [commit 34ce8e7db] The declared referential-cleanup marker. Conditional // spread, not a bare assignment: the contract is "absent unless // true", and an explicit `undefined` member would survive the // per-row context spreads as a present-but-undefined key. @@ -14363,7 +14363,7 @@ export class ObjectQL implements IObjectQLEngine { // permanently true here: it states the invariant, and the invariant // outlives this call site. if (priorRecord) hookContext.previous = coerceBooleanFields(updateSchema as any, priorRecord as any) as any; - // [#17219] All three `beforeUpdate` dispatch sites inside the hide + // [commit 706ad0fcc] All three `beforeUpdate` dispatch sites inside the hide // window share one wrapper, so a hook that faults reaching THROUGH a // key this pass withheld names that key instead of surfacing the // platform's own contract enforcement as the author's crash. It @@ -14483,7 +14483,7 @@ export class ObjectQL implements IObjectQLEngine { // ── [#14088] SEAL the hook-write recording ─────────────────────────── // - // The same CONFLUENCE #13657 uses one comment down, and for the same + // The same CONFLUENCE commit b003cf2e8 uses one comment down, and for the same // reason: on either branch this is the line at which // `hookContext.input.data` is the final POST-hook payload and nothing // engine-owned has written to it yet. One seal covers both branches, so @@ -14578,7 +14578,7 @@ export class ObjectQL implements IObjectQLEngine { } } - // ── [#13657] The POST-hook half of the declared-field door ────────── + // ── [commit b003cf2e8] The POST-hook half of the declared-field door ────────── // // The insert path's twin, applied to the second write verb — same // function, same envelope, same reason (see the long-form note at the @@ -14959,7 +14959,7 @@ export class ObjectQL implements IObjectQLEngine { updateSchema, hookContext.input.data as Record, opCtx.data as Record, opCtx.context, updateMsgCtx, ); - // [#14390] The by-id driver exit — where a driver's refusal + // [commit 9d7f7259f] The by-id driver exit — where a driver's refusal // leaves this door, and where a recognised unique violation // stops being the driver's error. `envelopeUniqueViolation` // returns everything else untouched (a NOT NULL, a deadlock, a @@ -15260,7 +15260,7 @@ export class ObjectQL implements IObjectQLEngine { opCtx.data as Record, opCtx.context, updateMsgCtx, ); // `updateMany` presence is part of the ladder verdict resolved above. - // [#14390] The predicate driver exit, enveloped on the same + // [commit 9d7f7259f] The predicate driver exit, enveloped on the same // terms as the by-id exit above. A multi-row write names no // row: `field` is whatever `uniqueViolationColumn` reads off // the driver's error, and NOTHING is invented about which of @@ -15418,7 +15418,7 @@ export class ObjectQL implements IObjectQLEngine { // redaction, same one argument — the message, the level and the // `object` are unchanged. // - // [#14390] …and, as on the insert door (#14095), the line still + // [commit 9d7f7259f] …and, as on the insert door (#14095), the line still // carries what the DATABASE said now that the caller receives an // envelope: the platform logger serializes `message` and `stack` // only, so logging the envelope would silently drop the failing @@ -16372,7 +16372,7 @@ export class ObjectQL implements IObjectQLEngine { // — same trust model as `__expandRead`), so it cannot be forged from // a request to bypass the guard on an ordinary write. // - // [#13644] This same marker is what `update()`'s hook-context + // [commit 34ce8e7db] This same marker is what `update()`'s hook-context // assembly projects onto the DECLARED `HookContext. // referentialFieldClear` (see buildReferentialFieldClear), so an // app guard can recognise the cleanup without reading an @@ -18227,10 +18227,10 @@ export class ObjectRepository implements IScopedObjectRepository { } /** - * [#16786] Declared `Promise | null>`, not `Promise`. + * [commit 5c8f5af50] Declared `Promise | null>`, not `Promise`. * * `IScopedObjectRepository.findOne` has declared that shape since #16231's - * ruling A landed (PR #16783), and `IDataEngine.findOne` — the call this + * ruling A landed (commit 854639b31), and `IDataEngine.findOne` — the call this * method forwards to, one line down — declares it too. This method sat * between two narrow declarations and re-widened the value back to `any` on * the way out, so `implements IScopedObjectRepository` stayed satisfied (a @@ -18261,7 +18261,7 @@ export class ObjectRepository implements IScopedObjectRepository { } /** - * [#16786] Declared `Promise | number | null>`, the same + * [commit 5c8f5af50] Declared `Promise | number | null>`, the same * re-widening as {@link findOne} and repaired the same way: the record for * the single-record form, the affected-row count for the predicate form * (`{ where, multi: true }`), `null` when the write matched nothing. @@ -18269,7 +18269,7 @@ export class ObjectRepository implements IScopedObjectRepository { * ⛔ `updateById` is deliberately NOT touched here. Its `Promise` is * what `IScopedObjectRepository.updateById` itself declares, so the class * matches its contract and there is no drift to repair on this side; that - * member is `packages/spec`'s to narrow and stays open on #16786. + * member is `packages/spec`'s to narrow (its spec half: commit 6059b29c0). */ async update(data: any, options: any = {}): Promise | number | null> { return this.engine.update(this.objectName, data, { diff --git a/packages/objectql/src/find-hook-result-shape.ts b/packages/objectql/src/find-hook-result-shape.ts index 89c7f11fcc6..a2d5eff3c83 100644 --- a/packages/objectql/src/find-hook-result-shape.ts +++ b/packages/objectql/src/find-hook-result-shape.ts @@ -27,7 +27,7 @@ * * The fork was real and pointed both ways — either the engine guarantees the * array, or `find()`'s declaration is wrong and the ~70 array-or-envelope - * normalizer limbs the #15094 census counted are load-bearing rather than dead. + * normalizer limbs a census counted (commit 901773b21 records its band) are load-bearing rather than dead. * The maintainer ruled the first (2026-09-06): the protocol is the baseline and * the declaration IS the contract, so the seam that can break it is closed * rather than the contract widened. `packages/spec/src/data/hook.zod.ts` backs diff --git a/packages/objectql/src/hook-exclude-objects.test.ts b/packages/objectql/src/hook-exclude-objects.test.ts index a71258ef332..de5d4060684 100644 --- a/packages/objectql/src/hook-exclude-objects.test.ts +++ b/packages/objectql/src/hook-exclude-objects.test.ts @@ -35,7 +35,7 @@ * 3. the two refused EXCLUSION shapes (`''`/`['']`, `'*'`), following #4281's * ruling on empty hook targets, plus the `[]` that is deliberately accepted * on that face; - * 3b. [#6573] the refused ALLOW shapes — `''`, `[]`, `['']` — and the scope + * 3b. [commit 708431313] the refused ALLOW shapes — `''`, `[]`, `['']` — and the scope * whose two faces cancel out. #4281 closed these on the metadata path only; * `registerHook` is the code path it never reached. Refused at the door, * with `hookMatchesObject`'s reading left deliberately unchanged; @@ -217,7 +217,7 @@ describe('[#5928] refused exclusion faces (#4281 / ADR-0078 lineage)', () => { }); /* - * ── [#6573] The allow face gets #4281's door too ──────────────────────────── + * ── [commit 708431313] The allow face gets #4281's door too ──────────────────────────── * * #4281 ("an empty target is not *no* target") was closed in two places, both * on the METADATA path: `HookSchema.object`'s refine in `packages/spec`, and @@ -413,7 +413,7 @@ describe('[#5928] property: hasHooksFor is never tighter than triggerHooks', () { object: '*', excludeObjects: ['account', 'sys_job'] }, { object: ['account', 'contact'], excludeObjects: 'contact' }, // `{ object: ['account','contact'], excludeObjects: ['account','contact'] }` - // used to sit here. #6573 refuses a fully-cancelled scope at registration, + // used to sit here. Commit 708431313 refuses a fully-cancelled scope at registration, // so it can no longer be registered at all — and a scope that cannot exist // cannot violate the gate/dispatch property. Its refusal is pinned below. { object: 'account', excludeObjects: 'lead' }, @@ -498,14 +498,14 @@ describe('[#5928] hookMatchesObject — the one shared rule', () => { }); it("keeps the truthiness read of `object: ''` — #6573 closed the door, not the matcher", () => { - // #5928 pinned this reading as preserved-not-endorsed and filed #6573. - // #6573's ruling: refuse `''` at REGISTRATION, and leave this read alone — + // #5928 pinned this reading as preserved-not-endorsed and filed the card commit 708431313 closed. + // The decision commit 708431313 records: refuse `''` at REGISTRATION, and leave this read alone — // flipping it would silently convert a fires-on-everything hook into a // fires-on-nothing one, the same defect pointing the other way. So the // matcher still answers "global" for a hand-built entry... expect(hookMatchesObject({ object: '' }, 'account')).toBe(true); // ...and no live entry can carry `''`, because registration refuses it. - // (The refusal itself is pinned in the #6573 block below.) + // (The refusal itself is pinned in the commit 708431313 block below.) const engine = makeEngine(); expect(() => register(engine, 'blank', { object: '' })).toThrow(); }); diff --git a/packages/objectql/src/hook-withheld-readonly-fault.test.ts b/packages/objectql/src/hook-withheld-readonly-fault.test.ts index 823da17ed67..aa6a38b3e44 100644 --- a/packages/objectql/src/hook-withheld-readonly-fault.test.ts +++ b/packages/objectql/src/hook-withheld-readonly-fault.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#17219] The composer's contract, at the seam rather than through a driver. + * [commit 706ad0fcc] The composer's contract, at the seam rather than through a driver. * * The three DECLINE conditions carry as much weight as the accept case, and for * the reason the card is about: a diagnostic that fires on the wrong error is diff --git a/packages/objectql/src/hook-withheld-readonly-fault.ts b/packages/objectql/src/hook-withheld-readonly-fault.ts index 4fac03314cf..691abb0972a 100644 --- a/packages/objectql/src/hook-withheld-readonly-fault.ts +++ b/packages/objectql/src/hook-withheld-readonly-fault.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#17219] Name the withheld key when a `before*` hook faults reaching THROUGH + * [commit 706ad0fcc] Name the withheld key when a `before*` hook faults reaching THROUGH * one — instead of letting the platform's own contract enforcement surface as * the author's crash. * @@ -46,7 +46,7 @@ * ⛔ Not by marshalling `ctx.submitted` onto the sandbox face: that face is * assembled key by key, `dispatch.scope` is the standing precedent for the * assembly discipline, and the shape was measured and refused on its merits in - * PR #17195. Nothing here adds a key to any authoring face or to any wire + * commit d2c1d1980. Nothing here adds a key to any authoring face or to any wire * payload. * * ## The classification this restores diff --git a/packages/objectql/src/in-memory-aggregation.ts b/packages/objectql/src/in-memory-aggregation.ts index c65412761a9..0f76950de77 100644 --- a/packages/objectql/src/in-memory-aggregation.ts +++ b/packages/objectql/src/in-memory-aggregation.ts @@ -282,7 +282,7 @@ function aggregateBucket( // booleans aggregate as NUMBERS on every face, with no per-aggregate // exception, so the order statistics answer in the same numeric domain // `sum`/`avg` already answer in (`toNumber`, `Number(true) === 1`). The - // coercion is BOOLEAN-ONLY, exactly like driver-memory's (#11065): + // coercion is BOOLEAN-ONLY, exactly like driver-memory's (commit 20950404c): // strings, dates and numbers reach the same raw comparison they always // did — widening it would change `min` over a text column. case 'min': { diff --git a/packages/objectql/src/lifecycle/lifecycle-service.test.ts b/packages/objectql/src/lifecycle/lifecycle-service.test.ts index 4c9d58a323f..7ca7213ee6f 100644 --- a/packages/objectql/src/lifecycle/lifecycle-service.test.ts +++ b/packages/objectql/src/lifecycle/lifecycle-service.test.ts @@ -764,7 +764,7 @@ describe('LifecycleService.sweep — unguarded reap batching (#5194)', () => { }); it('ttl.onlyWhen {$null: true} spares tombstones and still reaps ordinary expired rows (#10165)', async () => { - // The #10165 acceptance criterion, both halves, against rows that really + // The acceptance criterion behind commit 801296050, both halves, against rows that really // disappear. A sys_session tombstone BACKDATES expires_at (#7732 stamps // `now - 1000`), so it looks maximally expired — without the filter it is // reaped first and hardest. Predicate-honouring store: the exclusion below @@ -981,7 +981,7 @@ describe('LifecycleService.sweep — Archiver (P3)', () => { }); /* ------------------------------------------------------------------ * - * [#10347] The Archiver honours a declared `ttl`. + * [commit 530c1df65] The Archiver honours a declared `ttl`. * * The property under test is "the declared ttl cutoff GOVERNED which rows * moved", and it is invisible to a suite that only asserts rows were @@ -1145,7 +1145,7 @@ describe('LifecycleService.sweep — Archiver (P3)', () => { }); /* ==================================================================== * - * [#10528] The Archiver resolves its window through ADR-0057 P4 + * [commit 7d483e1e5] The Archiver resolves its window through ADR-0057 P4 * governance — the same `effectiveWindowMs` resolver the Reaper uses. * * Before this card the three legs below were not "partly wired", they were @@ -1189,7 +1189,7 @@ describe('LifecycleService.sweep — Archiver governance (#10528)', () => { } as any, }; - /** `ttl` + `archive` (no `retention`) — the pair #10347 made executable. + /** `ttl` + `archive` (no `retention`) — the pair commit 530c1df65 made executable. * Its due window is `ttl.expireAfter` on `ttl.field`, so the governance * key that governs it is `expireAfter`, not `maxAge`. */ const TTL_ARCHIVE_OBJ: LifecycleObjectLike = { @@ -1452,7 +1452,7 @@ describe('LifecycleService.sweep — Archiver governance (#10528)', () => { it('DEFECT CONTROL (override): with ttl declared it is `expireAfter` that governs — on the ttl field', async () => { // Which override key applies follows which window SELECTION picks - // (#10347). A fix that always consulted `maxAge` would leave this red. + // (commit 530c1df65). A fix that always consulted `maxAge` would leave this red. const stores = governedStores({ sys_audit_log: [ { id: 'expired-400d', created_at: at(-2 * DAY), expires_at: at(-400 * DAY), organization_id: null }, diff --git a/packages/objectql/src/lifecycle/lifecycle-service.ts b/packages/objectql/src/lifecycle/lifecycle-service.ts index 789a83f1759..34b1dd7989b 100644 --- a/packages/objectql/src/lifecycle/lifecycle-service.ts +++ b/packages/objectql/src/lifecycle/lifecycle-service.ts @@ -22,7 +22,7 @@ import type { * rotation falls back to an age-based reap bounded by `shards × unit`. * - **Archiver** (P3): copies audit-class cold rows to the declared archive * datasource, then deletes them from the hot store. Cold is `created_at` - * past `archive.after`, or [#10347] `ttl.field` past `ttl.expireAfter` + * past `archive.after`, or [commit 530c1df65] `ttl.field` past `ttl.expireAfter` * when the object declares a `ttl` beside its `archive`. **Safety rule:** an * object that declares `archive` is never hot-deleted unless the archive * copy succeeded — a compliance ledger must not be dropped unarchived. @@ -109,7 +109,7 @@ export interface LifecycleObjectLike { lifecycle?: Lifecycle; fields?: Record; /** - * [#16729] The object's tenancy posture, DECLARED here because the Archiver + * [commit 0f38ab084] The object's tenancy posture, DECLARED here because the Archiver * hands this very object to a driver that reads the key * (`cold.syncSchema(object, obj)` below), and every driver resolves a * uniqueness partition from it: `tenancy.enabled: false` means one row per @@ -122,7 +122,7 @@ export interface LifecycleObjectLike { * `tenancy` and therefore omits it. The object then reaches `syncSchema` as * the `{ name, fields }` shape, which is exactly the partial re-registration * `SqlDriver.computeAndRecordTenantField`'s sticky record exists to survive. - * Declaring the key is the same correction #16711 made where the shard leaf + * Declaring the key is the same correction commit 7862fb711 made where the shard leaf * narrowed `indexes` and `tenancy` off the object it was handed: a type must * not refuse a key the code below it reads. */ @@ -1005,7 +1005,7 @@ export class LifecycleService { // store; when the archive datasource isn't registered, rows are retained // (never dropped unarchived) and the object is reported as skipped. // - // [#10347] This return is not a policy DROP. A lifecycle may declare `ttl` + // [commit 530c1df65] This return is not a policy DROP. A lifecycle may declare `ttl` // beside `archive` — that pair parses — and until this card the ttl branch // below was simply unreachable for it, so the declared per-row expiry never // ran anywhere. {@link archiveObject} now applies that window itself (see @@ -1028,7 +1028,7 @@ export class LifecycleService { 'global', report, ); - // [#10165] `ttl.onlyWhen` rides the same argument `retention.onlyWhen` + // [commit 801296050] `ttl.onlyWhen` rides the same argument `retention.onlyWhen` // does below — one reap path, one scope spread (see `reap()`'s `scope`). outcomes.push(await this.reap(engine, object, lc, 'ttl', lc.ttl.field, windowMs, report, lc.ttl.onlyWhen)); } @@ -1225,7 +1225,7 @@ export class LifecycleService { /** * Archiver (ADR-0057 §3.3 / P3): copy rows past `archive.after` from the * hot store to the archive datasource, then delete the copied rows hot. - * [#10347] When the object ALSO declares `ttl`, the declared per-row expiry + * [commit 530c1df65] When the object ALSO declares `ttl`, the declared per-row expiry * is what selects candidates — `ttl.field` past its `expireAfter` window — * instead of `created_at` past `archive.after`. * Batched (500 × 20 per sweep) so a large backlog drains across sweeps @@ -1262,7 +1262,7 @@ export class LifecycleService { await cold.syncSchema(object, obj); } - // [#10347] WHICH ROWS ARE DUE. `archive` alone moves rows by age from + // [commit 530c1df65] WHICH ROWS ARE DUE. `archive` alone moves rows by age from // `created_at`, bounded by `archive.after` — unchanged. But a lifecycle may // also declare `ttl` beside `archive`: ADR-0057 §3.5's refine is satisfied // (`ttl` IS a bounding policy) and the `archive.after === retention.maxAge` @@ -1290,8 +1290,8 @@ export class LifecycleService { // author has not decided yet — against the retain-first posture that makes // this method refuse to hot-delete anything the cold store has not taken. // - // [#10643] `retention` declared beside `ttl` + `archive`: once an open - // question at this line (#10527), since decided — and decided at parse + // [commit 5649efbf9] `retention` declared beside `ttl` + `archive`: once an open + // question at this line, since decided by that commit — and decided at parse // time rather than here. `LifecycleSchema` (`packages/spec`, the // superRefine on the lifecycle block) refuses that triple unless the ttl // restates the age bound exactly: `ttl.field` must be `created_at` and @@ -1309,10 +1309,10 @@ export class LifecycleService { // straight back on this line, so it is not a spec-local change. Which // WINDOW governs is a separate leg either way: with `ttl` declared it is // the `expireAfter` override key that applies, not `maxAge` (see the - // #10528 block below). + // commit 7d483e1e5 block below). const dueField = lc.ttl ? lc.ttl.field : 'created_at'; - // [#10528] WHICH WINDOW IS DUE — resolved through ADR-0057 P4 governance, + // [commit 7d483e1e5] WHICH WINDOW IS DUE — resolved through ADR-0057 P4 governance, // the same {@link effectiveWindowMs} every window on the reap path goes // through. Until this card the cutoff below was read straight off the // declaration, and that was not one forgotten call: `reapObject` RETURNS @@ -1325,7 +1325,7 @@ export class LifecycleService { // // Resolved HERE rather than in `reapObject` before it delegates, because // the selection above is what decides WHICH window is governed and that - // decision lives in this method by the 2026-08-20 ruling (#10347). + // decision lives in this method by the 2026-08-20 ruling (commit 530c1df65). // Resolving in the caller would mean either duplicating the selection or // splitting one decision across two methods — and the per-tenant leg is a // pass over this method's own hot/cold batch loop, which cannot leave it @@ -1411,7 +1411,7 @@ export class LifecycleService { return moved; }; - // [#10528] Per-tenant windows (ADR-0057 §3.2), in the shape `reap()` uses: + // [commit 7d483e1e5] Per-tenant windows (ADR-0057 §3.2), in the shape `reap()` uses: // each overriding tenant gets its own cutoff on its own rows, then one // global pass covers everyone else INCLUDING rows with no organization — // a bare `$nin` would silently skip NULL-org rows, since a value that is @@ -1458,7 +1458,7 @@ export class LifecycleService { // Cold-side retention: `keep` bounds the archive itself. // - // [#10528] Governance deliberately does NOT reach this line. `keep` bounds + // [commit 7d483e1e5] Governance deliberately does NOT reach this line. `keep` bounds // the ARCHIVE — how long cold rows survive — not which hot rows are due, // and the `lifecycle` settings namespace has no key for it // (`retention_overrides` carries `maxAge` / `expireAfter` only). It also @@ -1504,7 +1504,7 @@ export class LifecycleService { const tenantWindows = (this.governance.tenantOverrides.get(object) ?? []).filter( (t) => typeof t[overrideKey] === 'string', ); - // `retention.onlyWhen` / `ttl.onlyWhen` [#10165] narrow every delete to + // `retention.onlyWhen` / `ttl.onlyWhen` [commit 801296050] narrow every delete to // the declared row filter — rows outside it (live workflow state, audit // tombstones) are retained regardless of age/expiry. const scope = onlyWhen ?? {}; diff --git a/packages/objectql/src/metadata-facade.test.ts b/packages/objectql/src/metadata-facade.test.ts index f8b2957d0dc..75deb4146f9 100644 --- a/packages/objectql/src/metadata-facade.test.ts +++ b/packages/objectql/src/metadata-facade.test.ts @@ -51,7 +51,7 @@ describe('MetadataFacade provenance passthrough', () => { // getItem('object', …) routes to the merged-object path, so read the // generic collection directly to inspect what register() stored. // - // [#6725] The direct read is STILL the right instrument here, and for + // [commit 1507ba356] The direct read is STILL the right instrument here, and for // the same reason as before: this pin is about the STORED document, and // the two object reads answer the contributor copy — which now exists, // and which deliberately does carry the `'sys_metadata'` sentinel (see @@ -87,7 +87,7 @@ describe('MetadataFacade provenance passthrough', () => { }); /** - * [#6725] The write/read pin. + * [commit 1507ba356] The write/read pin. * * `MetadataFacade.register('object', …)` wrote through `registerItem` into the * generic `metadata` map, while every one of this class's object reads resolves @@ -98,7 +98,7 @@ describe('MetadataFacade provenance passthrough', () => { * `register('object', …)` through both members; this file is the gate for the * facade's half of that. * - * Refs #6725, #6505 / PR #6723, #6808, ADR-0010, ADR-0029. + * Refs commit 1507ba356, #6505 / commit 8ad609c69, #6808, ADR-0010, ADR-0029. */ describe('MetadataFacade object write/read round-trip', () => { let registry: SchemaRegistry; @@ -147,7 +147,7 @@ describe('MetadataFacade object write/read round-trip', () => { }); it('serves the runtime-effective object, as the contract says it does', async () => { - // #6505 / PR #6723: `getObject` answers the object as the engine runs + // #6505 / commit 8ad609c69: `getObject` answers the object as the engine runs // it, not the document its author wrote. The materialization seam is // `registerObject`'s, so it only runs now that the write reaches it. const multiTenantRegistry = new SchemaRegistry({ multiTenant: true }); diff --git a/packages/objectql/src/metadata-facade.ts b/packages/objectql/src/metadata-facade.ts index 082ea91ed1f..012a16b98db 100644 --- a/packages/objectql/src/metadata-facade.ts +++ b/packages/objectql/src/metadata-facade.ts @@ -14,7 +14,7 @@ import { SchemaRegistry } from './registry.js'; * never reaches this predicate — `'objects'` arrives here as `'object'`. * `SchemaRegistry.getItem` / `listItems` still special-case BOTH spellings to * the contributor path (their own callers are not all folded), which is the - * read-side alias #6725's write fix had to match; the fold upstream makes the + * read-side alias commit 1507ba356's write fix had to match; the fold upstream makes the * two layers agree instead of merely overlapping. */ function isObjectType(type: string): boolean { @@ -124,7 +124,7 @@ export class MetadataFacade { } /** - * [#6725] An `object` lives in TWO places in a `SchemaRegistry`, and this + * [commit 1507ba356] An `object` lives in TWO places in a `SchemaRegistry`, and this * write has to reach both of them. * * `SchemaRegistry.unregisterObject`'s header states the invariant directly: @@ -260,7 +260,7 @@ export class MetadataFacade { /** * Unregister a metadata item * - * [#6725] An object leaves both places it was written into, for the same + * [commit 1507ba356] An object leaves both places it was written into, for the same * reason {@link register} writes both: `unregisterItem` only empties the * generic `metadata` map, which no object read consults. Removing one half is * the exact shape of #6808 — the row was gone and `metadata['object']` was diff --git a/packages/objectql/src/metadata-service-getobject-equivalence.test.ts b/packages/objectql/src/metadata-service-getobject-equivalence.test.ts index 984c90a8b9d..148e532cbe4 100644 --- a/packages/objectql/src/metadata-service-getobject-equivalence.test.ts +++ b/packages/objectql/src/metadata-service-getobject-equivalence.test.ts @@ -1,11 +1,11 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. /** - * Conformance pin — `getObject(name)` ≡ `get('object', name)` (#6745). + * Conformance pin — `getObject(name)` ≡ `get('object', name)` (commit 7a5ef0008). * * `IMetadataService.getObject` (`packages/spec/src/contracts/metadata-service.ts`) * DECLARES that the pair resolves through one lookup in every implementation this - * repo ships, and that both members hand back the identical object. PR #6723 (for + * repo ships, and that both members hand back the identical object. commit 8ad609c69 (for * #6505) wrote that down after measuring it with a throwaway probe, which left the * statement declared-but-ungated: nothing failed if a later edit made the pair * diverge, and the contract TSDoc would then simply be lying. This file is the gate. @@ -26,7 +26,7 @@ * `registry.getObject`). An object written the first way was readable back * through neither member — measured, both `undefined` — so a pin seeded that * way would have compared `undefined` to `undefined` and called it - * equivalence. #6725 has since closed that split (`facade.register('object', + * equivalence. Commit 1507ba356 has since closed that split (`facade.register('object', * …)` performs the contributor write too, and pins the round-trip in * `metadata-facade.test.ts`), so either seeding would work here now; this one * is kept because it seeds the registry directly, the way a registry-backed @@ -48,7 +48,7 @@ * converge on `SchemaRegistry.getObject`, whose merge result is memoized in * `mergedObjectCache`, so both members hand back the same instance. * - * Refs #6745, #6505, PR #6723, #6725. + * Refs #6505; commits 7a5ef0008 (the getObject pin), 8ad609c69 (getObject's declared answer), 1507ba356 (the facade split fix). */ import { describe, it, expect } from 'vitest'; @@ -167,7 +167,7 @@ const IMPLEMENTATIONS: readonly PinnedImplementation[] = [ for (const object of objects) { // Seeded on the registry, not through `facade.register('object', …)` // — see the header. That write reached neither object read until - // #6725 closed the split; it now would, but this seeding is the + // commit 1507ba356 closed the split; it now would, but this seeding is the // one a registry-backed host actually performs. registry.registerObject(object.definition as never, 'com.example.pin'); } diff --git a/packages/objectql/src/metadata-service-roundtrip-conformance.test.ts b/packages/objectql/src/metadata-service-roundtrip-conformance.test.ts index 52df7424d5a..bcaed2d4fee 100644 --- a/packages/objectql/src/metadata-service-roundtrip-conformance.test.ts +++ b/packages/objectql/src/metadata-service-roundtrip-conformance.test.ts @@ -14,7 +14,7 @@ * three implementations at once: it depends on `@objectstack/metadata` * (`MetadataManager`) and `@objectstack/core` (`createMemoryMetadata`) and owns * `MetadataFacade`. That is the same argument - * `metadata-service-getobject-equivalence.test.ts` (#6745) already makes for + * `metadata-service-getobject-equivalence.test.ts` (commit 7a5ef0008) already makes for * living here, and it is why `packages/spec` cannot host this half. * * ## The four subjects, and why four for three implementations @@ -38,7 +38,7 @@ * full verbatim ruling text and the row-2 convergence rationale (the * direction is `check:meta-type-normalized`'s: normalize once at the entry, * decide on the normalized value — the gate's header carries - * #3984/#5881/#6241). + * #3984, #5881 and the third bypass, fixed in commit 83a3b1f2e). * * The shared table states the same ruling as `expected` answers — `refused` * rows carry the ADR-0112 envelope contract, the plural row is `readable` @@ -65,7 +65,7 @@ * drifted off a decided contract, and the fix belongs in the implementation; * update the pin only in the PR that changes the ruling. * - * Refs #7223, #7378, #6725, PR #7211, #6745. + * Refs #7223, #7378; commits 1507ba356 (the facade split fix, PR #7211), 7a5ef0008 (the getObject pin). */ import { describe, it, expect } from 'vitest'; diff --git a/packages/objectql/src/metadata-validation-sweep.test.ts b/packages/objectql/src/metadata-validation-sweep.test.ts index a9f40f14c53..e4364c98c6a 100644 --- a/packages/objectql/src/metadata-validation-sweep.test.ts +++ b/packages/objectql/src/metadata-validation-sweep.test.ts @@ -18,7 +18,7 @@ * Types without a Zod schema in the central registry (today only * `rag_pipeline` among the URL-map kinds — `theme`/`webhook` and their * siblings all resolve schemas via `UNREGISTERED_KIND_SCHEMAS` since - * #6245/#10194) are still expected to pass through unvalidated — that is + * #6245 / commit 2306a765c) are still expected to pass through unvalidated — that is * the documented fall-through, not a regression. We pin it explicitly so any * future coverage gap is visible in the report. * @@ -195,7 +195,7 @@ const FIXTURES: Record = { app: { valid: { name: 'sweep_app', label: 'Sweep' }, // The invalid probe breaks `label`, not `name`: an ungrammatical item - // name is refused by the #12194 grammar door (INVALID_REQUEST 400) + // name is refused by the grammar door (commit 311433f6b, INVALID_REQUEST 400) // BEFORE the central Zod registry runs, so a bad name can no longer // prove the schema gate this sweep exists to prove. The name-grammar // refusal has its own pins in metadata-protocol. diff --git a/packages/objectql/src/overlay-precedence.test.ts b/packages/objectql/src/overlay-precedence.test.ts index 7f2f04c7daf..0bbd9f1876b 100644 --- a/packages/objectql/src/overlay-precedence.test.ts +++ b/packages/objectql/src/overlay-precedence.test.ts @@ -403,7 +403,7 @@ describe('overlay whitelist enforcement (shared-DB invariant)', () => { // allowOrgOverride:false (no per-org agent fork). The kernel ships // exactly two platform agents; tenants extend via skills + tools. expect(allowedFromRegistry.has('agent')).toBe(false); - // #6483 — `permission`/`position` rolled BACK to + // Commit ee58392e1 — `permission`/`position` rolled BACK to // allowOrgOverride:false (with page/app/action/dataset/book/ // tool/skill; the whole nine-type divergence family). ADR-0005's // security row has always said ❌: "Authorization correctness; diff --git a/packages/objectql/src/plugin-governance-scoped-metadata.test.ts b/packages/objectql/src/plugin-governance-scoped-metadata.test.ts index 8a895bb8dc9..a2ef259f546 100644 --- a/packages/objectql/src/plugin-governance-scoped-metadata.test.ts +++ b/packages/objectql/src/plugin-governance-scoped-metadata.test.ts @@ -2,7 +2,7 @@ /** * [#15252] The boot-time action-governance audit reaches a SCOPED metadata - * service — the C4 cell #14423's ruling left open. + * service — the C4 cell commit a56baa2bd left open. * * ## What was broken * diff --git a/packages/objectql/src/plugin.ts b/packages/objectql/src/plugin.ts index b5e39e9cd0a..f2969e51e7e 100644 --- a/packages/objectql/src/plugin.ts +++ b/packages/objectql/src/plugin.ts @@ -1540,7 +1540,7 @@ export class ObjectQLPlugin implements Plugin { * hides all of it behind a dialect-local bind-safety net, which is why the * SQLite/Turso suites never saw it. * - * The split is the same ruling #7737/#10629 made for federated objects — + * The split is the same ruling #7737 made for federated objects (commit 199ec4712) — * that flag is about DDL, and a binding that is DDL-free must not ride on it * — applied to the managed ones. */ @@ -2634,14 +2634,14 @@ export class ObjectQLPlugin implements Plugin { if (meta && typeof loadMany === 'function') { loadStandaloneActions = () => loadMany.call(meta, 'action'); } - // [#14423] The KEYED plural read, preferred over `loadMany` — see + // [commit a56baa2bd] The KEYED plural read, preferred over `loadMany` — see // `collectEngineActionDeclarations`. A plane that predates it (or a test // double) simply does not offer it and the unkeyed read above stands. const loadManyKeyed = meta?.loadManyKeyed; if (meta && typeof loadManyKeyed === 'function') { loadStandaloneActionsKeyed = () => loadManyKeyed.call(meta, 'action'); } - // [#14423] The router's THIRD rung, injected the same way its second one + // [commit a56baa2bd] The router's THIRD rung, injected the same way its second one // is. `resolveRouteActionDeclaration` prefers `loadDiagnosed` and falls // back to `load`; this mirrors that branch and unwraps, so the audit // receives a declaration-or-nothing exactly like `lookupRegistryAction`. diff --git a/packages/objectql/src/protocol-meta.test.ts b/packages/objectql/src/protocol-meta.test.ts index f62eee1f31f..4d0bb5e4907 100644 --- a/packages/objectql/src/protocol-meta.test.ts +++ b/packages/objectql/src/protocol-meta.test.ts @@ -67,7 +67,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // save stamps `organization_id` on the row — is unchanged, but since // the 2026-08-08 ruling only types that DECLARE a per-org channel may // carry one, and `app` rolled back to `allowOrgOverride: false` in - // #6483. `view` is the whitelisted specimen, so this now measures the + // commit ee58392e1. `view` is the whitelisted specimen, so this now measures the // stamping on a row the platform can actually read back. mockEngine.findOne.mockResolvedValue(null); await protocol.saveMetaItem({ @@ -86,7 +86,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { }), expect.anything()); }); - // [#14770] Re-spelled from `app` to `view`, and its sibling below with + // [commit d5cbb44f3] Re-spelled from `app` to `view`, and its sibling below with // it. The CLAIM is unchanged — an org row and an env-wide row of the // same `(type, name)` both exist, and the org row is the one SERVED, // whole, by precedence rather than a merge. It just has to be measured @@ -95,12 +95,12 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // `getMetaItem` now resolves its own read scope through // `organizationIdForMetaRead` — the read-side twin of the predicate // `saveMetaItem` already gates on — so on `app`, which rolled back to - // `allowOrgOverride: false` in #6483, `organizationId` is gated to + // `allowOrgOverride: false` in commit ee58392e1, `organizationId` is gated to // `undefined` and the org partition is never queried. On `app` this - // case was pinning the phantom read #14770 removes: a pre-#6190 + // case was pinning the phantom read commit d5cbb44f3 removed: a pre-#6190 // org-scoped row served INSTEAD OF the live env-wide document. `view` // is the whitelisted specimen — the same re-spelling #6190 made one - // case up and #14683 made one case down. + // case up and commit 96326040f made one case down. it('getMetaItem returns org-specific overlay when both org and env-wide rows exist', async () => { // findOverlay calls: first attempts org=org_alpha (returns row), // env-wide fallback should be skipped. @@ -149,7 +149,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // ⚠️ NON-VACUITY, and the reason this case had to move too. A // fall-through only states something if the org partition was // actually read FIRST. Left on `app` this case kept passing after - // #14770 while measuring nothing at all: the gate resolves `app` to + // commit d5cbb44f3 while measuring nothing at all: the gate resolves `app` to // `undefined`, so the only read ever issued was the env-wide one and // the assertion could no longer fail. expect(mockEngine.findOne).toHaveBeenCalledWith('sys_metadata', { @@ -157,28 +157,28 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { }); }); - // [#14683] Re-spelled from `app` to `view`, the READ-side twin of the + // [commit 96326040f] Re-spelled from `app` to `view`, the READ-side twin of the // `[#6190]` re-spelling three cases up — same reason, one verb over. // `getMetaItems` now resolves its own read scope through // `organizationIdForMetaRead`, so an `organizationId` handed in for a // type the registry declares NON-overridable is gated to `undefined` // and the org partition is never queried. `app` rolled back to - // `allowOrgOverride: false` in #6483, so on `app` this case was + // `allowOrgOverride: false` in commit ee58392e1, so on `app` this case was // asserting a union the platform must NOT perform: the org rows it // seeded are the pre-#6190 phantoms `loadMetaFromDb` walks past, and - // reading them back is the resurrection #14683 closes. + // reading them back is the resurrection commit 96326040f closed. // // The CLAIM is unchanged and is what this case still pins — env-wide // and org rows union, org winning on collision. It just has to be // measured on a type that has an org partition to union. // - // ⚠️ SUPERSEDED, 2026-09-03 (#14770). This paragraph used to read "Its + // ⚠️ SUPERSEDED, 2026-09-03 (commit d5cbb44f3). This paragraph used to read "Its // two `getMetaItem` (SINGULAR) siblings above keep `app` deliberately: - // that verb is untouched here." That was true when #14683 landed and is - // the sentence #14770 falsified: the singular verb now gates too, so + // that verb is untouched here." That was true when commit 96326040f landed and is + // the sentence commit d5cbb44f3 falsified: the singular verb now gates too, so // both siblings moved to `view` in the same edit. The reasoning it gave // — a singular caller CAN be right about its scope, and its REST door - // already gates — held for the DOOR and not for the VERB: `#14770` + // already gates — held for the DOOR and not for the VERB: commit d5cbb44f3 // measured four runtime callers that reach the verb with a raw active // organization, and on a `??` precedence read an ungated organization // does not merely ADD a row, it SUBSTITUTES the served document. @@ -280,7 +280,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { }); describe('saveMetaItem', () => { - // [#8818] WAS `rejects.toThrow('Item data is required')` — a bare + // [commit fd6bdf89f] WAS `rejects.toThrow('Item data is required')` — a bare // message match that stayed green while the refusal declared no // ADR-0112 envelope at all, so `clientFacingFailureText` withheld the // sentence and the REST boundary served `500 INTERNAL_ERROR`. The @@ -415,7 +415,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // given, and `sampleApp` is shared by every case in this file. registry.registerItem('app', { ...sampleApp }, 'name', 'com.acme.showcase'); - // #6483 rolled `app`'s `allowOrgOverride` back to `false` + // Commit ee58392e1 rolled `app`'s `allowOrgOverride` back to `false` // (ADR-0005 table: ❌ for page/app/action), so overriding this // packaged app needs the one documented door that remains — the // `OS_METADATA_WRITABLE` operator escape hatch. The receipt @@ -666,7 +666,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // Every overlay-allowed built-in type now has a canonical Zod // schema registered in `getMetadataTypeSchema()`. The probe // breaks `label`, not `name`: an ungrammatical item name is - // refused by the #12194 grammar door (INVALID_REQUEST 400) + // refused by the grammar door (commit 311433f6b, INVALID_REQUEST 400) // before the registry runs, so a bad name can no longer reach // — and therefore cannot prove — the schema gate under test. let caught: any; @@ -1634,7 +1634,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // here it would have flipped this test red for a reason that has // nothing to do with what it proves. // - // [#10194] `theme` left it by exactly the webhook rule: it gained a + // [commit 2306a765c] `theme` left it by exactly the webhook rule: it gained a // SCHEMA (not a registry entry), and the old specimen body // (`tokens: {}` — an alias of `customVars`, with the required `colors` // missing) is spec-INVALID and now 422s. `analytics_cube` was bound in @@ -1644,7 +1644,7 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { // no-schema fall-through control below. Each newly-bound type's own // behaviour, door and 422 both, is pinned in the tests below. // - // [#10485] `theme` then left the CONTRACT ITSELF (ADR-0049 — the + // [commit 35ad101bc] `theme` then left the CONTRACT ITSELF (ADR-0049 — the // `themes` carrier and `ThemeSchema` retired; the `themes: 'theme'` // fold left `PLURAL_TO_SINGULAR`), so it is no longer a URL-map-only // kind at all: both halves of its old pair now earn the #8421 @@ -1843,14 +1843,14 @@ describe('ObjectStackProtocolImplementation - Metadata Persistence', () => { }); // ─────────────────────────────────────────────────────────────── - // [#10194] `theme` / `analytics_cube` — the two doors #6245 left + // [commit 2306a765c] `theme` / `analytics_cube` — the two doors #6245 left // open, closed the same way and pinned the same way: the write door // is UNCHANGED (no-static-entry authorization fall-through, verdict // byte-identical), the shape check is new. Both halves per type, so a // change that quietly CLOSED the door fails the "accepts" half. // ─────────────────────────────────────────────────────────────── - // [#10485] `theme` left this pair: the carrier retired out of the + // [commit 35ad101bc] `theme` left this pair: the carrier retired out of the // spelling contract, so BOTH halves now earn the #8421 unrecognised // refusal before any schema is consulted — pinned once below. The // still-bound `webhook` door keeps the two-halves pin alive for the diff --git a/packages/objectql/src/protocol-org-overlay-registry-gate.test.ts b/packages/objectql/src/protocol-org-overlay-registry-gate.test.ts index fd23a4b18eb..a90c39fcd57 100644 --- a/packages/objectql/src/protocol-org-overlay-registry-gate.test.ts +++ b/packages/objectql/src/protocol-org-overlay-registry-gate.test.ts @@ -168,7 +168,7 @@ describe('#6602 — the premise, read from the registry rather than restated', ( allowOrgOverride: true, }); // `flow` reaches the same seam through the OTHER write tier: not - // per-org overridable (#6283 / PR #6478) but still runtime-creatable, + // per-org overridable (#6283 / commit 474f131cf) but still runtime-creatable, // which is the tier a Studio-authored flow uses. expect(DEFAULT_METADATA_TYPE_REGISTRY.find((e) => e.type === 'flow')).toMatchObject({ allowOrgOverride: false, diff --git a/packages/objectql/src/protocol-recorded-by-null.test.ts b/packages/objectql/src/protocol-recorded-by-null.test.ts index 97f1dbea343..db5916e634b 100644 --- a/packages/objectql/src/protocol-recorded-by-null.test.ts +++ b/packages/objectql/src/protocol-recorded-by-null.test.ts @@ -20,7 +20,7 @@ * matched. With the sentinel gone the ordinary authoring paths must still * pass — that is the regression #4441 was bitten by. * - * [#14535] "The real thing" is a claim about the TARGET KEY too, and it was + * [commit 1aba3159a] "The real thing" is a claim about the TARGET KEY too, and it was * false here until this change. The declaration spelled `referenceTo` — an * alias `FieldSchema` refuses by name (#11567) and `referenceTargetOf`, the * single arbiter the write-path guard resolves through, does not read at all. diff --git a/packages/objectql/src/protocol-registry-shadow.test.ts b/packages/objectql/src/protocol-registry-shadow.test.ts index 5007cd94344..abde1591f61 100644 --- a/packages/objectql/src/protocol-registry-shadow.test.ts +++ b/packages/objectql/src/protocol-registry-shadow.test.ts @@ -190,7 +190,7 @@ function findByName(items: any[], name: string): any { return (items as any[]).find((it) => it?.name === name); } -// #6483 rolled `app`'s `allowOrgOverride` back to `false` (ADR-0005 — the +// Commit ee58392e1 rolled `app`'s `allowOrgOverride` back to `false` (ADR-0005 — the // amendment table says ❌ for `page`/`app`/`action`), so overriding the // PACKAGED app these suites are built around now needs the ONE documented // door that remains: the `OS_METADATA_WRITABLE` operator escape hatch, which @@ -296,7 +296,7 @@ describe('registry shadow — control-plane PUT → GET → DELETE keeps the art }); describe('registry shadow — scoped-kernel lock enforcement is shadow-immune', () => { - // Same #6483 door as above: with `app` no longer allowOrgOverride, the + // Same commit ee58392e1 door as above: with `app` no longer allowOrgOverride, the // save would 403 NOT_OVERRIDABLE at the type gate and never reach the // L3 lock this case exists to prove is shadow-immune. Behind the hatch // the type gate passes and the LOCK is what refuses — the ordering the diff --git a/packages/objectql/src/query-expression-conformance.test.ts b/packages/objectql/src/query-expression-conformance.test.ts index 6751c8fc48b..baee7a054de 100644 --- a/packages/objectql/src/query-expression-conformance.test.ts +++ b/packages/objectql/src/query-expression-conformance.test.ts @@ -1029,7 +1029,7 @@ describe('#4226 — sort / select / expand on the list path (real ObjectQL engin // refused on two axes must not be sent two different ways, which is // exactly how #4256 and #6673 drifted apart in the first place. // - // [#8648] It used to assert only that the four SORT/FILTER doors share + // [commit e5eeb499c] It used to assert only that the four SORT/FILTER doors share // one stem — which left the claim unpinned in the one place where // reading it as word-identity was FALSE. The SEARCH axis cannot match // that stem and never did; measured from the running doors on this @@ -1067,7 +1067,7 @@ describe('#4226 — sort / select / expand on the list path (real ObjectQL engin // actionable. // // ⛔ Unifying the SEARCH wording onto the shared stem is route 3 of - // #8648 and was NOT taken: it changes a shipped error message and + // the card commit e5eeb499c fixed, and was NOT taken: it changes a shipped error message and // needs somewhere for the `text` narrowing to live. Layer 2 is what // makes that a decision someone takes on purpose instead of a silent // edit — if you are here because it went red, that is the pin working. @@ -1114,7 +1114,7 @@ describe('#4226 — sort / select / expand on the list path (real ObjectQL engin emit: () => engine.find('showcase_task', { orderBy: [{ field: 'sort_key', order: 'asc' }] }), }, { - // [#8648] The door the claim was missing. SEARCH has no engine + // [commit e5eeb499c] The door the claim was missing. SEARCH has no engine // twin to pair with: `search` is expanded at ingress into the // `$or` of `$icontains` the engine receives (ADR-0061), so // this axis has exactly one door — which is why "the three @@ -1388,7 +1388,7 @@ describe('#4226 — sort / select / expand on the list path (real ObjectQL engin expect(err.message).toMatch(/ObjectQL\.find\('showcase_task'\)/); expect(err.message).toMatch(/follows the relationship 'project_id' into another object/); // The one-vocabulary discipline, emitted-vs-emitted: both doors close - // with the SAME remedy sentence the #8648 agreement pin protects. + // with the SAME remedy sentence the commit e5eeb499c agreement pin protects. const ingressErr: any = await protocol .findData({ object: 'showcase_task', query: { where: { 'project_id.name': 'Apollo' } } }) .then(() => null, (e: unknown) => e); diff --git a/packages/objectql/src/register-object-authored-shape.pin.ts b/packages/objectql/src/register-object-authored-shape.pin.ts index 9f329be96c8..74da0d31ba2 100644 --- a/packages/objectql/src/register-object-authored-shape.pin.ts +++ b/packages/objectql/src/register-object-authored-shape.pin.ts @@ -4,7 +4,7 @@ * #5543 — compile-time pin for the shape `registerObject` accepts. * * Both doors (`ObjectQL.registerObject` and `SchemaRegistry.registerObject`) - * are annotated `ServiceObject`. Since ADR-0122 phase 2 (#6083) that bare spec + * are annotated `ServiceObject`. Since ADR-0122 phase 2 (commit 53068c130) that bare spec * alias means the **authored** (`z.input`) shape — defaulted keys optional, * pre-transform — which is what the registry actually receives: `registerObject` * runs no `parse`, so nothing on that path materializes a `.default(...)`. diff --git a/packages/objectql/src/registry-artifact-co-ownership.test.ts b/packages/objectql/src/registry-artifact-co-ownership.test.ts index d05f5007d98..55a91323757 100644 --- a/packages/objectql/src/registry-artifact-co-ownership.test.ts +++ b/packages/objectql/src/registry-artifact-co-ownership.test.ts @@ -199,7 +199,7 @@ describe('ADR-0130 D1 + D3 — the gate relaxation and the object-name check are expect(err.namespace).toBe('crm'); expect(err.existingPackageId).toBe('com.acme.crm'); expect(err.incomingPackageId).toBe('com.acme.crm.billing'); - // [#14474] The ADR-0112 envelope, asserted the same way this file already + // [commit df657d9df] The ADR-0112 envelope, asserted the same way this file already // asserts its D3 sibling's (`caught?.code` / `caught?.status` below). The // instance check above is NOT a substitute: it stayed green through every // year this class carried no `code` and no `status` at all, which is diff --git a/packages/objectql/src/registry-cross-package-item-classes.test.ts b/packages/objectql/src/registry-cross-package-item-classes.test.ts index 6ac4d644413..40bdd082804 100644 --- a/packages/objectql/src/registry-cross-package-item-classes.test.ts +++ b/packages/objectql/src/registry-cross-package-item-classes.test.ts @@ -46,7 +46,7 @@ * for all of them, and a single refusal can carry findings from several * classes at once). `ENVELOPE PRESENCE` then asserts the envelope itself, in * one place. Repaired the same way as #14367 (`registerObject`'s bare `Error`) - * and #14474 (`NamespaceConflictError`), one door over. + * and commit df657d9df (`NamespaceConflictError`), one door over. * * ⛔ If `ENVELOPE PRESENCE` below goes red, the envelope has been REMOVED or * its code renamed — a regression, not a cleanup. Restore it rather than diff --git a/packages/objectql/src/registry-namespace-install-gate.test.ts b/packages/objectql/src/registry-namespace-install-gate.test.ts index fe36a63340e..584f3eae2ac 100644 --- a/packages/objectql/src/registry-namespace-install-gate.test.ts +++ b/packages/objectql/src/registry-namespace-install-gate.test.ts @@ -57,7 +57,7 @@ describe('SchemaRegistry — namespace install gate (ADR-0048 Phase 1)', () => { }); it('carries the ADR-0112 envelope: code NAMESPACE_CONFLICT + status 422', () => { - // [#14474] The assertion the instance checks above cannot make, and the + // [commit df657d9df] The assertion the instance checks above cannot make, and the // reason this defect survived: `toThrowError(NamespaceConflictError)` and // `toBeInstanceOf(NamespaceConflictError)` are TRUE of a class carrying no // `code` and no `status`, so both stayed green while `POST /api/v1/packages` diff --git a/packages/objectql/src/registry-ownership-refusal-envelope.test.ts b/packages/objectql/src/registry-ownership-refusal-envelope.test.ts index c155694f22c..1c1fb2a1beb 100644 --- a/packages/objectql/src/registry-ownership-refusal-envelope.test.ts +++ b/packages/objectql/src/registry-ownership-refusal-envelope.test.ts @@ -8,7 +8,7 @@ * * The refusal (ADR-0029 D3, single owner per object name) used to be a bare * `Error`. Measured while reverse-verifying the install-time - * `DUPLICATE_ARTIFACT_OBJECT_NAME` check one layer up (#14163): with that + * `DUPLICATE_ARTIFACT_OBJECT_NAME` check one layer up (ADR-0130 D3, commit 1dcb995f2): with that * check ablated, `expect(refused).toBeDefined()` STAYED GREEN, because this * refusal fired one step later and looked, to a throw-shaped assertion, * exactly like the check that had just been deleted. Only the envelope diff --git a/packages/objectql/src/registry.ts b/packages/objectql/src/registry.ts index bbf2a1b3773..74cf3cdefca 100644 --- a/packages/objectql/src/registry.ts +++ b/packages/objectql/src/registry.ts @@ -16,7 +16,7 @@ import { // from one place. Re-exported below under its original name. ITEM_KEY_DISCRIMINATORS, readDiscriminatorValue as discriminatorValue, - // [#10062] The ADR-0029 D9.6 provenance pair, sunk into metadata-core for the + // [commit fa5d137ab] The ADR-0029 D9.6 provenance pair, sunk into metadata-core for the // same reason as the table above: `@objectstack/service-automation`'s flow // precedence asks the same question ("does a code package ship this name?") // and reached it by importing this package, which it does not declare — so @@ -36,7 +36,7 @@ import { type ObjectFieldTypeRefusal, type ObjectFieldTypeViolation, } from '@objectstack/metadata-core'; -// [#8460] `scalarOverridesPackagedBase` is the #8284 comparison, imported rather +// [ADR-0029 D9.2a] `scalarOverridesPackagedBase` is the #8284 comparison, imported rather // than re-spelled: the object FOLD asks the same question one layer down (has // this scalar been authored away from the packaged default?), and the ruling // required the same mechanism, not a second comparison shape. @@ -171,7 +171,7 @@ export function parseFQN(fqn: string): { namespace: string | undefined; shortNam /** * The three SCALAR props {@link mergeObjectDefinitions} resolves last-writer-wins - * — the exact set the #8284 and #8460 rulings both cover, and the same three + * — the exact set the #8284 ruling and ADR-0029 D9.2a both cover, and the same three * {@link scalarOverridesPackagedBase} answers for. */ const OBJECT_FOLD_SCALAR_KEYS = ['label', 'pluralLabel', 'description'] as const; @@ -220,7 +220,7 @@ type ObjectFoldScalarKey = (typeof OBJECT_FOLD_SCALAR_KEYS)[number]; * priority 140 does not become the base layer") fails if this merge set is * widened to copy it through. * - * [#8460] …the SCALAR override above is conditional. `tenantAuthored` names + * [ADR-0029 D9.2a] …the SCALAR override above is conditional. `tenantAuthored` names * the scalars the fold's BASE has authored away from the packaged owner's * value; an extender yields on those. See * {@link SchemaRegistry.tenantAuthoredScalars} for why the set is computed once @@ -248,7 +248,7 @@ function mergeObjectDefinitions( merged.indexes = [...(base.indexes || []), ...extension.indexes]; } - // Override scalar props (last writer wins) — [#8460] unless the base has been + // Override scalar props (last writer wins) — [ADR-0029 D9.2a] unless the base has been // authored by the tenant, in which case the extender's packaged default yields. const yields = (key: ObjectFoldScalarKey): boolean => tenantAuthored?.has(key) === true; if (extension.label !== undefined && !yields('label')) merged.label = extension.label; @@ -1510,7 +1510,7 @@ export const OBJECT_OWNERSHIP_CONFLICT_CODE = 'OBJECT_OWNERSHIP_CONFLICT' as con * install blow up later at table creation. Shareable platform namespaces * (`base`/`system`/`sys`) are exempt. * - * [#14474] Carries the ADR-0112 envelope (`code` + `status`), like its sibling + * [commit df657d9df] Carries the ADR-0112 envelope (`code` + `status`), like its sibling * {@link ArtifactObjectNameConflictError} below. Unlike that sibling, this * refusal IS reachable from a wire: `POST /api/v1/packages` * (`packages/runtime/src/domains/packages.ts`) calls `installPackage` with no @@ -1727,7 +1727,7 @@ export class ObjectOwnershipConflictError extends Error { } } -// [#10062] `isTenantAuthored` and `isCodeArtifactBody` used to be defined here. +// [commit fa5d137ab] `isTenantAuthored` and `isCodeArtifactBody` used to be defined here. // They now live in `@objectstack/metadata-core` // (`code-artifact-provenance.ts`), imported at the top of this file and // re-exported immediately below, so every caller's spelling — including @@ -2448,7 +2448,7 @@ export class SchemaRegistry { contributors: ObjectContributor[], baseDefinition: ServiceObject, ): ServiceObject { - // [#8460] Computed ONCE, over the base the fold starts from — never + // [ADR-0029 D9.2a] Computed ONCE, over the base the fold starts from — never // re-derived from the running `merged`, which would make an extender's own // scalar look "authored" to the next extender and silently invert // extender-vs-extender precedence (D9.3: declared numbers order peers). @@ -2466,7 +2466,7 @@ export class SchemaRegistry { } /** - * [#8460] Which of the three fold scalars the BASE layer carries a + * [ADR-0029 D9.2a] Which of the three fold scalars the BASE layer carries a * TENANT-AUTHORED value for — i.e. one that no longer equals the packaged * owner's. * @@ -2505,11 +2505,11 @@ export class SchemaRegistry { * {@link getPackagedObjectOwner} — whose extra `isCodeArtifactBody` test * (D9.8) would make this decline to protect a RUNTIME-authored object, i.e. * exactly the object whose owner row the tenant wrote by hand. The two agree - * wherever a packaged owner exists, which is every shape #8460 measured; they + * wherever a packaged owner exists, which is every shape the ADR-0029 D9.2a amendment records; they * differ only on a tenant-authored owner, and there the ruled sentence still * reads the same way — the tenant's own row is the explicit override and a * package's `objectExtensions` entry is the packaged default. The rejected - * alternative is the trap PR #8454 named one layer up, in its own form: + * alternative is the trap commit 427344c26 named one layer up, in its own form: * comparing against a body that already has extenders folded onto it * ({@link resolveOwnerLayer}) would report every extender's scalar as * "unchanged" and yield nothing, ever. diff --git a/packages/objectql/src/scoped-repository-return-narrowing.test.ts b/packages/objectql/src/scoped-repository-return-narrowing.test.ts index 88d269d9b7c..46aa68e1ced 100644 --- a/packages/objectql/src/scoped-repository-return-narrowing.test.ts +++ b/packages/objectql/src/scoped-repository-return-narrowing.test.ts @@ -5,12 +5,12 @@ import ts from 'typescript'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -// ─── [#16786] the repository a CLASS-typed call site reaches is declared ──── +// ─── [commit 5c8f5af50] the repository a CLASS-typed call site reaches is declared ──── // // `IScopedObjectRepository` (`packages/spec/src/contracts/scoped-context.ts`) // declares `findOne` as `Promise | null>` and `update` as // `Promise | number | null>` — ruling A on #16231, landed -// as PR #16783. `IDataEngine`, the call each `ObjectRepository` member forwards +// as commit 854639b31. `IDataEngine`, the call each `ObjectRepository` member forwards // to, declares the same shapes. `ObjectRepository` sat between those two narrow // declarations and re-widened the result back to `Promise`. // @@ -34,7 +34,7 @@ import { fileURLToPath } from 'node:url'; // // ⚠️ The first line is why the probes below are written through the CLASS and // the exported engine door rather than through `HookContext`. `HookContext.api` -// was narrowed to `IScopedContext` by #5945/#6311, so a handler typed +// was narrowed to `IScopedContext` by #5945 / commit 59b794f71, so a handler typed // `(ctx: HookContext) => …` reads the narrow type today and read it before this // fix too — a probe written that way is GREEN on both sides and pins nothing. // The `any` lives on the class-typed doors, so that is where the probes go. diff --git a/packages/objectql/src/search-companion-read-projection-conformance.test.ts b/packages/objectql/src/search-companion-read-projection-conformance.test.ts index a0e55b1c36a..53f5050e8d9 100644 --- a/packages/objectql/src/search-companion-read-projection-conformance.test.ts +++ b/packages/objectql/src/search-companion-read-projection-conformance.test.ts @@ -240,7 +240,7 @@ async function makeEngine(declared: boolean): Promise { /** * The `plugin-pinyin-search` write hook, in miniature. * - * [#13657] Carries `stampCompanion`'s DECLARATION GUARD + * [commit b003cf2e8] Carries `stampCompanion`'s DECLARATION GUARD * (`companion-projection.ts`: `if (!schema?.fields?.[SEARCH_COMPANION_FIELD]) * return;`). It was missing here, which made this double LOOSER than the hook * it stands in for — the #4550 failure shape one layer down: in the diff --git a/packages/objectql/src/search-companion.test.ts b/packages/objectql/src/search-companion.test.ts index fe0470e4bb3..1d88799f834 100644 --- a/packages/objectql/src/search-companion.test.ts +++ b/packages/objectql/src/search-companion.test.ts @@ -199,7 +199,7 @@ describe('containsCJK / isCompanionMatchableTerm', () => { }); // ───────────────────────────────────────────────────────────────────────────── -// [#10290] The primary key is never a companion source. +// [commit 2570ab05c] The primary key is never a companion source. // // The two blocks below are a matched pair and are meant to be read together: // the first is the NEGATIVE control (the defect — it fails on the pre-fix diff --git a/packages/objectql/src/search-companion.ts b/packages/objectql/src/search-companion.ts index 8d39ac91b3a..b7985174934 100644 --- a/packages/objectql/src/search-companion.ts +++ b/packages/objectql/src/search-companion.ts @@ -94,7 +94,7 @@ function isCompanionSourceType(type: string | undefined): boolean { } /** - * [#10290] Field names that carry the record's PRIMARY KEY — its address — + * [commit 2570ab05c] Field names that carry the record's PRIMARY KEY — its address — * rather than any human-authored text. * * Keyed on the NAME because that is where the role lives: the driver @@ -111,7 +111,7 @@ function isCompanionSourceType(type: string | undefined): boolean { const RECORD_ADDRESS_FIELD_NAMES: ReadonlySet = new Set([SystemFieldName.ID, '_id']); /** - * [#10290] Is `fieldName` the object's primary key? + * [commit 2570ab05c] Is `fieldName` the object's primary key? * * Exported so the refusal in {@link resolveSearchCompanionSources} is one * named judgement a caller can ask about, rather than a literal buried in a @@ -149,7 +149,7 @@ export function isCompanionSourceEligible(fieldMeta: CompanionFieldMeta | undefi * hook — deriving both from the same function means there is no stored * mapping to drift. * - * ## [#10290] The PRIMARY KEY is never a source + * ## [commit 2570ab05c] The PRIMARY KEY is never a source * * ADR-0079's derivation ends at "first title-eligible field by declaration * order", and on a table whose only text column IS its primary key — system @@ -201,7 +201,7 @@ export function resolveSearchCompanionSources(schema: CompanionObjectMeta | unde if (!schema?.fields) return []; const display = resolveDisplayField(schema as any); if (!display) return []; - // [#10290] Before the metadata gate: the primary key's METADATA is a + // [commit 2570ab05c] Before the metadata gate: the primary key's METADATA is a // perfectly ordinary readable text column, so only its name can refuse it. if (isPrimaryKeyField(display)) return []; const meta = schema.fields[display]; diff --git a/packages/objectql/src/skip-schema-sync-registers-object-metadata.test.ts b/packages/objectql/src/skip-schema-sync-registers-object-metadata.test.ts index 3c58361f7fb..5e1a2d09c66 100644 --- a/packages/objectql/src/skip-schema-sync-registers-object-metadata.test.ts +++ b/packages/objectql/src/skip-schema-sync-registers-object-metadata.test.ts @@ -19,7 +19,7 @@ * pins the encoding half against a live Postgres; this file pins the boot half: * that the flag routes to the DDL-FREE registration instead of to nothing. * - * It is the same ruling #7737/#10629 already made for FEDERATED objects — that + * It is the same ruling #7737 already made for FEDERATED objects (commit 199ec4712) — that * flag is about DDL, and a binding that is DDL-free must not ride on it — * extended to the managed ones. */ @@ -150,7 +150,7 @@ describe('OS_SKIP_SCHEMA_SYNC boot registers object metadata without DDL (#10995 const { driver, calls } = recordingDriver(); await install(true, [PREF, external], driver); - // The managed one only — #7737/#10629 already bind the federated one at + // The managed one only — #7737 and commit 199ec4712 already bind the federated one at // `kernel:ready`, and handing it to the managed route would register it // under its OBJECT name instead of its remote table. expect(calls.registerObjectMetadata[0]).toEqual(['sys_user_preference']); diff --git a/packages/objectql/src/sys-metadata-repository.test.ts b/packages/objectql/src/sys-metadata-repository.test.ts index 4ae485ce951..7bd5497f04c 100644 --- a/packages/objectql/src/sys-metadata-repository.test.ts +++ b/packages/objectql/src/sys-metadata-repository.test.ts @@ -701,7 +701,7 @@ describe('SysMetadataRepository', () => { const ref = { org: 'org_alpha', type: 'app' as const, name: 'ticket_service_app' }; // `intent: 'runtime-only'` — a whole-app build stages a BRAND-NEW app // (nothing artifact-backed under this name), which is exactly the - // intent the protocol layer computes for it. Required since #6483 + // intent the protocol layer computes for it. Required since commit ee58392e1 // rolled `app`'s `allowOrgOverride` back to `false` (ADR-0005): the // repository's default `override-artifact` intent now 403s for `app`, // while the runtime-create tier this write actually belongs to stays @@ -714,7 +714,7 @@ describe('SysMetadataRepository', () => { // Same `runtime-only` intent the real caller computes: the protocol's // publish handler derives intent from `isArtifactBacked` and nothing // ships an artifact under this name (promoteDraft's own default is - // `override-artifact`, which #6483's `app` rollback now 403s). + // `override-artifact`, which commit ee58392e1's `app` rollback now 403s). await repo.promoteDraft(ref, { actor: 'admin', intent: 'runtime-only' }); const activeRow = Array.from(engine.rows.values()).find( (r) => (r as any).type === 'app' diff --git a/packages/objectql/src/system-write-organization.test.ts b/packages/objectql/src/system-write-organization.test.ts index 14250432d4e..1679cb84eb2 100644 --- a/packages/objectql/src/system-write-organization.test.ts +++ b/packages/objectql/src/system-write-organization.test.ts @@ -114,7 +114,7 @@ const DISPATCH_ORDER = { * * ⚠️ Its exclusion below is `unclassified`, not `global`. Until the 2026-08-31 * ruling this file read it as "platform namespace ⇒ deliberately org-less - * (#8672)"; that wholesale reading was withdrawn, and what these cases now pin + * (…)"; that wholesale reading was withdrawn, and what these cases now pin * is that an UNADJUDICATED object's behaviour did not move — which is what * bounds the reclassification's blast radius to the admitted list. The admitted * and `global` sides are pinned in `tenancy-by-object-classification.test.ts`. @@ -344,7 +344,7 @@ describe('#8844 the exclusions — populations the refusal must not touch', () = 'a platform-namespace object stays org-less on the %s posture', async (posture) => { // ⚠️ [#13491] Reads as an UNCLASSIFIED verdict now, not a namespace one. - // #8672 measured this primitive on `sys_permission_set` and filed it as an + // The card commit ff08691e6 cites measured this primitive on `sys_permission_set` and filed it as an // observation because an org-less row is defensible there. The #8844 // ruling confirms that reasoning holds for platform objects and does NOT // generalize to application objects — which is exactly the boundary here. diff --git a/packages/objectql/src/tenancy-by-object-classification.test.ts b/packages/objectql/src/tenancy-by-object-classification.test.ts index 6a53cbbb41d..9049f30940b 100644 --- a/packages/objectql/src/tenancy-by-object-classification.test.ts +++ b/packages/objectql/src/tenancy-by-object-classification.test.ts @@ -8,7 +8,7 @@ // measurement fired: // // - isSystem x a TENANT-SCOPED object = IN scope; -// - isSystem x a genuinely GLOBAL object = OUT of scope, #8672's reasoning +// - isSystem x a genuinely GLOBAL object = OUT of scope, commit ff08691e6's recorded reasoning // inheriting PER OBJECT rather than by namespace. // // ## What each test here discriminates @@ -23,7 +23,7 @@ // each admitted-object case carries its excluded-object control, run // through the same engine on the same posture. // 2. The engine's `bypassTenantAudit` isSystem mute. This is the gate the -// #13178 census measured as silencing 135 of 175 write call sites (77%) — +// census cited in commit e49d98896's message measured as silencing 135 of 175 write call sites (77%) — // the control's LARGEST gate, sitting ahead of the condition the control // is about. Pinned as the OPTION the engine hands the driver, because that // is the whole of what the engine decides; `@objectstack/objectql` cannot @@ -91,7 +91,7 @@ const PACKAGE_ID = '#13491'; /** ADMITTED by the inventory — #12745 fixed its writer, a backfill was ordered. */ const SYS_FILE = { name: 'sys_file', fields: { key: { type: 'text' } } } as any; -/** GLOBAL by the inventory — #8672's own example, named verbatim in the ruling. */ +/** GLOBAL by the inventory — commit ff08691e6's own example, named verbatim in the ruling. */ const SYS_PERMISSION_SET = { name: 'sys_permission_set', fields: { label: { type: 'text' } } } as any; /** UNCLASSIFIED — a platform object the inventory did not adjudicate. */ const SYS_UNADJUDICATED = { name: 'sys_audit_entry', fields: { subject: { type: 'text' } } } as any; diff --git a/packages/objectql/src/tenancy/platform-object-tenancy.ts b/packages/objectql/src/tenancy/platform-object-tenancy.ts index 7df78dfa4ba..622c7619fe8 100644 --- a/packages/objectql/src/tenancy/platform-object-tenancy.ts +++ b/packages/objectql/src/tenancy/platform-object-tenancy.ts @@ -14,7 +14,7 @@ * exists for; it has occurred five times (#12745, #12928, #10673, #8617, * cloud#1239 — one a credentials table) and every instance was found by a * person reading call sites, never by the control. - * - `isSystem` x a GENUINELY GLOBAL object = OUT of scope. #8672's reasoning + * - `isSystem` x a GENUINELY GLOBAL object = OUT of scope. Commit ff08691e6's recorded reasoning * ("an org-less row is defensible for `sys_permission_set`") inherits **per * object**; the wholesale `sys_ / cloud_ / ai_` namespace exemption is * withdrawn. @@ -31,7 +31,7 @@ * ⛔ The census that measures this is NOT restated here. It is derived by * `scripts/platform-object-tenancy-census.mjs`, committed as * `scripts/platform-object-tenancy-census.json`, and held to the tree by - * `scripts/check-platform-object-tenancy-census.mjs` (#14957). Its PREDICATE is + * `scripts/check-platform-object-tenancy-census.mjs` (commit 26144c204). Its PREDICATE is * the half this paragraph used to leave out: an object is inside the machinery * when `resolveTenantFieldName` answers non-null on the registered schema — * after `applySystemFields`, because the injected column is what the engine @@ -50,7 +50,7 @@ * * The ARGUMENT survives that measurement, and no digit was load-bearing for it: * the great majority of platform-namespace objects carry the tenant column — - * `sys_permission_set`, #8672's own example of a legitimately org-less object, + * `sys_permission_set`, commit ff08691e6's own example of a legitimately org-less object, * among them — so a schema read admits nearly all of them in one stroke, i.e. * it replaces a wholesale exemption with a wholesale inclusion. The ruling's classification source is * "有列**且有写手填**" — the column AND a writer that fills it — and the second @@ -100,7 +100,7 @@ import { isPlatformNamespaceObject } from './system-write-organization'; export type PlatformObjectTenancy = /** Column present AND a citable writer fills it. In scope. */ | 'tenant-scoped' - /** #8672's reasoning inherits: rows are deliberately org-less. Out of scope. */ + /** Commit ff08691e6's reasoning inherits: rows are deliberately org-less. Out of scope. */ | 'global' /** Not determinable from the tree. Out of scope, PENDING ADJUDICATION. */ | 'unclassified'; @@ -141,7 +141,7 @@ export const PLATFORM_OBJECT_TENANCY: Readonly { // ⭐ THIS ASSERTION IS THE INVERSION. Its two earlier lives, in order: - // * before #14399 the boot loop minted ['lead_views', + // * before commit 3c1bbd2a8 the boot loop minted ['lead_views', // 'lead_views.default', 'lead_views.hot'] — the container and its // whole expansion filed under the row identity, so // `getViewsByObject('crm_lead')` had nothing for this document; - // * #14399 moved `name` to LAST in the derivation, so it minted + // * commit 3c1bbd2a8 moved `name` to LAST in the derivation, so it minted // AGREED_KEYS instead — the right key, but with the author's // `name` silently overwritten on the way past. - // The #14666 ruling (direction 2, 2026-09-03) ends the second: a + // The ruling commit d0ee598e6 records (direction 2, 2026-09-03) ends the second: a // container whose `name` disagrees with its derived binding is // REFUSED, exactly as the artifact/HMR door has always refused it. // - // #14399's derivation answer is NOT lost by inverting this — it moves + // Commit 3c1bbd2a8's derivation answer is NOT lost by inverting this — it moves // to where the artifact door's answer was already read in this file: // the refusal names the key it derived. Both SOURCE registrars are now // read the same way, which is the convergence the card asked for. @@ -244,7 +244,7 @@ describe('#14399 — the row\'s own `name` is the LAST term of the container der expect(error.message).toContain("'crm_lead'"); // The derivation itself, still pinned: `crm_lead` is what it derived, // NOT the row's own `lead_views`. A refusal naming `lead_views` as the - // derived key would mean #14399 had regressed. + // derived key would mean commit 3c1bbd2a8 had regressed. expect(error.message).toContain("binds to, 'crm_lead'"); // Nothing filed: a refusal that has already registered half the // document would leave the registry in the state the card calls the @@ -272,7 +272,7 @@ describe('#14399 — the row\'s own `name` is the LAST term of the container der const err = await loadThroughArtifactDoor(divergentContainer).catch((e) => e as any); expect(err.code).toBe('VALIDATION_ERROR'); expect(err.status).toBe(400); - // ⭐ [#14666] THE SECOND INVERSION, and the card's actual subject. This + // ⭐ [commit d0ee598e6] THE SECOND INVERSION, and the card's actual subject. This // used to read // // expect((engine.registry.getItem('view', 'crm_lead') as any).name) @@ -293,7 +293,7 @@ describe('#14399 — the row\'s own `name` is the LAST term of the container der }); it('so the boot loop\'s expanded items are addressable under the object', () => { - // [#14666] Driven on the ANONYMOUS container now. The expansion + // [commit d0ee598e6] Driven on the ANONYMOUS container now. The expansion // property this pins — expanded items bind to the derived object, not // to the container's row identity — is unchanged, but the divergent // shape no longer reaches expansion at all: it is refused before @@ -363,7 +363,7 @@ describe('#14399 — the row\'s own `name` is the LAST term of the container der }); // ------------------------------------------------------------------ - // [#14666] Scope controls. The ruling names keeping the refusal's scope + // [commit d0ee598e6] Scope controls. The ruling names keeping the refusal's scope // tight as the implementation's MAIN RISK, and `registerMetadataCollections` // is the GENERIC loop every metadata kind runs — so the three narrowings in // the gate get a control each, plus the measurement that decided which of diff --git a/packages/objectql/vitest.config.ts b/packages/objectql/vitest.config.ts index a379feae8c6..5f83f66abf7 100644 --- a/packages/objectql/vitest.config.ts +++ b/packages/objectql/vitest.config.ts @@ -58,7 +58,7 @@ import { // repo. `extends: true` keeps the root options (aliases included) on both. const REPO_TESTS: string[] = JSON.parse(readFileSync(path.join(__dirname, 'vitest.repo-tests.json'), 'utf8')); -// #17853 / #17978 — say so when a path named on the command line will run no +// Commit 08f5f0e5a / #17978 — say so when a path named on the command line will run no // tests. Invoked HERE, at config load, and ⛔ deliberately NOT as a // `test.reporters` entry: naming that option replaces vitest's own reporter // defaulting instead of extending it, which measurably changes a healthy run's