diff --git a/.changeset/runtime-provenance-anchors.md b/.changeset/runtime-provenance-anchors.md new file mode 100644 index 00000000000..4786cf0cd53 --- /dev/null +++ b/.changeset/runtime-provenance-anchors.md @@ -0,0 +1,11 @@ +--- +'@objectstack/runtime': patch +--- + +Provenance comments in `@objectstack/runtime` were re-anchored + +Comment and docblock lines under `src/` that cited tracker numbers which no +longer resolve on GitHub now cite the commit in this repository's history that +decided the matter, and say in their own words what was decided. Comments +only: no route, error code, refusal text, type, export or runtime behaviour +changes. diff --git a/packages/runtime/src/action-declarative-update.test.ts b/packages/runtime/src/action-declarative-update.test.ts index b692d0db680..e082757749f 100644 --- a/packages/runtime/src/action-declarative-update.test.ts +++ b/packages/runtime/src/action-declarative-update.test.ts @@ -336,7 +336,7 @@ describe('#15079 point 3 — the authorization point: a caller who cannot read o expect(res.body.error.code).toBe('RECORD_NOT_FOUND'); expect(res.body.error.message).toContain(RECORD_ID); expect(res.body.error.message).toContain(OBJECT); - // ⛔ The #14143 class: a swallowed load must never become an implicit + // ⛔ The class commit f19475c0a closed: a swallowed load must never become an implicit // grant. The verdict is CONSUMED — no write was even attempted. expect(rig.updates).toHaveLength(0); expect(rig.row.status).toBe('open'); diff --git a/packages/runtime/src/action-door-record-load-denied.test.ts b/packages/runtime/src/action-door-record-load-denied.test.ts index 0022598ddeb..7751c6d37c6 100644 --- a/packages/runtime/src/action-door-record-load-denied.test.ts +++ b/packages/runtime/src/action-door-record-load-denied.test.ts @@ -32,7 +32,7 @@ * * 1. **Both doors × both surfaces.** The flow door and the script/body door, * on the REST `/actions` route and on the MCP `run_action` bridge. A rule - * implemented at one door is the failure class #14143 and #15168 each paid + * implemented at one door is the failure class commit f19475c0a and #15168 each paid * for on this exact seam, so every case below is asserted on all four. * 2. **⛔ No run, no body.** The refusal lands BEFORE `automation.execute` * (no persisted run) and BEFORE `executeAction` (no trusted, RLS-bypassing @@ -46,7 +46,7 @@ * 4. **Record-less and new-record actions are byte-for-byte unchanged.** An * object-less action key never attempts a load, so its verdict is never * `true` and it still receives the `recordId` stamp — the regression that - * #14143 deliberately kept and that this card must not take away. + * commit f19475c0a deliberately kept and that this card must not take away. * 5. **A load that SUCCEEDS still runs.** The owner reaches the flow and the * handler exactly as before; this is the firing control that stops every * zero above from being a rig that dispatches nothing. @@ -450,7 +450,7 @@ describe('[#16370] refuseDeniedSubjectLoad — the rule, isolated from every doo it('returns silently when the verdict is `false` — and the stamp is NOT the predicate', () => { // ⛔ `record.id` is truthy in BOTH cases; re-deriving the verdict from - // it is the #14143 defect verbatim, so this pair is what says the + // it is the defect commit f19475c0a fixed, verbatim, so this pair is what says the // implementation reads the flag and nothing else. expect(() => refuseDeniedSubjectLoad(OBJECT, RECORD_ID, { record: { id: RECORD_ID }, recordLoadDenied: false })).not.toThrow(); diff --git a/packages/runtime/src/action-execution.ts b/packages/runtime/src/action-execution.ts index 64fef292ebb..7c81014a2e6 100644 --- a/packages/runtime/src/action-execution.ts +++ b/packages/runtime/src/action-execution.ts @@ -900,14 +900,14 @@ export function isFlowActionRefusal(e: unknown): e is FlowActionRefusal { * and a downstream reader that had to tell them apart could only infer. * * [#15168] **The wiring takes the subject LOAD, not a bare record.** The flow - * face of #14143's signal (`AutomationContext.recordLoadDenied`, declared by + * face of commit f19475c0a's signal (`AutomationContext.recordLoadDenied`, declared by * #14244) is derived here, once, from {@link loadActionSubjectRecord}'s * outcome — so a caller cannot hand this door a record while dropping the * verdict that says the caller could not read it. Both call sites already held * that outcome and were passing `subject.record` out of it; taking the whole * `subject` removes the second de-facto source rather than adding a key beside * it, and makes the omission a compile error instead of a silent inertness one - * door over (the shape #14143 was filed for). + * door over (the shape commit f19475c0a fixed). */ export async function dispatchFlowAction(deps: ActionExecutionDeps, requestContext: HttpProtocolContext, @@ -1685,10 +1685,10 @@ export function buildActionEngineFacade(_deps: ActionExecutionDeps, ql: any, ec? /** * The subject-record load's outcome, as the two action doors hand it to a - * handler (#14143). + * handler (commit f19475c0a). */ export interface ActionSubjectRecordLoad { - /** What the handler receives as `ctx.record`. Unchanged by #14143. */ + /** What the handler receives as `ctx.record`. Unchanged by commit f19475c0a. */ record: Record; /** * `true` exactly when a caller-scope load was ATTEMPTED and did not deliver @@ -1700,7 +1700,7 @@ export interface ActionSubjectRecordLoad { /** * Load an action's subject record IN THE CALLER'S OWN SCOPE, and report whether - * that load actually delivered the row (#14143). ONE producer for both action + * that load actually delivered the row (commit f19475c0a). ONE producer for both action * doors — the MCP `run_action` bridge below and the REST `/actions` route * (`domains/actions.ts`) — because the signal it emits is documented to app * authors, and a signal only one of two doors sets is an authorization guard @@ -1793,7 +1793,7 @@ export function actionRecordLoadSignal(load: ActionSubjectRecordLoad): { recordL * reading it left open ("whether the automation engine acts on it … is a * separate reading") is this function. A swallowed load must never become an * implicit grant — the rule is #15079's, and a rule implemented at one of three - * doors is the failure class #14143 and #15168 each already paid for here. + * doors is the failure class commit f19475c0a and #15168 each already paid for here. * * ## The predicate is the LOAD's verdict — ⛔ never the action's `locations` * @@ -1906,11 +1906,11 @@ function declarativeUpdateRefusal(message: string, status: number): Error { * 'update'` + `patch` (#14092, maintainer ruling 2026-09-01, quoted on the * card). ONE implementation, called by BOTH action doors. * - * ## Shared on purpose, for the #14143 reason + * ## Shared on purpose, for the reason of commit f19475c0a * * The REST `/actions` door and the MCP `run_action` bridge are two doors onto * one action model, and this repo has now paid twice for a rule implemented at - * one of them: #14143 (a `recordLoadDenied` signal only one door set) and + * one of them: commit f19475c0a (a `recordLoadDenied` signal only one door set) and * #15168 (a flow face with no populator at all). An authorization rule is the * worst possible thing to fork, and contract point 3 is an authorization rule * — so the branch each door owns is three lines, and everything that decides @@ -1944,7 +1944,7 @@ function declarativeUpdateRefusal(message: string, status: number): Error { * the caller's own scope actually delivered it. A caller who cannot read the * row is refused HERE, before any write is attempted, on * `subject.recordLoadDenied`. Re-deriving that from `subject.record` is the - * #14143 defect verbatim: the door stamps `record.id = recordId` on a refused + * defect commit f19475c0a fixed, verbatim: the door stamps `record.id = recordId` on a refused * load, so `record.id` is truthy either way and `if (!record?.id)` is false on * a row the caller cannot see. A swallowed load must never become an implicit * grant. @@ -2202,7 +2202,7 @@ export async function invokeBusinessAction(deps: ActionExecutionDeps, // Load the subject record under RLS when row-context (engages the same // permission path as get_record — an unseen record reads as not-found). - // [#14143] Through the ONE shared producer, so this door and the REST + // [commit f19475c0a] Through the ONE shared producer, so this door and the REST // `/actions` door emit the same `recordLoadDenied` signal to handlers. const subject = await loadActionSubjectRecord(objectName, recordId, () => callData('get', { object: objectName, id: recordId }, driver, envId, ec)); @@ -2213,7 +2213,7 @@ export async function invokeBusinessAction(deps: ActionExecutionDeps, // first, and an action with no handler has no body to elevate for. The // shared executor the REST `/actions` door also calls, so the two doors // cannot disagree about the identity the write carries — the failure class - // #14143 and #15168 each paid for once, on this exact seam. + // commit f19475c0a and #15168 each paid for once, on this exact seam. if (isDeclarativeUpdateAction(action)) { const result = await executeDeclarativeUpdateAction(deps, action, { objectName, actionName: name, subject, recordId, params, ec, driver, envId, callData, @@ -2281,7 +2281,7 @@ export async function invokeBusinessAction(deps: ActionExecutionDeps, ); const actionContext: any = { record, - // [#14143] The caller-scope load's verdict, on the same context the + // [commit f19475c0a] The caller-scope load's verdict, on the same context the // record rides. `ctx.record.id` is present either way (the stamp is // load-bearing for record-less actions), so this is the ONLY thing that // tells a handler its subject row did not resolve for THIS caller — diff --git a/packages/runtime/src/action-governance-scope-divergence.test.ts b/packages/runtime/src/action-governance-scope-divergence.test.ts index 3d506d622ec..5828a05df90 100644 --- a/packages/runtime/src/action-governance-scope-divergence.test.ts +++ b/packages/runtime/src/action-governance-scope-divergence.test.ts @@ -1,9 +1,9 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #14423 (a) — the AGREEMENT, where this file used to pin the divergence. + * Commit a56baa2bd — the AGREEMENT, where this file used to pin the divergence. * - * The two sites the card names: + * The two sites that diverged: * - the AUDIT, `runActionGovernanceInventory` (`packages/objectql/src/ * action-governance.ts`), whose metadata-plane sources are now * `loadStandaloneActionsKeyed = () => meta.loadManyKeyed('action')` and the @@ -13,7 +13,7 @@ * whose third rung is `meta.loadDiagnosed('action', name)` — resolved per * request off `deps.resolveService(requestContext, 'metadata', envId)`. * - * PR #14421 closed the registry rung. This file measured the remaining one and + * Commit bd8795ea1 closed the registry rung. This file measured the remaining one and * reproduced it four ways; the measurement is now the fix's pin, case for * case, with the same harness. **C1 and C5 are unchanged controls** — they * were green before and must stay green, because a "fix" that simply stopped @@ -184,7 +184,7 @@ function auditAccused(warnings: Array<{ message: string; meta?: Record loadManyKeyed.call(meta, 'action') : undefined, - lookupRegistryAction: () => undefined, // rung 2 holds nothing — #14421's rung is not the one under test + lookupRegistryAction: () => undefined, // rung 2 holds nothing — commit bd8795ea1's rung is not the one under test lookupMetadataAction: meta && typeof loadDiagnosed === 'function' ? async (name: string) => (await loadDiagnosed.call(meta, 'action', name))?.data : (meta && typeof load === 'function' ? (name: string) => load.call(meta, 'action', name) : undefined), @@ -323,7 +323,7 @@ describe('#14423 (a) — the audit and the router now answer from one identity a // The keyed enumeration is short for the same reason — keying is not a // cure for an unreachable loader, and does not claim to be. expect(await meta.loadManyKeyed('action')).toEqual([]); - // [#14423 item 1] ...and the sibling enumeration no longer THROWS where + // [commit a56baa2bd] ...and the sibling enumeration no longer THROWS where // its two siblings merely came back short. await expect(meta.listNames('action')).resolves.toEqual([]); @@ -335,7 +335,7 @@ describe('#14423 (a) — the audit and the router now answer from one identity a }); /** - * C4 — a BOUNDARY, not a defect, and pinned as one. NARROWER since #16610. + * C4 — a BOUNDARY, not a defect, and pinned as one. NARROWER since commit 316a20fc5. * * `metadata` is registered `SCOPED`, so `PluginLoader.getService` mints one * instance per `scopeId`. The kernel's RAW SYNCHRONOUS accessor @@ -348,7 +348,7 @@ describe('#14423 (a) — the audit and the router now answer from one identity a * plane. That asymmetry is what every assertion below exercises — the * accessor, directly, never the plugin's wiring around it. * - * ## What the PLUGIN does with that accessor, after #16610 + * ## What the PLUGIN does with that accessor, after commit 316a20fc5 * * `ObjectQLPlugin.resolveGovernanceMetadataService` no longer calls the * synchronous accessor alone, so the throw is no longer swallowed into @@ -363,7 +363,7 @@ describe('#14423 (a) — the audit and the router now answer from one identity a * ⚠ So do NOT read the paragraph above as a live defect in `plugin.ts`. * It describes the rung the plugin now reaches for SECOND, and this case * pins that rung's behaviour — which is why its assertions stay green and - * stay true across #16610. + * stay true across commit 316a20fc5. * * ## Why this stays accused, and why that is CORRECT * diff --git a/packages/runtime/src/action-object-less-key-agreement.test.ts b/packages/runtime/src/action-object-less-key-agreement.test.ts index 865c95c48f1..2f1ff942a19 100644 --- a/packages/runtime/src/action-object-less-key-agreement.test.ts +++ b/packages/runtime/src/action-object-less-key-agreement.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * "Object-less" has ONE answer inside `action-execution.ts` (#14864). + * "Object-less" has ONE answer inside `action-execution.ts` (commit 066dd3bd0). * * `isObjectLessActionKey` (`@objectstack/objectql`) is the canonical predicate: * the routed object is object-less when it is the canonical diff --git a/packages/runtime/src/action-owner-key-single-source.test.ts b/packages/runtime/src/action-owner-key-single-source.test.ts index d88a457faef..ca333fdb473 100644 --- a/packages/runtime/src/action-owner-key-single-source.test.ts +++ b/packages/runtime/src/action-owner-key-single-source.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * The standalone-action owner-key ladder has ONE spelling (#14422). + * The standalone-action owner-key ladder has ONE spelling (commit dc7c226b9). * * `action.objectName` -> `action.object` -> the object-less * `GLOBAL_ACTION_OBJECT_KEY` decides which engine key a standalone `action` @@ -26,16 +26,16 @@ * B reads this package's own source and fails if the ladder grows a second * body here. * - * Half C closes the same hole one level down (#14678). #14422 converged the + * Half C closes the same hole one level down (commit 73ad0bba7). Commit dc7c226b9 converged the * LADDER, and the runtime kept three bare `'global'` spellings elsewhere in * `action-execution.ts` that the ladder check could not see: a live comparison * in `seedFlowActionParams`, a warn-once log key in `enforceActionParams`, and * a docblock. All three were equal in value and invisible to every test in the - * repo, which is the whole shape #14422 was filed to remove — so the same + * repo, which is the whole shape commit dc7c226b9 was written to remove — so the same * convergence needed the same weld, or the next reader re-inlines one and * nothing says so. * - * Half D (#14878) is the odd one out and says so at its own section below: it + * Half D (commit 29db3cd2a) is the odd one out and says so at its own section below: it * is not about this package's source at all. It is the TREE-scoped absence pin * for the plugin member this convergence deleted, carried here as well as in * `@objectstack/objectql` so that losing either copy still leaves a guard. @@ -157,14 +157,14 @@ describe('standalone-action owner key — half C: no bare literal (#14678)', () // file was written to replace. Both controls are positive assertions // against text the converged file must carry. // - // [#14864] The second control used to be the `seedFlowActionParams` + // [commit 066dd3bd0] The second control used to be the `seedFlowActionParams` // comparison `objectName !== GLOBAL_ACTION_OBJECT_KEY`. That guard is // gone — it was one of the two rival answers to "is this route // object-less", and it now delegates to `isObjectLessActionKey` like // its neighbours. Re-anchored rather than deleted, and deliberately // onto a site this file's own subject does not move: the warn-once log // key in `enforceActionParams`, which is the SECOND of the three bare - // literals #14678 converged and is untouched by the predicate work. + // literals commit 73ad0bba7 converged and is untouched by the predicate work. // ⛔ Do not re-anchor a control onto the thing the next change is most // likely to edit — a control that moves with its subject stops being a // control. @@ -184,9 +184,9 @@ describe('standalone-action owner key — half C: no bare literal (#14678)', () }); /** - * ── Half D [#14878]: the absence assertion is TREE-scoped, not FILE-scoped ─── + * ── Half D [commit 29db3cd2a]: the absence assertion is TREE-scoped, not FILE-scoped ─── * - * #14667 deleted a private `actionObjectKey` member from `ObjectQLPlugin` and + * Commit dc7c226b9 deleted a private `actionObjectKey` member from `ObjectQLPlugin` and * DID write a guard for it — `not.toContain(...)` against `plugin.ts`. The kind * of guard was right; its SCOPE was the defect. A pin written by the deleting PR * can only look where its author thought to look, and the whole failure mode is @@ -260,7 +260,7 @@ describe('standalone-action owner key — half C: no bare literal (#14678)', () */ /** - * The member #14667 deleted from `ObjectQLPlugin`. Held as DATA: naming a symbol + * 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/runtime/src/action-params-enforcement.test.ts b/packages/runtime/src/action-params-enforcement.test.ts index 041bacdc95b..612474201d4 100644 --- a/packages/runtime/src/action-params-enforcement.test.ts +++ b/packages/runtime/src/action-params-enforcement.test.ts @@ -2,7 +2,7 @@ /** * `enforceActionParams` — the ADR-0104 D2 gate itself, not its validator - * (#14864). + * (commit 066dd3bd0). * * ## What was measured, and why this file exists * diff --git a/packages/runtime/src/action-record-load-denied.test.ts b/packages/runtime/src/action-record-load-denied.test.ts index 8ccc962af3e..fd5ad894e2e 100644 --- a/packages/runtime/src/action-record-load-denied.test.ts +++ b/packages/runtime/src/action-record-load-denied.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#14143] A handler must be able to tell "the caller cannot read this row" + * [commit f19475c0a] A handler must be able to tell "the caller cannot read this row" * from "this action legitimately has no record". * * ## The defect @@ -493,7 +493,7 @@ describe('[#15168] the FLOW door and its verdict — MCP run_action', () => { * `AutomationContext.recordLoadDenied` is a declared spec key * (`contracts/automation-service.ts`, pinned in `packages/spec`), the * dispatcher is its ONE populator, and a populator that quietly stopped - * populating would be exactly the inert-signal shape #14143 was filed for. So + * populating would be exactly the inert-signal shape commit f19475c0a fixed. So * the assertions #15168 wrote at the doors are re-pinned HERE, on the * dispatcher itself, where a denied subject can still be constructed. * @@ -556,8 +556,8 @@ describe('[#15168] dispatchFlowAction derives the verdict from the subject load' /** * [#15168] The convergence itself. A per-door assertion is satisfied by two - * copies of a rule, and two copies drifting apart is the defect #14143 was - * filed for and the reason this card had to move both doors in one stroke — so + * copies of a rule, and two copies drifting apart is the defect commit f19475c0a + * fixed, and the reason this card had to move both doors in one stroke — so * the SAME caller against the SAME row is driven through both doors and the * signal is compared as a set. */ diff --git a/packages/runtime/src/analytics-query-read-scope-withhold.test.ts b/packages/runtime/src/analytics-query-read-scope-withhold.test.ts index b222b089376..5b8617ce0a6 100644 --- a/packages/runtime/src/analytics-query-read-scope-withhold.test.ts +++ b/packages/runtime/src/analytics-query-read-scope-withhold.test.ts @@ -44,7 +44,7 @@ * withhold got broader" and "the withhold swallowed everything" are one edit * apart. * - * ⚠️ [#12281] The DECLARED half of that predicate has since widened, and this + * ⚠️ [commit 0783d7b80] The DECLARED half of that predicate has since widened, and this * file's half-envelope case was reversed with it. `declaresServerFault` required * a non-empty string `code` beside the 5xx and read the `status` spelling only, * so this exit withheld a NARROWER band than `/data`. Ruled 2026-08-27 on #12509 @@ -270,12 +270,12 @@ describe('[#5811] POST /analytics/query — a read-scope failure says nothing ab }); it('[#12281] a 5xx with only HALF an envelope is ALSO withheld — a status alone declares it', async () => { - // ⚠️ REVERSED, deliberately. Until #12281 this case asserted the opposite + // ⚠️ REVERSED, deliberately. Until commit 0783d7b80 this case asserted the opposite // ("a code is required, not just a status"), on the reasoning that a // producer shipping a status without a code "has not declared anything". // // The maintainer ruled otherwise on #12509, 2026-08-27 (option D), - // propagated to #12281: `errorResponseBase` adopts the structural + // landed in commit 0783d7b80: `errorResponseBase` adopts the structural // withhold for EVERY declared 5xx message, aligning to `/data` — whose // `declaredHttpStatus` never looked at `code` at all. Naming a 5xx status // IS the declaration; the code is a second, independent channel (#9106), diff --git a/packages/runtime/src/api-exposure.test.ts b/packages/runtime/src/api-exposure.test.ts index 0b3ebda877f..970eb693e91 100644 --- a/packages/runtime/src/api-exposure.test.ts +++ b/packages/runtime/src/api-exposure.test.ts @@ -111,7 +111,7 @@ describe('checkApiExposure (#1889)', () => { expect(checkApiExposure(createOnly, 'import', { writeMode: 'update' }).allowed).toBe(false); }); - // [#6259] Was spelled `'batch'`, which reached this rule only through the + // [commit 6968885ef] Was spelled `'batch'`, which reached this rule only through the // `batch: 'bulk'` alias row — a spelling no producer sends (`callData` lost // its `batch` arm in #5856; REST gates `/batch` on `'bulk'`). With the row // gone `'batch'` is an unknown operation and falls to the ungated @@ -126,7 +126,7 @@ describe('checkApiExposure (#1889)', () => { expect(checkApiExposure(createOnly, 'bulk', { bulkChild: 'create' }).allowed).toBe(false); }); - // [#6259] The absence pin's runtime half: `batch` is no longer a spelling + // [commit 6968885ef] The absence pin's runtime half: `batch` is no longer a spelling // this gate understands. It is NOT denied — an unmapped action respects // `apiEnabled` only — which is exactly why the row could not be left in // place as "harmless": it silently bought a bulk∧child judgement for a @@ -138,7 +138,7 @@ describe('checkApiExposure (#1889)', () => { expect(checkApiExposure({ apiEnabled: false }, 'batch').status).toBe(404); }); - // [#6259] The prose half of the same finding: this function's `@param` + // [commit 6968885ef] The prose half of the same finding: this function's `@param` // listed `batch` among the runtime data actions its only caller sends. it('the `@param action` TSDoc does not advertise `batch` as a live action', () => { const source = fs.readFileSync( diff --git a/packages/runtime/src/api-mapping.ts b/packages/runtime/src/api-mapping.ts index 2a72e54c794..9af1c67d7b1 100644 --- a/packages/runtime/src/api-mapping.ts +++ b/packages/runtime/src/api-mapping.ts @@ -26,7 +26,7 @@ * * Five short sentences, and everything below is the MINIMAL faithful reading of * them — `transform`'s now says out loud, at the point of authoring, what this - * module and the E7 publish gate have always answered at rejection time (#6065). + * module and the E7 publish gate have always answered at rejection time (commit 026101660). * Where the text is silent this module takes the least expressive option * available and says so here, because the alternative — inventing expression * power (a template language, JSONPath, wildcards, conditionals) — would put a diff --git a/packages/runtime/src/app-plugin.job-data-reach.test.ts b/packages/runtime/src/app-plugin.job-data-reach.test.ts index 5a362081565..c072268c4f7 100644 --- a/packages/runtime/src/app-plugin.job-data-reach.test.ts +++ b/packages/runtime/src/app-plugin.job-data-reach.test.ts @@ -113,7 +113,7 @@ const live: Array<{ }> = []; /** - * [#10629] This fixture provisions `sweep_note` and nothing else, so the + * [commit 13a6cb4ad] This fixture provisions `sweep_note` and nothing else, so the * engine's own single-tenant probe (`ObjectQL.probeInstallOrganizations`) reads * a `sys_organization` that was never created. The probe is fail-soft by * construction, but the driver and the engine each log the fault on the way out. diff --git a/packages/runtime/src/app-plugin.job-degraded-outcome.test.ts b/packages/runtime/src/app-plugin.job-degraded-outcome.test.ts index 318721c2114..8cfe28c8560 100644 --- a/packages/runtime/src/app-plugin.job-degraded-outcome.test.ts +++ b/packages/runtime/src/app-plugin.job-degraded-outcome.test.ts @@ -91,7 +91,7 @@ afterEach(async () => { /** * A real engine over the migrated test backend, carrying the REAL `sys_job*`. * - * ⚠️ [#10629] No expected-read-refusal capture here, deliberately and by + * ⚠️ [commit 13a6cb4ad] No expected-read-refusal capture here, deliberately and by * MEASUREMENT: every read this file performs carries `isSystem`, so the * engine's single-tenant probe over the unprovisioned `sys_organization` never * fires and neither refusal channel emits a frame (checked on the red run: zero diff --git a/packages/runtime/src/app-plugin.seed-locale-producer.test.ts b/packages/runtime/src/app-plugin.seed-locale-producer.test.ts index 3cd696b8cbd..096d40d6c7f 100644 --- a/packages/runtime/src/app-plugin.seed-locale-producer.test.ts +++ b/packages/runtime/src/app-plugin.seed-locale-producer.test.ts @@ -33,7 +33,7 @@ import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@obj * -time paths in other declared file surfaces, and the ledger row records that * split rather than claiming it away. * - * ⛔ Not housed in `seed-loader.test.ts` — the natural home, held by PR #16783. + * ⛔ Not housed in `seed-loader.test.ts` — the natural home, then held by the change that landed as commit 854639b31. */ /** diff --git a/packages/runtime/src/artifact-function-declarations.test.ts b/packages/runtime/src/artifact-function-declarations.test.ts index 5b8c423ed9d..0d9f3c794af 100644 --- a/packages/runtime/src/artifact-function-declarations.test.ts +++ b/packages/runtime/src/artifact-function-declarations.test.ts @@ -64,7 +64,7 @@ describe('mergeRuntimeModule — declared functions', () => { it('re-attaches into the ARRAY form without dropping what it declared (#6238)', async () => { // The array spelling reaches this seam for the first time now that - // #6238 lets it past the parse. Rebuilding it as a map would attach the + // commit c8d6f6e08 lets it past the parse. Rebuilding it as a map would attach the // callable and drop `effect` beside it — the same silent un-declaring // #4396 fixed for the map form, arriving by the other door. const bundle: any = { diff --git a/packages/runtime/src/batch-row-driver-text-real-driver.integration.test.ts b/packages/runtime/src/batch-row-driver-text-real-driver.integration.test.ts index 2f7f50a6254..f4d20439637 100644 --- a/packages/runtime/src/batch-row-driver-text-real-driver.integration.test.ts +++ b/packages/runtime/src/batch-row-driver-text-real-driver.integration.test.ts @@ -77,7 +77,7 @@ const NOTE = { }; /** - * [#10629] This fixture provisions its own business objects and nothing else, + * [commit 13a6cb4ad] This fixture provisions its own business objects and nothing else, * so the engine's single-tenant probe (`ObjectQL.probeInstallOrganizations`, * memoised once per engine) reads a `sys_organization` that was never created. * The probe is fail-soft by construction — it catches `isMissingTableError` and @@ -88,7 +88,7 @@ const NOTE = { const ABSENT_TENANCY_TABLE = 'sys_organization'; /** - * [#14403] The first bytes of the batch-row sink's OWN log line + * [commit 93d2d679b] The first bytes of the batch-row sink's OWN log line * (`clientFacingRowFailureText`, `metadata-protocol/src/protocol.ts`). A * literal rather than an import: the sink keeps that function private on * purpose, and what this suite pins is the line an OPERATOR reads, which is @@ -97,21 +97,21 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; const SINK_WITHHOLD_PREFIX = "[Protocol] Withheld a caught error's text from a batch row"; describe('[#8502] a REAL driver fault is withheld from every batch row', () => { - /** [#10629] The expected-noise capture belonging to the latest rig. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest rig. */ let noise: ExpectedReadRefusalCapture | null = null; let dir: string | null = null; let engine: ObjectQL | null = null; - /** [#14403] Undoes the latest rig's `console.warn` recorder. */ + /** [commit 93d2d679b] Undoes the latest rig's `console.warn` recorder. */ let restoreWarn: (() => void) | null = null; afterEach(async () => { - // [#14403] First, so a throw below can never leave `console.warn` patched. + // [commit 93d2d679b] First, so a throw below can never leave `console.warn` patched. restoreWarn?.(); restoreWarn = null; try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so // a failure here can never leave the engine running. Every test in this // file rigs and writes, so the probe fires for each of them: this holds // for a single `-t` run as well as for the whole file. @@ -126,7 +126,7 @@ describe('[#8502] a REAL driver fault is withheld from every batch row', () => { connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true, }); - // [#10629] Installed on the REAL driver (the one that logs) before it + // [commit 13a6cb4ad] Installed on the REAL driver (the one that logs) before it // runs a statement — the `Object.create(real)` wrapper below resolves // `logger` through the prototype chain to this sink. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); @@ -161,7 +161,7 @@ describe('[#8502] a REAL driver fault is withheld from every batch row', () => { } const protocol: any = new ObjectStackProtocolImplementation(engine as any); - // [#14403] Record the sink's own withhold line so BOTH directions of + // [commit 93d2d679b] Record the sink's own withhold line so BOTH directions of // its decision can be asserted: it must log exactly when it withheld. // ⛔ Recorded, never muted — every call is forwarded to the real // `console.warn`, so what a shard log shows is unchanged by this @@ -213,7 +213,7 @@ describe('[#8502] a REAL driver fault is withheld from every batch row', () => { expect(payload).not.toContain('SQLITE'); expect(payload).not.toContain('bd_child'); - // ── [#14403] The sink's OPERATOR half, direction one: it withheld, + // ── [commit 93d2d679b] The sink's OPERATOR half, direction one: it withheld, // so it LOGGED — and the line carries the driver's own sentence whole. // That is what keeps withholding distinguishable from DELETING the // diagnostic, which is the failure this file's sink was built against. @@ -280,7 +280,7 @@ describe('[#8502] a REAL driver fault is withheld from every batch row', () => { // idempotent batch writer branches on — it was `INTERNAL_ERROR` with no // status while the sentence was withheld. // - // ── [#14723] …and the row speaks the WIRE spelling ───────────────── + // ── [commit 65846bc46] …and the row speaks the WIRE spelling ─────── // The engine's envelope is `code: 'DUPLICATE_RECORD'` in-process (the // objectql pins on `insert` / `insertMany` hold that), and this row // used to relay it verbatim while the whole-request failure on the @@ -306,7 +306,7 @@ describe('[#8502] a REAL driver fault is withheld from every batch row', () => { expect(payload).not.toContain('UNIQUE constraint failed'); expect(payload).not.toContain('SQLITE_CONSTRAINT'); - // ── [#14403] The OPERATOR half — re-measured, and now a PIN ──────── + // ── [commit 93d2d679b] The OPERATOR half — re-measured, and now a PIN ──────── // What stood here called this a KNOWN RESIDUAL and deliberately // asserted nothing, on the reading that the driver's own sentence // "reaches neither the response nor the console". Re-measured on this @@ -322,7 +322,7 @@ describe('[#8502] a REAL driver fault is withheld from every batch row', () => { // `ERROR Insert operation failed {"object":"bd_note","error": // {"message":"UNIQUE constraint failed: bd_note.email …"}}`. // That line takes the envelope's `cause` on purpose (#14095 / - // #14390, `e instanceof DuplicateRecordError ? e.cause : e`, + // commit 9d7f7259f, `e instanceof DuplicateRecordError ? e.cause : e`, // because the platform logger serializes only `message` and // `stack`) and is pinned in objectql's // `driver-fault-redaction.test.ts`, which asserts the failing diff --git a/packages/runtime/src/batch-row-http-status-real-driver.integration.test.ts b/packages/runtime/src/batch-row-http-status-real-driver.integration.test.ts index d6c5aca122d..6dd59353d49 100644 --- a/packages/runtime/src/batch-row-http-status-real-driver.integration.test.ts +++ b/packages/runtime/src/batch-row-http-status-real-driver.integration.test.ts @@ -74,7 +74,7 @@ const CHILD = { }; /** - * [#10629] This fixture provisions its three business objects and nothing else, + * [commit 13a6cb4ad] This fixture provisions its three business objects and nothing else, * so the engine's single-tenant probe (`ObjectQL.probeInstallOrganizations`, * memoised once per engine) reads a `sys_organization` that was never created. * The probe is fail-soft by construction — it catches `isMissingTableError` and @@ -88,13 +88,13 @@ const CHILD = { */ const ABSENT_TENANCY_TABLE = 'sys_organization'; -/** [#10629] The capture is a PIN, not a mute — this is the assertion half. */ +/** [commit 13a6cb4ad] The capture is a PIN, not a mute — this is the assertion half. */ const expectExpectedNoiseWithheld = (noise: ExpectedReadRefusalCapture | null): void => { expect(noise?.silentChannels() ?? ['no capture was installed']).toEqual([]); }; describe('[#8570] a batch row carries the status its producer DECLARED — real driver', () => { - /** [#10629] The expected-noise capture belonging to the latest rig. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest rig. */ let noise: ExpectedReadRefusalCapture | null = null; let dir: string | null = null; let engine: ObjectQL | null = null; @@ -112,7 +112,7 @@ describe('[#8570] a batch row carries the status its producer DECLARED — real connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true, }); - // [#10629] Installed on the REAL driver (the one that logs) before it + // [commit 13a6cb4ad] Installed on the REAL driver (the one that logs) before it // runs a statement — the `Object.create(real)` wrapper below resolves // `logger` through the prototype chain to this sink. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); diff --git a/packages/runtime/src/bulk-write-real-driver.integration.test.ts b/packages/runtime/src/bulk-write-real-driver.integration.test.ts index a8700d0f542..e721e31752b 100644 --- a/packages/runtime/src/bulk-write-real-driver.integration.test.ts +++ b/packages/runtime/src/bulk-write-real-driver.integration.test.ts @@ -98,7 +98,7 @@ function metadataFor(objects: any[]) { } /** - * [#10629] This fixture provisions its own business objects and nothing else, + * [commit 13a6cb4ad] This fixture provisions its own business objects and nothing else, * so the engine's single-tenant probe (`ObjectQL.probeInstallOrganizations`, * memoised once per engine) reads a `sys_organization` that was never created. * The probe is fail-soft by construction — it catches `isMissingTableError` and @@ -111,14 +111,14 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; describe('bulk-write hardening on a REAL SqlDriver (framework#3147–#3152, #3172, #3173)', () => { let dir: string | null = null; let engine: ObjectQL | null = null; - /** [#10629] The expected-noise capture belonging to the latest boot. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest boot. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave the engine running. Every test in this file // boots and writes, so the probe fires for each of them: this holds for a // single `-t` run as well as for the whole file. @@ -129,7 +129,7 @@ describe('bulk-write hardening on a REAL SqlDriver (framework#3147–#3152, #317 async function boot(objects: any[], plan: FaultPlan = {}) { dir = mkdtempSync(join(tmpdir(), 'os-bulk-real-')); const real = new SqlDriver({ client: 'better-sqlite3', connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true }); - // [#10629] Installed on the REAL driver (the one that logs) before it runs + // [commit 13a6cb4ad] Installed on the REAL driver (the one that logs) before it runs // a statement, and on the engine before it issues a read — the two sinks the // expected refusal travels out on. `wrapDriver` prototype-delegates, so the // wrapper resolves `logger` through the chain to this sink. diff --git a/packages/runtime/src/cascade-delete-multivalue-lookup-real-driver.integration.test.ts b/packages/runtime/src/cascade-delete-multivalue-lookup-real-driver.integration.test.ts index ef9ebf9a236..28306ca51a0 100644 --- a/packages/runtime/src/cascade-delete-multivalue-lookup-real-driver.integration.test.ts +++ b/packages/runtime/src/cascade-delete-multivalue-lookup-real-driver.integration.test.ts @@ -164,7 +164,7 @@ const SINGLE = { const OWNER_PACKAGE = 'com.objectstack.test.9362'; /** - * [#10629] This fixture provisions its own business objects and nothing else, + * [commit 13a6cb4ad] This fixture provisions its own business objects and nothing else, * so the engine's single-tenant probe (`ObjectQL.probeInstallOrganizations`, * memoised once per engine) reads a `sys_organization` that was never created. * The probe is fail-soft by construction — it catches `isMissingTableError` and @@ -371,14 +371,14 @@ function declareCascadeDeleteCell(cell: DialectCell): void { () => { let dir: string | null = null; let engine: ObjectQL | null = null; - /** [#10629] The expected-noise capture belonging to the latest rig. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest rig. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so // a failure here can never leave the engine running. Every test in this // file rigs and writes, so the probe fires for each of them: this holds // for a single `-t` run as well as for the whole file. @@ -405,7 +405,7 @@ function declareCascadeDeleteCell(cell: DialectCell): void { async function rig(objects: unknown[]) { const real = await newDriver(); - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. // [#18617] The reason half is this CELL'S dialect: the refusal line the // driver writes says `no such table: sys_organization` on SQLite and diff --git a/packages/runtime/src/cross-field-refusal-operand-withhold.test.ts b/packages/runtime/src/cross-field-refusal-operand-withhold.test.ts index 80a524aecd0..83dfbb628f2 100644 --- a/packages/runtime/src/cross-field-refusal-operand-withhold.test.ts +++ b/packages/runtime/src/cross-field-refusal-operand-withhold.test.ts @@ -337,10 +337,10 @@ describe('[#7929] a cross-field refusal keeps its envelope and stops disclosing */ let crudScope: FilterCondition | null = null; /** - * [#10983] Every read below that the driver refuses reaches this engine's + * [commit 6a4e929f5] Every read below that the driver refuses reaches this engine's * `find()`, so its `catch` logs an `ERROR Find operation failed` frame * BEFORE rethrowing (`engine.ts`) — a green-test noise instance of the - * same defect class #10629/#10630 closed, just without a table to key on + * same defect class commits 13a6cb4ad / dd8172ee2 closed, just without a table to key on * (the refusal never reaches `backendStatementFault`; see * `expected-read-refusal-noise.ts`'s second predicate for why and how). * Withheld and COUNTED here, never muted — `silentChannels()` and @@ -387,7 +387,7 @@ describe('[#7929] a cross-field refusal keeps its envelope and stops disclosing }); afterAll(() => { - // [#10983] The pin, not the mute: every declared object's channel fired + // [commit 6a4e929f5] The pin, not the mute: every declared object's channel fired // at least once, AND the count is exactly what this describe block's // five `it`s produce — six `ql.find()` calls refused (the sixth test // below drives the driver directly, bypassing this engine on purpose, diff --git a/packages/runtime/src/default-datasource-plugin.test.ts b/packages/runtime/src/default-datasource-plugin.test.ts index 415c3cd5535..3501f06ae71 100644 --- a/packages/runtime/src/default-datasource-plugin.test.ts +++ b/packages/runtime/src/default-datasource-plugin.test.ts @@ -26,7 +26,7 @@ const BOOT_TIMEOUT = 60_000; const ENV = 'OS_ALLOW_DRIVER_CONNECT_FAILURE'; /** - * [#10629] Exactly one case in this file writes through the booted engine, and + * [commit 13a6cb4ad] Exactly one case in this file writes through the booted engine, and * that write runs the engine's single-tenant probe * (`ObjectQL.probeInstallOrganizations`) against a `sys_organization` this * composition never creates. The probe is fail-soft by construction — it @@ -170,7 +170,7 @@ describe('DefaultDatasourcePlugin — the default datasource as a declaration (# const { createPrebuiltDriverFactory } = await import('@objectstack/service-datasource'); const { SqliteWasmDriver } = await import('@objectstack/driver-sqlite-wasm'); const hostBuilt = new SqliteWasmDriver({ filename: ':memory:' }); - // [#10629] Installed before the driver runs a statement; the engine half + // [commit 13a6cb4ad] Installed before the driver runs a statement; the engine half // is scoped after bootstrap, because the read it covers is the `insert` // below rather than anything the boot itself does. const noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); @@ -194,7 +194,7 @@ describe('DefaultDatasourcePlugin — the default datasource as a declaration (# await engine.insert('note', { title: 'through-the-adopted-default' }); const rows = await engine.find('note'); expect(rows.map((r: any) => r.title)).toContain('through-the-adopted-default'); - // [#10629] The capture is a PIN, not a mute: the probe's two log lines + // [commit 13a6cb4ad] The capture is a PIN, not a mute: the probe's two log lines // are withheld from the shared shard log and asserted here instead, so // a probe that stopped running goes red rather than merely quiet. expect(noise.silentChannels()).toEqual([]); diff --git a/packages/runtime/src/degraded-boot-parity.test.ts b/packages/runtime/src/degraded-boot-parity.test.ts index 3d94fe8866e..168c5662d89 100644 --- a/packages/runtime/src/degraded-boot-parity.test.ts +++ b/packages/runtime/src/degraded-boot-parity.test.ts @@ -86,7 +86,7 @@ async function bootDatasource(): Promise { }) as any, engine: () => ({ registerDriver: (d: any) => drivers.set(d.name, d), - // [#12010] The double stores a bare `{ name: 'd' }` stand-in, while + // [commit 77b91bdb4] The double stores a bare `{ name: 'd' }` stand-in, while // `ConnectionEngineLike.getDriverByName` is now derived from the engine // contract and answers `IDataDriver | undefined`. Narrowing on the way // out keeps the double as loose as this parity test needs it without diff --git a/packages/runtime/src/discovery-schema-conformance.test.ts b/packages/runtime/src/discovery-schema-conformance.test.ts index 0d98c901c6a..6a2b7812399 100644 --- a/packages/runtime/src/discovery-schema-conformance.test.ts +++ b/packages/runtime/src/discovery-schema-conformance.test.ts @@ -376,7 +376,7 @@ describe('[#4828] getDiscoveryInfo() conforms to DiscoverySchema', () => { // two different rules and #5673 deliberately moved only the first — #4828's // "never CLAIM production on a guess" is untouched, and this case is the // guard against a later simplification collapsing them back into one. - // [#6287] `preview` dropped out of this list when it gained a declared fold + // [commit 84c86fb45] `preview` dropped out of this list when it gained a declared fold // (`sandbox`) — it is an `EnvironmentTypeSchema` member, so it is no longer // an example of a spelling this repo does not recognise. The rule and its // remaining examples are untouched. diff --git a/packages/runtime/src/dispatcher-5xx-demoted-code-withhold.test.ts b/packages/runtime/src/dispatcher-5xx-demoted-code-withhold.test.ts index a471fad0823..c7ad0a14e5d 100644 --- a/packages/runtime/src/dispatcher-5xx-demoted-code-withhold.test.ts +++ b/packages/runtime/src/dispatcher-5xx-demoted-code-withhold.test.ts @@ -40,9 +40,9 @@ * * The MESSAGE. `errorResponseBase` still withholds on `declaresServerFault` * (which needs a string code) rather than on every declared 5xx; aligning it - * to `/data` is the same ruling's prose axis and it is #12281's card, with its + * to `/data` is the same ruling's prose axis and it is commit 0783d7b80's change, with its * own measurement-first step. Section 4 pins the message behaviour AS IT - * STANDS so that card's change is visible as a change rather than as a silent + * STANDS so that commit's change is visible as a change rather than as a silent * drift, and names what will move. */ @@ -257,12 +257,12 @@ describe('[#12509] the exits read the shared rule, they do not restate it', () = }); // --------------------------------------------------------------------------- -// 4. The prose axis, pinned AS IT STANDS — #12281's card, not this one +// 4. The prose axis, pinned AS IT STANDS — commit 0783d7b80's change, not this one // --------------------------------------------------------------------------- describe('[#12509] the MESSAGE axis — now widened by #12281, and the code axis is unaffected', () => { it('a declared 5xx WITH a code still has its prose withheld at errorResponseBase', async () => { - // Unchanged by #12281: this shape declared a 5xx, so it was withheld + // Unchanged by commit 0783d7b80: this shape declared a 5xx, so it was withheld // under `declaresServerFault` and is withheld under // `serverFaultProvenance`. Kept as the no-regression end of the band. const answer = await postAnalyticsQuery( @@ -276,13 +276,13 @@ describe('[#12509] the MESSAGE axis — now widened by #12281, and the code axis }); it('[#12281] a declared 5xx with NO code ALSO has its prose withheld now', async () => { - // ⚠️ FLIPPED, as this file said it would be. Until #12281 this asserted + // ⚠️ FLIPPED, as this file said it would be. Until commit 0783d7b80 this asserted // `'Data service not available'` on the wire, with the note: "When - // #12281 lands this expectation flips to the generic sentence — + // [commit 0783d7b80] lands this expectation flips to the generic sentence — // deliberately pinned so that lands as a CHANGE rather than as drift // nobody sees." This is that landing. // - // Ruled 2026-08-27 on #12509 (option D), propagated to #12281: + // Ruled 2026-08-27 on #12509 (option D), landed in commit 0783d7b80: // `errorResponseBase` adopts the structural withhold for EVERY declared // 5xx message. `serverFaultProvenance` reads `status ?? statusCode` and // does not consult `code`, so this shape — `action-execution.ts`'s @@ -299,7 +299,7 @@ describe('[#12509] the MESSAGE axis — now widened by #12281, and the code axis it('[#12281] an UNDECLARED 5xx still keeps its prose — the two axes stay independent', async () => { // The control that keeps the flip above honest. This file's own subject // is `demotedDeclaredCode`, which withholds the CODE on an undeclared - // 5xx; #12281 withholds the MESSAGE on a DECLARED one. They read + // 5xx; commit 0783d7b80 withholds the MESSAGE on a DECLARED one. They read // opposite limbs of `serverFaultProvenance`, so an edit that collapsed // them into "5xx ⇒ withhold everything" would go red here. const answer = await postAnalyticsQuery(thrown('no strategy can handle query for cube "pipeline"', {})); diff --git a/packages/runtime/src/dispatcher-error-vocabulary.ts b/packages/runtime/src/dispatcher-error-vocabulary.ts index 927f045cbe3..9535357d0ff 100644 --- a/packages/runtime/src/dispatcher-error-vocabulary.ts +++ b/packages/runtime/src/dispatcher-error-vocabulary.ts @@ -107,7 +107,7 @@ export type CodeStampShape = */ | 'codehelper' /** - * [#13233] The SAME code-carrying helper, stamping through an OBJECT + * [commit 3800e4293] The SAME code-carrying helper, stamping through an OBJECT * LITERAL instead of an assignment: `return { severity, code, message }` * (shorthand) or `{ code: errCode }` (longhand). * @@ -187,14 +187,14 @@ export type CodeStampShape = export type CodeDoor = 'dispatcher' | 'rest' | 'plugin-route' | 'none'; /** - * [#16649] `'boot-refusal'` was HERE, and is retired. It named a refusal raised + * [commit 44c917a47] `'boot-refusal'` was HERE, and is retired. It named a refusal raised * before any HTTP boundary exists — the CLI rethrows it and aborts — and until * #16404 the ledger ratified that class as not owed a row * (`MONGODB_MULTI_TENANT_UNSUPPORTED` was UNregistered by #8035 on "host boot * matching is not wire vocabulary"). #16404 deleted the exemption (the ledger * is the published face, door or no door), which left the verdict meaning only * "a registration this tree still owes" — #16449 discharged nine of those, - * #16649's first half the remaining fourteen, and the second half widened + * commit 613bfbd3d the remaining fourteen, and commit 44c917a47 widened * `check-dispatcher-error-vocabulary`'s face refusal from `packages/spec/src/` * to every published package's `src/`, which is what makes the verdict * unwritable: a row carrying it inside that face is now a @@ -308,7 +308,7 @@ export const UNREGISTERED_CODE_SITES: readonly UnregisteredCodeSite[] = [ // `check:dispatcher-error-vocabulary` refuses any verdict there but // `foreign-vocabulary` / `runtime-pinned`. ── // - // ── [#16649] Fourth cycle, the rest of that class: the fourteen + // ── [commit 613bfbd3d] Fourth cycle, the rest of that class: the fourteen // `boot-refusal` rows that remained after #16449 — the nine // `@objectstack/core` refusals (the three ADR-0130 D4 artifact-package // refusals, the four `MigrationJournalRefusal` codes, @@ -321,7 +321,7 @@ export const UNREGISTERED_CODE_SITES: readonly UnregisteredCodeSite[] = [ // (`stale-row`), the reachability each row recorded now carried on its // ledger row. // - // ── [#16649, second half] The class is now closed MECHANICALLY rather than + // ── [commit 44c917a47, second half] The class is now closed MECHANICALLY rather than // by having been emptied once. `check-dispatcher-error-vocabulary`'s face // refusal, which #16449 could only afford over `packages/spec/src/`, covers // every published package's `src/` — the whole of this scan's population on @@ -483,7 +483,7 @@ export const UNREGISTERED_CODE_SITES: readonly UnregisteredCodeSite[] = [ // `invisible`: each refusal IS served to the client, in the vendor's flat // `{ message, code }` shape. That this endpoint's bodies are the vendor's // wire rather than this repo's envelope is not inferred here — it is the - // 2026-08-21 maintainer ruling (#10554), carried in `check-route-envelope` + // 2026-08-21 maintainer ruling (landed in commit 6abc4df03), carried in `check-route-envelope` // as the `vendorWire` entry for this same file. // // ⛔ `pending-registration` would be FALSE for all four. That verdict says @@ -694,9 +694,9 @@ export const UNREGISTERED_CODE_SITES: readonly UnregisteredCodeSite[] = [ 'that a live wire code is outside the vocabulary; it does not prescribe the remedy.', }, - // ── pending registration [#14921]: a metadata-tree refusal that reaches a + // ── pending registration [commit c1d274de7]: a metadata-tree refusal that reaches a // ── dispatcher-door read ─────────────────────────────────────────────── - // Not a widened scan and not a demotion: this producer is NEW. #14921 made + // Not a widened scan and not a demotion: this producer is NEW. Commit c1d274de7 made // `FilesystemLoader.list()` (and the shared `loadMany()` walk behind it) // refuse a metadata name derived from more than one file, where before it // reported the name twice and served the first by extension precedence. @@ -731,7 +731,7 @@ export const UNREGISTERED_CODE_SITES: readonly UnregisteredCodeSite[] = [ + 'that batch\'s input, and the registration is what ratchets it out again.', }, - // ── [#13233] field-level catalogs, reached by the OBJECT-LITERAL helper ── + // ── [commit 3800e4293] field-level catalogs, reached by the OBJECT-LITERAL helper ── // // The 29 rows below are the whole verdict cost of widening `codehelper` to // the object-literal stamp position, and they are one genre from end to @@ -1221,7 +1221,7 @@ export const UNREGISTERED_CODE_SITES: readonly UnregisteredCodeSite[] = [ ]; /** - * [#13233] Why a helper's codes cannot be read from source, and whether that + * [commit 3800e4293] Why a helper's codes cannot be read from source, and whether that * matters. A DIFFERENT question from {@link CodeVerdict}, so a different * vocabulary — a site row answers "does this code reach a wire and is it * registered", and none of its members can answer "we never learn the value". @@ -1257,7 +1257,7 @@ export type UnresolvedHelperVerdict = | 'restamped-elsewhere'; /** - * [#13233] A code-carrying helper this scan can SEE but cannot READ: the stamp + * [commit 3800e4293] A code-carrying helper this scan can SEE but cannot READ: the stamp * resolves to a parameter, and no in-file call site passes a value that reduces * to a literal. * @@ -1276,7 +1276,7 @@ export type UnresolvedHelperVerdict = * So the helper is classified here instead, with a door, a verdict and its * evidence, and the gate reconciles this list in BOTH directions: an entry the * scan no longer reports goes stale and REDS, exactly like a site row. ⭐ That - * is what makes it a widening rather than an exemption — before #13233 none of + * is what makes it a widening rather than an exemption — before commit 3800e4293 none of * these helpers produced a site OR an unresolved, because no shape reached * them; now every one is recorded, evidenced, and ratcheted. * diff --git a/packages/runtime/src/dispatcher-plugin.declared-5xx-prose-withhold.test.ts b/packages/runtime/src/dispatcher-plugin.declared-5xx-prose-withhold.test.ts index 106f8b1dfe1..658da6bcb99 100644 --- a/packages/runtime/src/dispatcher-plugin.declared-5xx-prose-withhold.test.ts +++ b/packages/runtime/src/dispatcher-plugin.declared-5xx-prose-withhold.test.ts @@ -1,16 +1,16 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#12281] `errorResponseBase` withholds the message of EVERY **declared** 5xx, + * [commit 0783d7b80] `errorResponseBase` withholds the message of EVERY **declared** 5xx, * aligning this exit to `/data` — and still keeps an **undeclared** 5xx legible. * * ## The ruling this pins * - * Maintainer, 2026-08-27, on #12509 (option D), propagated verbatim to #12281: + * Maintainer, 2026-08-27, on #12509 (option D), landed in commit 0783d7b80: * * > `errorResponseBase` adopts the **structural withhold for every declared 5xx * > message**, aligning to `/data`'s rule; the author-facing text channel is - * > `userMessage` (#9934), never the raw message. + * > `userMessage` [commit 79c46da90], never the raw message. * * ## The two axes it closes * @@ -36,7 +36,7 @@ * * ## ⛔ Why every case below DRIVES the shape rather than asserting the predicate * - * The #12281 measurement established that the population reaching this door is + * Commit 0783d7b80's measurement established that the population reaching this door is * **EMPTY** today: `metadata-protocol`'s `deleteMetaItem` reaches only the REST * `/meta` door (the dispatcher plugin mounts neither `/meta` nor `/data`), and * `action-execution.ts`'s seven `statusCode` throws are all caught before this diff --git a/packages/runtime/src/dispatcher-plugin.declared-user-message.test.ts b/packages/runtime/src/dispatcher-plugin.declared-user-message.test.ts index ad544acf961..b6235b9c711 100644 --- a/packages/runtime/src/dispatcher-plugin.declared-user-message.test.ts +++ b/packages/runtime/src/dispatcher-plugin.declared-user-message.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#13241] `errorResponseBase` carries the producer's `userMessage` to the wire + * [commit a21d2a9cf] `errorResponseBase` carries the producer's `userMessage` to the wire * — the author-facing text channel the declared-5xx prose withhold names as its * own compensation, and the one ADR-0112 boundary that dropped it. * @@ -29,10 +29,10 @@ * * ## Why this is the compensation channel and not a decoration * - * The 2026-08-27 ruling on #12509 (option D), propagated to #12281, made this + * The 2026-08-27 ruling on #12509 (option D), landed in commit 0783d7b80, made this * exit withhold the message of every **declared** 5xx: * - * > the author-facing text channel is `userMessage` (#9934), never the raw + * > the author-facing text channel is `userMessage` [commit 79c46da90], never the raw * > message. * * That sentence only holds if the channel exists here. Before this change a @@ -43,7 +43,7 @@ * * ## ⚠️ Status-agnostic, which is wider than the card's framing * - * #9934 made the mark status-agnostic on purpose ("a 400, 403, 409 or 503 + * Commit 79c46da90 made the mark status-agnostic on purpose ("a 400, 403, 409 or 503 * refusal may all carry it"), so the gap here was never confined to the * declared-5xx band that motivated it: a marked **4xx** refusal reaching this * exit lost the field too, with no withhold anywhere in the picture. `§2` drives @@ -194,14 +194,14 @@ describe('[#13241] the dispatcher throw-transparent exit carries `userMessage`', expect(res.statusCode).toBe(503); expect(res.body.success).toBe(false); - // The withhold still holds — this change must not re-open #12281. + // The withhold still holds — this change must not undo commit 0783d7b80. expect(res.body.error.message).toBe(INTERNAL_ERROR_MESSAGE); expect(JSON.stringify(res.body)).not.toContain('acme_prod'); // …and the author's channel now survives it. expect(res.body.error.userMessage).toBe('Reporting is briefly offline. Try again in a few minutes.'); - // The mark never MOVES the status or the code (#9934's third + // The mark never MOVES the status or the code (commit 79c46da90, the ruling's third // constraint) — a marked fault is still the sanitised fault. expect(res.body.error.code).toBe('SERVICE_UNAVAILABLE'); }); @@ -209,7 +209,7 @@ describe('[#13241] the dispatcher throw-transparent exit carries `userMessage`', it('an UNMARKED declared 5xx is byte-identical to before — the mark is opt-in', async () => { // The regression guard on the paragraph above: if the field were // synthesised from `message` rather than read from the throw, the - // withheld prose would ride out on the new channel and #12281 would + // withheld prose would ride out on the new channel and commit 0783d7b80 would // be undone by its own compensation. const res = await throwFromAnalyticsQuery( declaring({ status: 503, code: 'SERVICE_UNAVAILABLE' }, 'Upstream warehouse pool exhausted for tenant acme_prod.'), @@ -299,7 +299,7 @@ describe('[#13241] the dispatcher throw-transparent exit carries `userMessage`', expect(res.statusCode).toBe(403); expect(res.body.error.code).toBe('PERMISSION_DENIED'); // The half this card repaired: the author's channel now survives - // the denial door too (#9934 is status-agnostic, and 403 is the + // the denial door too (commit 79c46da90's mark is status-agnostic, and 403 is the // refusal class most likely to carry authored text). expect(res.body.error.userMessage).toBe('Ask an admin for the Reporting role.'); // …verbatim, and never in place of the diagnostic channel. diff --git a/packages/runtime/src/dispatcher-plugin.ts b/packages/runtime/src/dispatcher-plugin.ts index acbf6f9366a..ebf50bc224a 100644 --- a/packages/runtime/src/dispatcher-plugin.ts +++ b/packages/runtime/src/dispatcher-plugin.ts @@ -600,7 +600,7 @@ function sendResultBase( * boundaries. ⛔ It is NOT "withhold every 5xx" — #5667 kept UNDECLARED 5xx * legible on purpose, and a bare `Error` still goes through the heuristic alone. * - * [#12281] A fifth, and the reason that predicate is now {@link + * [commit 0783d7b80] A fifth, and the reason that predicate is now {@link * serverFaultProvenance}: `declaresServerFault` required a non-empty string * `code` beside the 5xx and read the `status` spelling only, so this exit * withheld a NARROWER band than `/data` — a declared 5xx with no code, and a @@ -618,7 +618,7 @@ function sendResultBase( * into `errorReporter` and the log. * * ⚠️ It reaches the client at `error.code` — NOT `error.details.code`, which is - * where this note pointed until #6270 corrected it (#6123 corrected the same + * where this note pointed until #6270 corrected it (commit 59d1933f9 corrected the same * sentence at three sibling sites). The `details` assembly below (#3842) only * STAGES the code in a local object; `buildApiError` then runs * `splitSemanticCode` (`./error-envelope.ts`), which PROMOTES it into the declared @@ -681,14 +681,14 @@ function errorResponseBase( const raw = err?.message; // [#3842] A thrown error's own `.code` finally has somewhere to go — see the // `declaredCode` note below for WHICH spelling travels. Resolved HERE, above - // the message ternary, because [#12281] that ternary now reads the same + // the message ternary, because [commit 0783d7b80] that ternary now reads the same // resolver answer: one read of the throw, one set of facts, so the prose rule // and the code rule can never be looking at different errors. const thrown = resolveThrownHttpError(err, 500); - // [#5811/#12281] Two independent reasons to withhold, both 5xx-only. The + // [#5811 / commit 0783d7b80] Two independent reasons to withhold, both 5xx-only. The // declaration comes first because it needs no guess about the text. // - // [#12281] The declaration limb is `serverFaultProvenance(thrown) === + // [commit 0783d7b80] The declaration limb is `serverFaultProvenance(thrown) === // 'declared'` — the ONE definition of "the producer named this 5xx itself" // (`@objectstack/types`), ruled 2026-08-27 (option D) and already read by // `demotedDeclaredCode` for the code channel. ⛔ Not re-derived here: "one @@ -712,7 +712,7 @@ function errorResponseBase( // goes through the heuristic alone. A naive `httpStatus >= 500` test would // silently delete that, which is the one way this change could do harm. // - // The author-facing text channel is `userMessage` (#9934), never the raw + // The author-facing text channel is `userMessage` (commit 79c46da90), never the raw // message — a producer whose 5xx prose is addressed to a human declares it // there and it survives the withhold on its own channel. // @@ -732,7 +732,7 @@ function errorResponseBase( // name. // // ⛔ Still NOT a widening of the `'declared'` limb. Absent the flag this - // expression is byte-identical, so #12281's structural withhold is intact + // expression is byte-identical, so commit 0783d7b80's structural withhold is intact // for every producer that declares a FAULT — which is the default, and the // only thing a rewrap can carry. The shared read is fail-closed on its own // account too: it requires a declared in-band 5xx, a non-empty string @@ -759,7 +759,7 @@ function errorResponseBase( // statusCode → validation 400 → 500), so the two reads cannot disagree. A // non-string `.code` (a driver errno) stays in `details`, as context. const declaredCode = demotedDeclaredCode(thrown); - // [#13241] The author-facing text channel the withhold above assumes as its + // [commit a21d2a9cf] The author-facing text channel the withhold above assumes as its // compensation. `resolveThrownHttpError` ALREADY answered whether the throw // declared one — `thrown.userMessage` is `declaredUserMessage`'s non-empty // string rule, the ONE read every boundary applies (`@objectstack/types`) — @@ -771,7 +771,7 @@ function errorResponseBase( // stop, which is why the shared resolver's field is read rather than // `err.userMessage` probed inline. // - // ⚠️ Status-agnostic on purpose (#9934's second constraint) — a 400, 403 or + // ⚠️ Status-agnostic on purpose (the ruling's second constraint, commit 79c46da90) — a 400, 403 or // 409 refusal may carry the mark too, so this is NOT gated on the 5xx limb // above. The withhold touches only the diagnostic `message`; the marked // channel is text an author deliberately addressed to the end user, so it diff --git a/packages/runtime/src/domains/action-activation-posture-gate.test.ts b/packages/runtime/src/domains/action-activation-posture-gate.test.ts index 80ea2ec7758..756a2048322 100644 --- a/packages/runtime/src/domains/action-activation-posture-gate.test.ts +++ b/packages/runtime/src/domains/action-activation-posture-gate.test.ts @@ -27,7 +27,7 @@ // // `status` AND `code` (the ADR-0112 envelope), AND that the engine's // `setActionActive` was never entered — a gate that refused after the ledger -// was written would still be #10243, with persistence. +// was written would still be the leak commit 02b41232d measured, with persistence. import { describe, it, expect, vi } from 'vitest'; @@ -282,7 +282,7 @@ describe('ADR-0126 §5 — the action activation write is operator-gated in wall // Sweeping a run surface into a metadata gate would lock every // ordinary user out of the actions built for them — the one - // thing the #10243 ruling did not do. + // thing the ruling commit 266436a7f landed did not do. expect(statusOf(res)).toBe(200); expect(h.executeAction).toHaveBeenCalled(); }); diff --git a/packages/runtime/src/domains/actions-fault-vs-rejection.test.ts b/packages/runtime/src/domains/actions-fault-vs-rejection.test.ts index 7721ab23c64..35b77965e27 100644 --- a/packages/runtime/src/domains/actions-fault-vs-rejection.test.ts +++ b/packages/runtime/src/domains/actions-fault-vs-rejection.test.ts @@ -217,10 +217,10 @@ describe('an unexpected FAULT is a 500', () => { }); /** - * [#17273] A sandboxed body that CRASHED is a fault — the face of #15071 this + * [#17273] A sandboxed body that CRASHED is a fault — the face of commit cf6e0a193 this * door left open. * - * #15071 ruled on the `/data` door: *"A declared code is the author's statement + * Ruled on the `/data` door (commit cf6e0a193): *"A declared code is the author's statement * about the failure mode they **handled**. A crash (`isScriptFaultMessage`, * #7543) is not that mode, so it is classified as a fault"*. This door read the * question the other way round. The table above states the discriminator as the @@ -289,7 +289,7 @@ describe('[#17273] a sandboxed body that CRASHED is a fault, not a rejection', ( }); it('negative control: a sandboxed DELIBERATE throw keeps its 400 and its own sentence', async () => { - // One `innerMessage` away from the first case. #15071's ruling fences + // One `innerMessage` away from the first case. Commit cf6e0a193's ruling fences // this explicitly — *"Ordinary declared refusals … are **untouched** — // only the crash branch moves"* — and an implementation that degraded // every sandbox-origin error to the fault terminal would turn the two @@ -336,7 +336,7 @@ describe('[#17273] a sandboxed body that CRASHED is a fault, not a rejection', ( * "message":"Cannot read properties of undefined (reading 'id')","httpStatus":500}} * * The same crash through the `/data` door answered `"Internal server error"` - * (#7543 / #15071). ⇒ the status was already right; what leaked was the + * (#7543 / commit cf6e0a193). ⇒ the status was already right; what leaked was the * sentence. * * **The shape worth carrying: a predicate that classifies by HOW a crash diff --git a/packages/runtime/src/domains/actions.ts b/packages/runtime/src/domains/actions.ts index 5aa9ba6dd77..f4a0f99ab35 100644 --- a/packages/runtime/src/domains/actions.ts +++ b/packages/runtime/src/domains/actions.ts @@ -122,7 +122,7 @@ function isActionActivationWrite(parts: string[], method: string): boolean { * * ## Order of operations, and why each step is where it is * - * 1. **Both authority gates, first.** `manage_metadata` (#10243: switching a + * 1. **Both authority gates, first.** `manage_metadata` (commit 266436a7f: switching a * shipped artifact off is functionally equivalent to deleting it), then the * ADR-0126 §5 posture gate. Ahead of the body checks and ahead of any * lookup, so a refused caller writes nothing and learns nothing — neither @@ -638,7 +638,7 @@ export async function handleActionsRequest(deps: DomainHandlerDeps, path: string } // Load the record (best-effort) so handlers can rely on `ctx.record`. - // [#14143] Through the ONE shared producer `loadActionSubjectRecord`, which + // [commit f19475c0a] Through the ONE shared producer `loadActionSubjectRecord`, which // also reports whether the CALLER's own scope actually delivered the row. // This door and the MCP `run_action` door must emit the same signal: a // documented guard (`if (ctx.recordLoadDenied) …`) that only one of two @@ -707,7 +707,7 @@ export async function handleActionsRequest(deps: DomainHandlerDeps, path: string // #15079 wrote into the declarative executor, now read by the flow door // and the script/body door as well. A signal only one of three doors // consumed is an authorization rule silently inert on the other two, - // which is the #14143 / #15168 failure class on this exact seam. + // which is the commit f19475c0a / #15168 failure class on this exact seam. // // Inside the `try`, like the declarative branch above, so the 404 takes // the ONE catch this door already has and is served with its `.status` / @@ -719,7 +719,7 @@ export async function handleActionsRequest(deps: DomainHandlerDeps, path: string const actionContext: any = { record, - // [#14143] The caller-scope load's verdict — see + // [commit f19475c0a] The caller-scope load's verdict — see // `loadActionSubjectRecord`. `ctx.record.id` is stamped either way, so // this is the only channel that distinguishes "the caller cannot read // this row" from "this action legitimately has no record". @@ -756,7 +756,7 @@ export async function handleActionsRequest(deps: DomainHandlerDeps, path: string // the flow context's `record` AND its `recordLoadDenied` // sibling from the same load outcome, so this door and the // MCP one cannot diverge on the signal the way the two - // doors diverged before #14143. + // doors diverged before commit f19475c0a. subject, params: reqParams, recordId, @@ -884,7 +884,7 @@ export async function handleActionsRequest(deps: DomainHandlerDeps, path: string // `ReferenceError` / a driver's own class "is a crash (500)") and the // header of this very file (`did it reject or crash? … crash → 500`). // - // The rule is #15071's, ruled on the `/data` door and quoted there + // The rule is commit cf6e0a193's, ruled on the `/data` door and quoted there // rather than restated: *"A declared code is the author's statement // about the failure mode they **handled**. A crash … is not that mode, // so it is classified as a fault"*. This is the same terminal at the diff --git a/packages/runtime/src/domains/activation-gate-positions-name-authority.test.ts b/packages/runtime/src/domains/activation-gate-positions-name-authority.test.ts index ee6e9269993..04cffaa954e 100644 --- a/packages/runtime/src/domains/activation-gate-positions-name-authority.test.ts +++ b/packages/runtime/src/domains/activation-gate-positions-name-authority.test.ts @@ -20,7 +20,7 @@ // // ⭐ WHAT THE ESCALATION BUYS, driven rather than argued: this gate is the ONLY // thing standing between a tenant org admin and the install-wide activation -// row under a walled posture. It is #10243 exactly — a tenant org owner +// row under a walled posture. It is exactly the leak commit 02b41232d measured — a tenant org owner // switching a shipped flow off ENVIRONMENT-WIDE — except that ADR-0126 made // the row DURABLE, so the same leak now survives a cold boot. The arms below // drive the real `POST /automation/:name/toggle` route and assert on whether @@ -206,7 +206,7 @@ for (const posture of ['group', 'isolated'] as const) { expect(codeOf(response)).toBe('PERMISSION_DENIED'); // The load-bearing assertion: refused BEFORE the write. A gate that // wrote the install-wide row and then refused would satisfy the two - // above and still be #10243. + // above and still be the leak commit 02b41232d measured. expect(h.toggleFlow).not.toHaveBeenCalled(); }); diff --git a/packages/runtime/src/domains/activation-gate.ts b/packages/runtime/src/domains/activation-gate.ts index b7e7b2c96dc..b31ba9672a4 100644 --- a/packages/runtime/src/domains/activation-gate.ts +++ b/packages/runtime/src/domains/activation-gate.ts @@ -25,7 +25,7 @@ * is inert. * - **`group` / `isolated`** — a real multi-organization deployment. Here the * write requires the PLATFORM OPERATOR, because a tenant org admin flipping - * an install-wide switch is precisely #10243: that incident measured a + * an install-wide switch is precisely the leak commit 02b41232d measured: a * tenant org owner switching a shipped flow off ENVIRONMENT-WIDE, read back * by an unrelated tenant in a different organization. ADR-0126 §5 makes * that durable in the correct direction — and a durable install-wide row @@ -64,7 +64,7 @@ * * Driven, not argued: with the minted row present, a tenant org admin holding * only the org-scoped `manage_metadata` capability flipped the install-wide - * switch under both walled postures — #10243 again, now with a DURABLE row. + * switch under both walled postures — the same leak commit 02b41232d measured, now with a DURABLE row. * See `activation-gate-positions-name-authority.test.ts`. * * ## Fail-open on an ABSENT posture is deliberate, not a gap @@ -93,7 +93,7 @@ export const ACTIVATION_DENY_CODE = 'PERMISSION_DENIED'; /** * [ADR-0066 D1 / #10145] The authoring capability every door onto the metadata - * plane demands — and, since the #10243 ruling, the activation switch too: + * plane demands — and, since the ruling commit 266436a7f landed, the activation switch too: * *"Disabling a shipped flow is functionally equivalent to deleting it for as * long as it stays off"*, and `DELETE` already required it. Actions inherit the * sentence with one word changed. @@ -149,7 +149,7 @@ export const ACTION_ACTIVATION_SUBJECT: ActivationSubject = { * ⚠️ Callers MUST run this BEFORE the write is attempted and before body * validation, so a refused caller writes nothing and learns nothing about the * contract. "Write first, refuse second" is the worst shape here — it is - * #10243 with an audit trail. + * the leak commit 02b41232d measured, with an audit trail. * * ⚠️ It has THREE exits, not two: a refusal, `undefined` to proceed, and a * THROW. See the posture read below for the class that throws and why a caller @@ -246,7 +246,7 @@ export async function refuseUngrantedActivationWrite( } /** - * [#10145 / #10243] The capability tier that sits IN FRONT of the §5 gate: the + * [#10145 / commit 266436a7f] The capability tier that sits IN FRONT of the §5 gate: the * caller must hold `manage_metadata` before the posture question is even asked. * * The `/automation` domain enforces this through its own diff --git a/packages/runtime/src/domains/automation-activation-posture-gate.test.ts b/packages/runtime/src/domains/automation-activation-posture-gate.test.ts index 9f45dd42f2d..5191a67e7a3 100644 --- a/packages/runtime/src/domains/automation-activation-posture-gate.test.ts +++ b/packages/runtime/src/domains/automation-activation-posture-gate.test.ts @@ -18,7 +18,7 @@ // // ## What this is made durable against // -// #10243, measured over HTTP: on a real `isolated` posture a tenant org owner +// The leak commit 02b41232d measured over HTTP: on a real `isolated` posture a tenant org owner // switched a shipped flow off through this very route and an unrelated tenant // in a DIFFERENT organization read it off — environment-wide reach from a // tenant caller. That leak went through a PROCESS-LOCAL map, so a cold boot @@ -191,7 +191,7 @@ describe('ADR-0126 §5 — the activation write is operator-gated in walled post expect(codeOf(response)).toBe('PERMISSION_DENIED'); // The load-bearing assertion: refused BEFORE the write. A gate // that wrote the row and then refused would satisfy the two - // above and still be #10243. + // above and still be the leak commit 02b41232d measured. expect(h.toggleFlow).not.toHaveBeenCalled(); }); @@ -275,7 +275,7 @@ describe('ADR-0126 §5 — the activation write is operator-gated in walled post // `POST /automation/trigger/toggle` RUNS a flow literally named // `toggle`; gating it would over-block an execution door, which - // is the one thing the #10243 ruling did not do. + // is the one thing the ruling commit 266436a7f landed did not do. expect(h.toggleFlow).not.toHaveBeenCalled(); }); }); diff --git a/packages/runtime/src/domains/automation-flow-clone.test.ts b/packages/runtime/src/domains/automation-flow-clone.test.ts index e3be8f3b33a..2ef9ba8ac08 100644 --- a/packages/runtime/src/domains/automation-flow-clone.test.ts +++ b/packages/runtime/src/domains/automation-flow-clone.test.ts @@ -7,9 +7,9 @@ * place. Three of the ADR's rules are the reason this file exists, and each has * a measurement behind it rather than a preference: * - * 1. **Whole-definition copy.** The centrepiece here is the #11703 + * 1. **Whole-definition copy.** The centrepiece here is the facet-drop (commit 5cb62d88b) * counter-example expressed as a test: the cloned definition must deep-equal - * its source apart from the three fields a clone mutates. #11703 measured a + * its source apart from the three fields a clone mutates. Commit 5cb62d88b records a * clone assembled from an ENUMERATED facet list dropping three of six facets * in silence — the record was created, the success toast fired, and the * difference was discoverable only by diffing the two rows. A flow has far @@ -68,7 +68,7 @@ const CTX = { request: {}, executionContext: { userId: 'user_1', systemPermissio * `MetadataProtectionFields`, so these are part of the parsed definition, not * decoration around it). * - * Deliberately fat. The #11703 lesson is that a clone test passes trivially + * Deliberately fat. The lesson of commit 5cb62d88b is that a clone test passes trivially * when the fixture has nothing to lose, so {@link EXEMPLAR_FACET_FLOOR} below * pins that this exemplar keeps exercising the assertion. */ @@ -180,7 +180,7 @@ describe('#12156 — whole-definition copy (the #11703 counter-example as a test expect(facetKeys.length).toBeGreaterThanOrEqual(EXEMPLAR_FACET_FLOOR); // THE assertion. Not a spot-check of `nodes`/`edges` — an enumerated - // check is the very shape #11703 measured failing, so the comparison is + // check is the very shape commit 5cb62d88b records failing, so the comparison is // whole-object or it is nothing. expect(omit(clone, FLOW_CLONE_MUTATED_FIELDS)).toEqual( omit(source, [...FLOW_CLONE_MUTATED_FIELDS, ...FLOW_CLONE_DROPPED_KEYS]), diff --git a/packages/runtime/src/domains/automation-resume-envelope.test.ts b/packages/runtime/src/domains/automation-resume-envelope.test.ts index 01bdfec5545..f3d1e95cd85 100644 --- a/packages/runtime/src/domains/automation-resume-envelope.test.ts +++ b/packages/runtime/src/domains/automation-resume-envelope.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #8796 — the resume body's OUTER envelope is a closed set. + * Commit a4331227b — the resume body's OUTER envelope is a closed set. * * `POST /automation/:name/runs/:runId/resume` assembles its engine signal * field-by-field from the body — deliberately (#3801: never spread the body, or @@ -10,7 +10,7 @@ * ones read. Measured on GA: `{"nodeId":"ask","values":{…}}` — no key of which * the route reads — answered HTTP 200 `success:true` with the screen submission * treated as EMPTY; the run completed and the submitted value never reached the - * flow. Maintainer ruling 2026-08-15 (Option A, on #8796): an unknown top-level + * flow. Maintainer ruling 2026-08-15 (Option A, landed in commit a4331227b): an unknown top-level * key is refused, located, naming the offending key(s) and the accepted set — * exactly `inputs` / `variables` / `output` / `branchLabel`. * diff --git a/packages/runtime/src/domains/automation-resume-value-shape.test.ts b/packages/runtime/src/domains/automation-resume-value-shape.test.ts index d66ac477a6e..c6a8ad46f85 100644 --- a/packages/runtime/src/domains/automation-resume-value-shape.test.ts +++ b/packages/runtime/src/domains/automation-resume-value-shape.test.ts @@ -4,7 +4,7 @@ * #9416 — the resume body refuses a MIS-SHAPED VALUE on an accepted key, and a * body that is not a JSON object at all. * - * #8796 closed the resume envelope's KEY set; this is the same silent-drop + * Commit a4331227b closed the resume envelope's KEY set; this is the same silent-drop * family one axis over, on the VALUE. The assembly type-guarded each accepted * key and skipped whatever failed the guard, so `{"inputs":"a string"}` passed * the closed key set (the key IS accepted), lost its value, and answered HTTP @@ -16,7 +16,7 @@ * * Maintainer ruling on the card — **Option A**: refuse, 400, located, naming * the key and the expected type; non-object and array bodies refuse the same - * way. It inherits #8796's ruling together with its reason, plus #3899's + * way. It inherits the ruling commit a4331227b landed together with its reason, plus #3899's * toggle-arm precedent (a truthy non-boolean `enabled` is refused there, never * coerced or dropped). ⛔ Option B — forward the raw value and let the engine * judge — was rejected: `ResumeSignal` types `variables`/`output` as @@ -184,7 +184,7 @@ describe('#9416 — a type-mismatched value on an accepted key is refused, not d it('refuses the mis-shaped value even when a sibling key is perfectly valid', async () => { // The half-wrong body must not be silently half-dropped — the same - // reasoning #8796 used to decline "refuse only when nothing is + // reasoning commit a4331227b used to decline "refuse only when nothing is // recognized". const r = await refusalFor({ inputs: { real: 'value' }, branchLabel: 7 }); expect(r.details?.fields).toMatchObject([{ field: 'branchLabel', code: 'invalid_type' }]); @@ -194,7 +194,7 @@ describe('#9416 — a type-mismatched value on an accepted key is refused, not d it('reports an unknown KEY ahead of a mis-shaped value — #8796 message unchanged', async () => { // Ordering pin: a body that is both misspelled and mis-shaped still // reports the misspelling, which is the correction the caller needs - // first and the one #8796 pinned. + // first and the one commit a4331227b pinned. const r = await refusalFor({ inputs: 'a string', values: { x: 1 } }); expect(r.details?.fields).toMatchObject([{ field: 'values', code: 'unknown_field' }]); expect(r.message).toMatch(/`values`/); diff --git a/packages/runtime/src/domains/automation-run-lifecycle-door.test.ts b/packages/runtime/src/domains/automation-run-lifecycle-door.test.ts index a1a4ac81486..c40d2bdda04 100644 --- a/packages/runtime/src/domains/automation-run-lifecycle-door.test.ts +++ b/packages/runtime/src/domains/automation-run-lifecycle-door.test.ts @@ -243,9 +243,9 @@ describe('#13953 — the run-lifecycle doors require the platform operator', () it('leaves the legacy execution door alone — `POST /automation/trigger/:name` for a flow named `runs`', async () => { // The gate excludes `parts[0] === 'trigger'`, exactly as the toggle - // (#10243) and clone (#12156) arms do, and BOTH route arms repeat + // (commit 266436a7f) and clone (#12156) arms do, and BOTH route arms repeat // the exclusion so gate and route cannot drift. Over-blocking an - // execution door is the one thing the #10243 ruling did not do. + // execution door is the one thing the ruling commit 266436a7f landed did not do. const h = makeDispatcher(); const { response } = await h.dispatcher.handleAutomation( 'trigger/runs/run_7/cancel', 'POST', undefined, USER_CTX(), undefined, diff --git a/packages/runtime/src/domains/automation-toggle-deny-message.test.ts b/packages/runtime/src/domains/automation-toggle-deny-message.test.ts index 6e6b750707c..1d326cd6694 100644 --- a/packages/runtime/src/domains/automation-toggle-deny-message.test.ts +++ b/packages/runtime/src/domains/automation-toggle-deny-message.test.ts @@ -5,7 +5,7 @@ * * ## The defect, exactly * - * #10243's ruling put the enablement door into the `manage_metadata` authoring + * Commit 266436a7f's ruling put the enablement door into the `manage_metadata` authoring * write set, and #11660 landed it by adding one arm to `isFlowAuthoringWrite`. * The refusal that arm reached was the shared one: * @@ -174,7 +174,7 @@ describe('#11666 — the enablement door refuses in its own words', () => { }); it('says the same thing in both directions — enabling and disabling', async () => { - // #10243's measurement was symmetric, and a caller switching a flow + // Commit 02b41232d's measurement was symmetric, and a caller switching a flow // ON is no more "authoring" than one switching it off. const h = boot(); diff --git a/packages/runtime/src/domains/automation-toggle-unknown-flow.test.ts b/packages/runtime/src/domains/automation-toggle-unknown-flow.test.ts index c52761defc7..d3a3ad9b599 100644 --- a/packages/runtime/src/domains/automation-toggle-unknown-flow.test.ts +++ b/packages/runtime/src/domains/automation-toggle-unknown-flow.test.ts @@ -54,7 +54,7 @@ function makeDispatcher(flowNames: string[] = ['welcome_flow']) { } /** - * [#10243] The caller now holds `manage_metadata`. + * [commit 266436a7f] The caller now holds `manage_metadata`. * * This file is about ERROR MAPPING on `POST /:name/toggle` — that an unknown * flow is a 404 rather than a 500, and that a malformed body is a 400. Its diff --git a/packages/runtime/src/domains/automation-write-capability-gate.test.ts b/packages/runtime/src/domains/automation-write-capability-gate.test.ts index c19b7198bc6..6b8f4140481 100644 --- a/packages/runtime/src/domains/automation-write-capability-gate.test.ts +++ b/packages/runtime/src/domains/automation-write-capability-gate.test.ts @@ -33,12 +33,12 @@ * `stays ungated` block below is the audit that makes any future change to * those verdicts come through this file. * - * ## [#10243] `POST /:name/toggle` CROSSED that line — deliberately, by ruling + * ## [commit 266436a7f] `POST /:name/toggle` CROSSED that line — deliberately, by ruling * * ⭐ This is the flip, recorded here rather than left to be discovered. #10145 * pinned toggle as ungated **in the open**, saying the verdict was a product * call and not a code call, so that a change to it would land in this file and - * be visible. It was filed as #10243, measured over HTTP, and ruled on + * be visible. It was filed, measured over HTTP (commit 02b41232d), and ruled on * 2026-08-23: toggle joins the `manage_metadata` write set. One arm on the * existing `isFlowAuthoringWrite`; ⛔ no new capability name (option C was * declined). @@ -175,7 +175,7 @@ const codeOf = (response: unknown): unknown => { /** * The gated writes, each with the service method it must never reach. * - * [#10243] Four, not three: `POST /:name/toggle` joined by ruling. It is listed + * [commit 266436a7f] Four, not three: `POST /:name/toggle` joined by ruling. It is listed * HERE rather than given a parallel block of its own so it inherits every * direction the other three are held to — the 403 + `PERMISSION_DENIED` * envelope, the "the service method was never entered" spy assertion, and the @@ -202,7 +202,7 @@ const AUTHORING_WRITES = [ spy: (h: Harness) => h.unregisterFlow, }, { - // [#10243] The enablement door. `enabled: false` deliberately — the + // [commit 266436a7f] The enablement door. `enabled: false` deliberately — the // caller trying to switch a shipped flow OFF is the one the measurement // caught reaching every organization on the deployment. name: 'POST /automation/:name/toggle (toggleFlow)', @@ -391,7 +391,7 @@ describe('#10145 — /automation authoring writes require `manage_metadata`', () it('[#10243 FLIPPED] POST /:name/toggle is NO LONGER in this block — it is gated now', async () => { // ⭐ This assertion used to read `.not.toBe(403)` and // `toHaveBeenCalledWith(FLOW, false)`. It is inverted deliberately, - // by the 2026-08-23 ruling on #10243, and the inversion is kept in + // by the 2026-08-23 ruling (commit 266436a7f), and the inversion is kept in // this block — rather than only added to the refusal loop above — // so that the audit reads as a CHANGED verdict instead of a pin // that quietly vanished. The full battery for this route (envelope, diff --git a/packages/runtime/src/domains/automation.ts b/packages/runtime/src/domains/automation.ts index 2c6ec513d9c..86c5c6f0b7f 100644 --- a/packages/runtime/src/domains/automation.ts +++ b/packages/runtime/src/domains/automation.ts @@ -15,7 +15,7 @@ import { } from '@objectstack/core'; // [ADR-0126 §5] The shared activation write-authority gate — one // implementation, one refusal envelope, per-door wording. See its header for -// the posture rule and the #10243 measurement behind it. +// the posture rule and the measurement behind it (commit 02b41232d). import { refuseUngrantedActivationWrite, FLOW_ACTIVATION_SUBJECT } from './activation-gate.js'; // [#19874] What the run-lifecycle refusal names as the remedy is read off the // SAME inputs the platform-admin derivation reads — the requested posture, the @@ -364,7 +364,7 @@ const FLOW_WRITE_DENY_MESSAGE = * same `code` and the same `status` as {@link FLOW_WRITE_DENY_MESSAGE}, and a * different sentence, because a different operation was attempted. * - * ⛔ Copy, not policy. [#10243]'s ruling put `POST /:name/toggle` into the + * ⛔ Copy, not policy. The ruling commit 266436a7f landed put `POST /:name/toggle` into the * authoring write set and that classification is untouched here: the same * callers are refused, with the same `PERMISSION_DENIED` and the same 403. * What moves is only what a refused caller is TOLD. Switching a shipped flow @@ -393,7 +393,7 @@ const FLOW_ENABLEMENT_DENY_MESSAGE = * sentence the refusal carries — and this file's own rule is that a question * spelled at two call sites is two questions that happen to agree today. * - * ⛔ The truth table is [#10243]'s, moved nowhere: the exclusion of + * ⛔ The truth table is commit 266436a7f's, moved nowhere: the exclusion of * `parts[0] === 'trigger'` and the absence of any depth bound are that arm's, * for that arm's reasons, restated below where they are read. */ @@ -406,15 +406,15 @@ function isFlowEnablementWrite(parts: string[], method: string): boolean { * * One predicate, for the reason {@link isRunStateRead} is one predicate: this * domain gets one policy per data class, and a policy spelled at three call - * sites is three policies that happen to agree today. [#10243] That is why the + * sites is three policies that happen to agree today. [commit 266436a7f] That is why the * toggle ruling below was one arm here rather than a fourth copy of the policy. * * `POST /` → registerFlow (create) * `PUT /:name` → registerFlow (update) * `DELETE /:name` → unregisterFlow (deregister) - * `POST /:name/toggle` → toggleFlow (enablement — #10243, see below) + * `POST /:name/toggle` → toggleFlow (enablement — commit 266436a7f, see below) * - * ## [#10243] Why `toggle` joins them — ruled, not inferred + * ## [commit 266436a7f] Why `toggle` joins them — ruled, not inferred * * #10145 left it out and said so in the open, because whether disabling a flow * is authoring or operating is a product call rather than a code call. It was @@ -459,7 +459,7 @@ function isFlowAuthoringWrite(parts: string[], method: string): boolean { // domain root, so `POST /trigger/:name` (parts `['trigger', name]`) and // `POST /:name/trigger` cannot reach this arm. if (method === 'POST' && parts.length === 0) return true; - // [#10243] `POST /automation/:name/toggle` — the enablement door. + // [commit 266436a7f] `POST /automation/:name/toggle` — the enablement door. // // Matched exactly as the ROUTER matches it, not approximately, because a // gate narrower than its route is a bypass and a gate wider than its route @@ -581,7 +581,7 @@ function isFlowActivationWrite(parts: string[], method: string): boolean { * clause ({@link FLOW_ACTIVATION_SUBJECT}), which is the only part that ever * differed. The shared module's header carries the full rationale: why the * operator test is a POSITION, why an absent posture fails open, and what - * #10243 measured. + * commit 02b41232d measured. */ const refuseUngrantedFlowActivationWrite = ( deps: DomainHandlerDeps, @@ -629,13 +629,13 @@ const RUN_RESTORE_SEGMENT = 'restore-suspension'; * gate narrower than its route is a bypass; a gate wider than its route is an * over-block. * - * ⛔ `parts[0] === 'trigger'` is excluded, exactly as the toggle (#10243) and + * ⛔ `parts[0] === 'trigger'` is excluded, exactly as the toggle (commit 266436a7f) and * clone (#12156) arms exclude it, and the ROUTE ARMS carry the same exclusion * so the two spellings stay byte-identical. `POST /automation/trigger/:name` * is the LEGACY EXECUTION door, answered ABOVE the flow-scoped block, so for a * flow literally named `runs` the path `/automation/trigger/runs/x/cancel` * RUNS that flow. Gating it would over-block an execution door — the one thing - * the #10243 ruling did not do — and dispatching a cancel from it would be the + * the ruling commit 266436a7f landed did not do — and dispatching a cancel from it would be the * mirror bypass. * * No upper bound on depth, for the reason the toggle arm documents: the arms @@ -837,7 +837,7 @@ function refuseUngrantedRunLifecycleWrite( * [#13953] The CLOSED body envelope both lifecycle doors accept — exactly one * optional key, `reason`. * - * Shaped on the resume door's own envelope discipline (#8796 / #9416), for the + * Shaped on the resume door's own envelope discipline (commit a4331227b / #9416), for the * same reason and with the same three refusals: the body itself must be a JSON * object (a string / number / boolean / array body used to normalise to `{}` * there and reach the engine as an empty signal, answered 200), an unknown @@ -1517,7 +1517,7 @@ function flowDefinitionRefusal(err: any): unknown { * disabled-flow exit stamps `'FLOW_DISABLED'`, its start-node-less exit * stamps `'FLOW_NO_START_NODE'`, and the arms below read those. #10025 * repeated the same shape for the definition-level input-schema refusal — - * spec seat first (#11504 registered `'FLOW_INPUT_SCHEMA_INVALID'`), then the + * spec seat first (commit f90e82024 registered `'FLOW_INPUT_SCHEMA_INVALID'`), then the * engine's non-retryable short-circuit stamps it — so its 422 is read here * through the same shared table, again never minted at this call site. * @@ -1905,7 +1905,7 @@ export async function classifyResumeResult( * a run that PAUSED → 200 with `runId` / `screen`, * on whichever attempt it paused — #9510) * POST /:name/toggle → toggleFlow (unknown name → 404, #7535) - * ⚑ authoring write — `manage_metadata` (#10243): + * ⚑ authoring write — `manage_metadata` (commit 266436a7f): * enablement is environment-wide, so an * unentitled toggle reached every organization * ⚑ refused with its OWN sentence (#11666) — @@ -2024,7 +2024,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str // whether automation is mounted here. Ahead of every body check too — a // refused caller writes nothing and learns nothing about the definition // contract. Which routes: `isFlowAuthoringWrite` above, one predicate, with - // the execution surfaces deliberately outside it — [#10243] `POST + // the execution surfaces deliberately outside it — [commit 266436a7f] `POST // /:name/toggle` moved INSIDE it by ruling, and moved by editing that one // predicate rather than by adding a check here. if (isFlowAuthoringWrite(parts, m)) { @@ -2370,7 +2370,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str // name (ADR-0126 §7.1). The copy itself, the fields it mutates, the // keys it must not carry forward and the notice it returns all live in // `../flow-clone.ts` — see that module's header for the ADR and for - // #11703, the measurement that decides the copy's SHAPE. + // commit 5cb62d88b, the measurement that decides the copy's SHAPE. // // Built out of `getFlow` + `registerFlow`, not a new contract method: // `IAutomationService` lives in `packages/spec`, and this door needs @@ -2400,7 +2400,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str unknownKeys.map((k) => ({ field: k, code: 'unknown_field', message: 'not a clone field — the clone body is { name, label }' })), ); } - // The NEW MACHINE NAME IS MANDATORY (ADR-0126 §7.1, the #11513 + // The NEW MACHINE NAME IS MANDATORY (ADR-0126 §7.1, commit e170b0ae5's // shape exactly). Refused here rather than defaulted, because // every default a clone could pick is either the source's own // name — the same-name clone the ADR bans outright — or a name @@ -2488,7 +2488,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str // values, applied as bare flow variables; `output`/`branchLabel` also // forwarded for approval-style resumes. The outer envelope is a CLOSED // set — exactly the four keys below — and an unknown top-level key is - // refused (#8796); since #9416 so is an accepted key carrying a value + // refused (commit a4331227b); since #9416 so is an accepted key carrying a value // of the wrong TYPE, and a body that is not a JSON object at all. // Returns the next paused `{ screen }` (multi-screen) or the completed // result. @@ -2546,7 +2546,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str // below, because its indices read as unknown keys) — so those // reached the engine as an empty signal and answered 200 // `success:true` with the submission treated as EMPTY: the - // #8796 failure shape, reached without misspelling anything. + // failure shape commit a4331227b closed, reached without misspelling anything. // `undefined` / `null` stay the legal bodyless resume (an // empty submission is legal — a screen whose declared fields // are all optional), which is why the normalisation survives @@ -2569,7 +2569,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str ); } const b = rawBody as Record; - // [#8796] The outer envelope is a CLOSED SET (maintainer ruling + // [commit a4331227b] The outer envelope is a CLOSED SET (maintainer ruling // 2026-08-15, Option A): an unknown top-level key is refused, // located, naming the offending key(s) AND the accepted set — // the closed-parameter-set policy (Route & surface ownership @@ -2614,7 +2614,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str })), ); } - // [#9416] VALUE SHAPES — the same silent-drop family as #8796, + // [#9416] VALUE SHAPES — the same silent-drop family commit a4331227b closed, // one axis over: a key that IS accepted, carrying a value the // engine contract excludes. The assembly below used to // type-guard each key and skip what failed the guard, so @@ -2624,7 +2624,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str // submission — the caller told its screen input landed when // nothing did. Ruled Option A (maintainer, on this card): 400, // located, naming the key and the expected type, inheriting - // #8796's ruling together with its reason plus #3899's toggle + // the ruling commit a4331227b landed together with its reason plus #3899's toggle // arm (a truthy non-boolean `enabled` is refused there, never // coerced or dropped). // @@ -2644,7 +2644,7 @@ export async function handleAutomationRequest(deps: DomainHandlerDeps, path: str // // Ordering: after the unknown-key refusal, so a body that is // both misspelled and mis-shaped still reports the misspelling - // #8796 pinned; before `resume()`, so nothing reaches the + // commit a4331227b pinned; before `resume()`, so nothing reaches the // engine until the body is legal and the suspension stays // intact for a corrected retry. const valueFailures: Array<{ field: string; code: 'invalid_type'; message: string }> = []; diff --git a/packages/runtime/src/domains/domain-protocol-handle-typing.test.ts b/packages/runtime/src/domains/domain-protocol-handle-typing.test.ts index e4143c798b8..54f3ae5a227 100644 --- a/packages/runtime/src/domains/domain-protocol-handle-typing.test.ts +++ b/packages/runtime/src/domains/domain-protocol-handle-typing.test.ts @@ -11,7 +11,7 @@ * * 1. **Compile-time** (section 1). An undeclared key — or a misspelt verb — in * one of these domains' request literals must be a COMPILE ERROR. That is - * the #11006 series' end state, and it stopped three seams short here. + * the end state of commit cccbe51bf's ruled pattern, and it stopped three seams short here. * 2. **Runtime** (section 2). ⛔ A host may occupy the `protocol` slot with a * PARTIAL object. Tightening the types and then deleting a * `typeof … === 'function'` probe would trade the compile-time improvement diff --git a/packages/runtime/src/domains/mcp-merged-skill-read.test.ts b/packages/runtime/src/domains/mcp-merged-skill-read.test.ts index 0fdf1aeca49..83a52a0e8cc 100644 --- a/packages/runtime/src/domains/mcp-merged-skill-read.test.ts +++ b/packages/runtime/src/domains/mcp-merged-skill-read.test.ts @@ -5,7 +5,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { HttpDispatcher } from '../http-dispatcher.js'; /** - * [#8726 — the HTTP half of #8328] `buildMcpBridge.listSkills` must read the + * [commit e783e163d — the HTTP half of #8328] `buildMcpBridge.listSkills` must read the * protocol layer's MERGED listing, not `IMetadataService.list('skill')`. * * ── The defect ──────────────────────────────────────────────────────────── @@ -18,7 +18,7 @@ import { HttpDispatcher } from '../http-dispatcher.js'; * flip never reached MCP prompts and step 3 of #8328's reproduction answered * `{"prompts":[]}`. * - * #8328's stdio half (PR #8724, `packages/mcp`) fixed the long-lived server. + * #8328's stdio half (commit ff4ba6a06, `packages/mcp`) fixed the long-lived server. * This is the per-request HTTP surface the reproduction actually runs through. * * ── Why the fakes are shaped the way they are ───────────────────────────── diff --git a/packages/runtime/src/domains/mcp.ts b/packages/runtime/src/domains/mcp.ts index 539b71b8a8d..dae5ade89b6 100644 --- a/packages/runtime/src/domains/mcp.ts +++ b/packages/runtime/src/domains/mcp.ts @@ -318,7 +318,7 @@ function toMcpWebRequest(_deps: DomainHandlerDeps, raw: any, parsedBody: any): R } /** - * [#8726] The protocol layer's overlay-aware merged read, as this package can + * [commit e783e163d] The protocol layer's overlay-aware merged read, as this package can * name it. * * ⚠️ **Deliberately `Pick`ed from the DECLARED contract rather than restated.** @@ -344,7 +344,7 @@ function toMcpWebRequest(_deps: DomainHandlerDeps, raw: any, parsedBody: any): R export type McpMergedMetadataRead = Pick; /** - * [#8726] Read this environment's `skill` rows through the merged listing. + * [commit e783e163d] Read this environment's `skill` rows through the merged listing. * * ── The defect this closes ──────────────────────────────────────────────── * @@ -361,7 +361,7 @@ export type McpMergedMetadataRead = Pick; * * ── Absent vs. degraded vs. failed — three outcomes, deliberately ───────── * - * 1. **No merged read on this host** → the pre-#8726 registry listing, + * 1. **No merged read on this host** → the registry listing before commit e783e163d, * unchanged, including its `?? []` for a host with no metadata service at * all. Structural absence is not degradation: a host that assembles this * runtime without the metadata protocol has no merged read to offer, so @@ -412,7 +412,7 @@ async function readMergedSkillRows( } /** - * [#8726] Report #6504's completeness verdict for the skill prompt surface. + * [commit e783e163d] Report #6504's completeness verdict for the skill prompt surface. * * This read never had a diagnosed wrapper at all — unlike the stdio bridge, * where #6504 had already landed one — so a known-partial skill surface @@ -644,7 +644,7 @@ export function buildMcpBridge(deps: DomainHandlerDeps, context: HttpProtocolCon // ExecutionContext filtering, exactly like `describeObject` (the MCP // route itself is authenticated). // - // [#8726] Through the protocol layer's MERGED listing — the second half + // [commit e783e163d] Through the protocol layer's MERGED listing — the second half // of #8328, whose own reproduction runs through THIS endpoint. See // {@link readMergedSkillRows}. listSkills: async () => { diff --git a/packages/runtime/src/domains/meta-put-falsy-body.test.ts b/packages/runtime/src/domains/meta-put-falsy-body.test.ts index c80188d24cf..25b372b5a8f 100644 --- a/packages/runtime/src/domains/meta-put-falsy-body.test.ts +++ b/packages/runtime/src/domains/meta-put-falsy-body.test.ts @@ -180,7 +180,7 @@ describe('#8842 — dispatcher PUT /meta/:type/:name with a falsy body', () => { // This drove `/lead/views/all_leads` — the compound arity, which // folded the trailing segments into `views/all_leads`. That arity - // is retired (#12176 stage 3), so the same name is addressed + // is retired (stage 3, commit 7986d973f), so the same name is addressed // percent-encoded, which keeps the path at two segments and lands // on the same `saveMetaItem`. The #8842 falsy-body hole this file // exists for is a property of that handler, not of the spelling. diff --git a/packages/runtime/src/domains/meta-save-capability-gate.test.ts b/packages/runtime/src/domains/meta-save-capability-gate.test.ts index eab6e2552fd..d39e45c6cd0 100644 --- a/packages/runtime/src/domains/meta-save-capability-gate.test.ts +++ b/packages/runtime/src/domains/meta-save-capability-gate.test.ts @@ -112,7 +112,7 @@ describe('#7019 — dispatcher PUT /meta/:type/:name: the capability gate', () = it('[#12195] refuses the ENCODED spelling too — one name, one gate', async () => { // This drove `/lead/views/all_leads`, the compound arity that folded // the trailing segments into `views/all_leads`. That arity is retired - // (#12176 stage 3); the same name is addressed percent-encoded, which + // (stage 3, commit 7986d973f); the same name is addressed percent-encoded, which // keeps the path at two segments and reaches the same `saveMetaItem`. // // The point of the case is unchanged: ONE gate covers every name shape. diff --git a/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts b/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts index fcd85cdf7f9..c2e77efe5a3 100644 --- a/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts +++ b/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts @@ -16,7 +16,7 @@ * * ## Why this half was NOT repaired by threading the parameter * - * The maintainer ruled a SPLIT (2026-08-23) over the two doors #11015 left + * The maintainer ruled a SPLIT (2026-08-23) over the two doors commit 82cb6e849 left * open, and the split is the decision rather than an inconsistency to be tidied * away later: * @@ -29,7 +29,7 @@ * the transport does not have. Threading one would be a NEW public surface, * which no ruling has opened. * - * So the repair is #11015's landed mechanism, applied mechanically: a face value + * So the repair is the mechanism commit 82cb6e849 landed, applied mechanically: a face value * (`'meta-dispatch'`), stated at this call site, that renders a clause naming * what a caller can actually do HERE. * @@ -43,7 +43,7 @@ * `'meta-envelope'` in the first place. Splitting the face for the 409's sake * therefore had to leave the 422 exactly where it was, and the 422's polarity * is "declare to trim" — silence renders the FULL prose — so a face that fell - * through would re-introduce #10888's duplication on this door alone, silently, + * through would re-introduce the duplication commit d806081dd removed on this door alone, silently, * with every 409 assertion green. Section 3 is that pin. * * ## Harness @@ -268,8 +268,8 @@ describe('[#11095] dispatcher PUT /meta — the destructive refusal', () => { const res: any = await put(stack, objectBody(NAME, SHRUNK_FIELDS)); - // Only the remedy clause is face-aware. #10886's sole-carrier verdict is - // untouched by this card exactly as it was untouched by #11015. + // Only the remedy clause is face-aware. Commit 809e61221's sole-carrier verdict is + // untouched by this card exactly as it was untouched by commit 82cb6e849. expect(res.response?.body?.error?.message).toContain("Field 'b' removed"); // Row 3 of the face inventory says this door is NOT a sole carrier, and // the claim is about THIS body. diff --git a/packages/runtime/src/domains/meta-state-plural-tolerance.test.ts b/packages/runtime/src/domains/meta-state-plural-tolerance.test.ts index 16dac90f66a..6945f156d5c 100644 --- a/packages/runtime/src/domains/meta-state-plural-tolerance.test.ts +++ b/packages/runtime/src/domains/meta-state-plural-tolerance.test.ts @@ -168,7 +168,7 @@ describe('dispatcher /meta FSM state read — the deliberate plural tolerance (# 'GET', `/meta/${segment}/task/state/status`, undefined, { from: 'todo' }, CTX(), ); - // [#12195] `ROUTE_NOT_FOUND`, not `RESOURCE_NOT_FOUND`, and the + // [commit 7986d973f] `ROUTE_NOT_FOUND`, not `RESOURCE_NOT_FOUND`, and the // change is the retirement showing through. `/meta/objectss/task/ // state/status` is four segments; the FSM branch requires the two // literals, so it used to fall into the compound fold, which diff --git a/packages/runtime/src/domains/meta-verb-fallthrough.test.ts b/packages/runtime/src/domains/meta-verb-fallthrough.test.ts index 3b04d263647..228f24d3089 100644 --- a/packages/runtime/src/domains/meta-verb-fallthrough.test.ts +++ b/packages/runtime/src/domains/meta-verb-fallthrough.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#8848] `DELETE` / `PATCH` / `POST` on `/metadata/:type/:name` must be + * [commit 4fc4a3c0b] `DELETE` / `PATCH` / `POST` on `/metadata/:type/:name` must be * REFUSED with a `405` naming what is allowed — never answered as a READ. * * ## The defect this pins @@ -196,7 +196,7 @@ describe('#8848 — an unsupported verb on /metadata/:type/:name', () => { const stack = boot(); // This drove `/meta/lead/views/all_leads`, the compound arity. It - // is retired (#12176 stage 3), so the same name is addressed + // is retired (stage 3, commit 7986d973f), so the same name is addressed // percent-encoded — two segments, same verb dispatch. const res = await stack.dispatcher.dispatch( 'DELETE', '/meta/lead/views%2Fall_leads', undefined, {}, SESSION(), diff --git a/packages/runtime/src/domains/packages-list-enabled-filter.test.ts b/packages/runtime/src/domains/packages-list-enabled-filter.test.ts index c8a2a647ae5..e4de12442a0 100644 --- a/packages/runtime/src/domains/packages-list-enabled-filter.test.ts +++ b/packages/runtime/src/domains/packages-list-enabled-filter.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#19394] `GET /api/v1/packages` honours the declared `enabled` filter — + * [commit 0862063ba] `GET /api/v1/packages` honours the declared `enabled` filter — * ruling item 2 of #17667. * * ## The defect this file pins shut @@ -39,7 +39,7 @@ * anything about them in either direction: pinning them as `201` would freeze * known residuals as intended behaviour, and pinning them as refused would be * this file quietly widening a graded scope. - * - **`hasMore` / `nextCursor`.** #19364 retired the request half + * - **`hasMore` / `nextCursor`.** Commit ada701220 retired the request half * (`limit` / `cursor`) and left `hasMore` a constant `false` that is now true * by construction. §5 asserts it is UNMOVED by this card — that is a * preservation pin, not a re-adjudication. diff --git a/packages/runtime/src/domains/packages-protocol-handle-typing.test.ts b/packages/runtime/src/domains/packages-protocol-handle-typing.test.ts index 0cf071966af..e9896d22360 100644 --- a/packages/runtime/src/domains/packages-protocol-handle-typing.test.ts +++ b/packages/runtime/src/domains/packages-protocol-handle-typing.test.ts @@ -8,7 +8,7 @@ * and either one alone is a regression: * * 1. **Compile-time** (section 1). An undeclared key in one of this domain's - * request literals must be a COMPILE ERROR. That is the #11006 series' end + * request literals must be a COMPILE ERROR. That is commit cccbe51bf's ruled end * state, and it stopped one seam short here. * 2. **Runtime** (section 2). ⛔ A host may occupy the `protocol` slot with a * PARTIAL object. Tightening the type and then deleting a diff --git a/packages/runtime/src/domains/packages-seed-apply-org-scope.test.ts b/packages/runtime/src/domains/packages-seed-apply-org-scope.test.ts index f2cbf9404d4..eff1411a6ae 100644 --- a/packages/runtime/src/domains/packages-seed-apply-org-scope.test.ts +++ b/packages/runtime/src/domains/packages-seed-apply-org-scope.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #15068 — the publish-then-read path under `applyPublishedSeeds`, and the + * Commit 8744de9e9 — the publish-then-read path under `applyPublishedSeeds`, and the * proof that its org-then-env ladder cannot choose between its two rungs. * * ## What the ladder was, and why deleting it needed a measurement @@ -24,7 +24,7 @@ * ## The mechanism, in one line * * `getMetaItem` opens with `organizationIdForMetaRead(request.type, - * request.organizationId)` (#14908, the singular twin of #14683's plural + * request.organizationId)` (commit d5cbb44f3, the singular twin of commit 96326040f's plural * gate) and spends that binding — never `request.organizationId` — on every * read below it. `seed` declares `allowOrgOverride: false` * (`metadata-plugin.zod.ts`), so the predicate answers `undefined` whatever @@ -34,7 +34,7 @@ * ⛔ The repair is NOT to restore org-awareness to this read. An org-scoped * `seed` row is the unhydratable phantom `reportUnhydratableOrgScopedRows` * exists to warn about — the same argument the `app` flip one function up - * carries since #15063. + * carries since commit ad35745e8. * * ## How this file is composed, and which half is doubled * @@ -487,7 +487,7 @@ describe('#15068 · 2 · the publish path stops spending an organization the gat const { readBackArgs } = await publishThenRead({ activeOrganizationId: ORG }); // Not cosmetic: an `organizationId` on a non-overridable read is the - // shape #14908 and #15063 exist to stop anyone reading as meaningful. + // shape commits d5cbb44f3 and ad35745e8 exist to stop anyone reading as meaningful. expect(readBackArgs).toEqual([{ type: 'seed', name: SEED }]); }); diff --git a/packages/runtime/src/domains/packages.ts b/packages/runtime/src/domains/packages.ts index 86b509c9da2..6884f2c35da 100644 --- a/packages/runtime/src/domains/packages.ts +++ b/packages/runtime/src/domains/packages.ts @@ -101,7 +101,7 @@ import { ManifestSchema, SEMVER_2_0_0_VERSION_PATTERN, manifestIdRefusal } from // `res`, and every error body on this surface is `deps.error`'s. See the // `@objectstack/rest` barrel entry that publishes the pair. import { repeatedQueryParamMessage } from '@objectstack/rest'; -// [#19394] The repo's ONE coercion for a query parameter its schema declares +// [commit 0862063ba] The repo's ONE coercion for a query parameter its schema declares // `z.boolean()`, from the module whose header is the authority on the rule // (`packages/runtime/src/query-param.ts`). Imported, never restated: the list // door's `enabled` is declared `z.boolean().optional()` — character for @@ -135,7 +135,7 @@ import { PackageInstallBodySchema, PackageInstallRequestSchema } from '@objectst * ("real services with no written contract, so they keep today's `any` rather * than being given a shape here that nothing verifies"). The `any` is honest * about the SLOT. What it also did, silently, was hand every request literal - * downstream of it an unchecked call target: the #11006 series' end state — + * downstream of it an unchecked call target: the end state of commit cccbe51bf's ruled pattern — * "an undeclared key in a request literal is a compile error" — stopped one * seam short here, so a misspelt or undeclared key in these literals compiled. * @@ -678,7 +678,7 @@ function withWritableVerdict ({ const flip = (d: HttpDispatcher, ctx: HttpProtocolContext) => d.handleActions(`/_activation/${OBJECT}/${ACTION}`, 'POST', { enabled: false }, ctx); -/** Door 3 — `POST /automation/:name/toggle` (`./automation.ts`, read-only here: PR #16755 holds that file). */ +/** Door 3 — `POST /automation/:name/toggle` (`./automation.ts`, read-only here: the change that landed as commit 44c849c7d held that file). */ const FLOW = 'vendor_lead_router'; const FLOW_DEFINITION = { name: FLOW, label: 'Vendor Lead Router', type: 'autolaunched', nodes: [], edges: [] }; diff --git a/packages/runtime/src/domains/share-links-enforcement-context.test.ts b/packages/runtime/src/domains/share-links-enforcement-context.test.ts index cf0e37e4b16..fbbad1ff01e 100644 --- a/packages/runtime/src/domains/share-links-enforcement-context.test.ts +++ b/packages/runtime/src/domains/share-links-enforcement-context.test.ts @@ -1,12 +1,12 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#6551 / #6206 / #6430] Dispatcher-face `/share-links` enforcement context. + * [#6551 / commit 8e13ca876 / #6430] Dispatcher-face `/share-links` enforcement context. * * The dispatcher domain used to rebuild a two-field `{ userId, tenantId }` * out of the request's ALREADY-COMPLETE resolved `ExecutionContext` and hand * that to `svc.createLink` / `svc.listLinks` / `svc.revokeLink` — the same - * consumption-site truncation #6206 fixed on the plugin-sharing face (PR + * consumption-site truncation commit 8e13ca876 fixed on the plugin-sharing face (PR * #6552), one entry point over. Structural subtyping keeps the trimmed object * compiling against the contract's `ExecutionContext` parameter, so only a * behavioural repro + a seam-parity pin can hold this boundary. @@ -498,7 +498,7 @@ describe('[#6551] the dispatcher seam itself', () => { for (const verb of ['createLink', 'listLinks', 'revokeLink'] as const) { expect(svc[verb]).toHaveBeenCalledTimes(1); const got = seen[verb]; - // The #6206 contract: the WHOLE `resolveExecutionContext` envelope, + // The contract commit 8e13ca876 set: the WHOLE `resolveExecutionContext` envelope, // unchanged — a re-trim shows up here as the exact keys it dropped. const dropped = Object.keys(envelope as any).filter( (k) => !(k in got) || got[k] !== (envelope as any)[k], diff --git a/packages/runtime/src/domains/share-links.ts b/packages/runtime/src/domains/share-links.ts index b94e7a28d3a..0a6021c73d3 100644 --- a/packages/runtime/src/domains/share-links.ts +++ b/packages/runtime/src/domains/share-links.ts @@ -90,7 +90,7 @@ export async function handleShareLinksRequest( const SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] } as const; const m = method.toUpperCase(); const parts = subPath.replace(/^\/+/, '').split('/').filter(Boolean); - // [#6551 / #6206 / #6430] The dispatcher's ALREADY-COMPLETE envelope, + // [#6551 / commit 8e13ca876 / #6430] The dispatcher's ALREADY-COMPLETE envelope, // passed through WHOLE to every adjudicating service call below. // // `createLink` / `listLinks` / `revokeLink` are ENFORCEMENT paths — the @@ -105,7 +105,7 @@ export async function handleShareLinksRequest( // two-field `{ userId, tenantId }` — structural subtyping keeps that // compiling, so the narrowing was invisible to tsc and every // `group`-posture caller was refused links on records they read fine - // elsewhere (the #6206 defect, on the dispatcher face). The routes' own + // elsewhere (the defect commit 8e13ca876 fixed, on the dispatcher face). The routes' own // 401 gate below reads only `ec?.userId` — an authentication decision // needs no authorization envelope. const ec = context.executionContext; diff --git a/packages/runtime/src/domains/tenancy-posture-outage-gates.test.ts b/packages/runtime/src/domains/tenancy-posture-outage-gates.test.ts index 3552eade5d7..0a1c2e3b847 100644 --- a/packages/runtime/src/domains/tenancy-posture-outage-gates.test.ts +++ b/packages/runtime/src/domains/tenancy-posture-outage-gates.test.ts @@ -419,7 +419,7 @@ describe('[#15900] the install-wide activation write — a tenancy service that expect(isAuthzStoreUnavailableError(err)).toBe(true); expect((err as { status?: unknown }).status).toBe(OUTAGE_STATUS); expect((err as { code?: unknown }).code).toBe(OUTAGE_CODE); - // Refused BEFORE the write — a gate that refuses afterwards is #10243 + // Refused BEFORE the write — a gate that refuses afterwards is the leak commit 02b41232d measured, // with an audit trail. expect(setActionActive).not.toHaveBeenCalled(); }); @@ -530,7 +530,7 @@ describe('[#15900] the automation toggle — the same install-wide gate, reached expect((err as { status?: unknown }).status).toBe(OUTAGE_STATUS); expect((err as { code?: unknown }).code).toBe(OUTAGE_CODE); // Refused BEFORE the durable row — ADR-0126 made this switch survive a - // cold boot, so a refusal after the write is the #10243 leak with an + // cold boot, so a refusal after the write is the leak commit 02b41232d measured, with an // audit trail. expect(toggleFlow).not.toHaveBeenCalled(); }); diff --git a/packages/runtime/src/domains/ui.ts b/packages/runtime/src/domains/ui.ts index c5baca7c22a..7ae39da7eea 100644 --- a/packages/runtime/src/domains/ui.ts +++ b/packages/runtime/src/domains/ui.ts @@ -13,7 +13,7 @@ // signature here would silently drift from the one the spec declares and // `ObjectStackProtocolImplementation` states it `implements` — which is the // whole reason `UiDomainProtocol` below is `Pick`ed rather than written out. -// Same move `domains/packages.ts` (#13598) and `domains/mcp.ts` (#8726) make. +// Same move `domains/packages.ts` (#13598) and `domains/mcp.ts` (commit e783e163d) make. import type { MetadataProtocol } from '@objectstack/spec/api'; import type { HttpProtocolContext, HttpDispatcherResult } from '../http-dispatcher.js'; import type { DomainHandlerDeps, DomainRoute } from '../domain-handler-registry.js'; diff --git a/packages/runtime/src/endpoint-executor.test.ts b/packages/runtime/src/endpoint-executor.test.ts index 3c8cff308d7..349ddb39f2c 100644 --- a/packages/runtime/src/endpoint-executor.test.ts +++ b/packages/runtime/src/endpoint-executor.test.ts @@ -533,7 +533,7 @@ describe('an unsupported declaration gets a structured 501, never invented seman expect(execute).not.toHaveBeenCalled(); }); - // [#10338] `target` is OPTIONAL in the vocabulary now, so a flow endpoint + // [commit d2619fd0c] `target` is OPTIONAL in the vocabulary now, so a flow endpoint // with the key OMITTED is a parseable declaration — the publish gate // refuses it (`apis-publish-gates.test.ts`), and this is the runtime // counterpart that gate mirrors (`planEndpointTarget`), for a declaration diff --git a/packages/runtime/src/expand-nested-fields-join-key.integration.test.ts b/packages/runtime/src/expand-nested-fields-join-key.integration.test.ts index a3f430e015a..2c8e8b81b3d 100644 --- a/packages/runtime/src/expand-nested-fields-join-key.integration.test.ts +++ b/packages/runtime/src/expand-nested-fields-join-key.integration.test.ts @@ -78,7 +78,7 @@ const TASK = { }; /** - * [#10629] This fixture provisions the four business objects it queries and nothing else, so the engine's + * [commit 13a6cb4ad] This fixture provisions the four business objects it queries and nothing else, so the engine's * own single-tenant probe (`ObjectQL.probeInstallOrganizations`, memoised once * per engine) reads a `sys_organization` that was never created. The probe is * fail-soft by construction — it catches `isMissingTableError` and only that — @@ -90,14 +90,14 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; describe('#7537 expand with a nested `fields` that omits the join key (REAL SqlDriver)', () => { let engine: ObjectQL | null = null; let dir: string | null = null; - /** [#10629] The expected-noise capture belonging to the latest boot. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest boot. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave the engine running. Every test in this file // boots and writes, so the probe fires for each of them: this holds for a // single `-t` run as well as for the whole file. @@ -112,7 +112,7 @@ describe('#7537 expand with a nested `fields` that omits the join key (REAL SqlD connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true, }); - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); noise.captureDriver(driver); diff --git a/packages/runtime/src/expected-read-refusal-noise.channel-asymmetry.test.ts b/packages/runtime/src/expected-read-refusal-noise.channel-asymmetry.test.ts index bb076f80937..bb2743f53e2 100644 --- a/packages/runtime/src/expected-read-refusal-noise.channel-asymmetry.test.ts +++ b/packages/runtime/src/expected-read-refusal-noise.channel-asymmetry.test.ts @@ -19,7 +19,7 @@ // `ObjectLogger.write` returns early unless // `LEVEL_ORDER[frame] >= LEVEL_ORDER[config.level]`. // -// ⚠️ [#13273] The frame this probe provokes is a MISSING TABLE, and `engine.ts` +// ⚠️ [commit 3a86a65e7] The frame this probe provokes is a MISSING TABLE, and `engine.ts` // now classifies that class onto `debug` rather than `error` (its own // `reportFindFailure`). Two mechanical consequences for this instrument, both // measured rather than reasoned: @@ -96,7 +96,7 @@ interface Readout { readonly driverPassThrough: number; /** * Process-stream lines carrying the engine's `Find operation failed`, from - * `stderr` and `stdout` together — [#13273] the frame's level decides which + * `stderr` and `stdout` together — [commit 3a86a65e7] the frame's level decides which * of the two it lands on, and this file measures whether a reader saw it at * all, not which pipe carried it. */ @@ -211,9 +211,9 @@ describe('#11569 expected-read-refusal-noise: the two channels are not equally l it( 'engine pass-through: the SAME unrecognised read is loud at `debug` — the instrument produces a positive', async () => { - // [#13273] `debug` is the level that admits THIS frame: the probe reads a + // [commit 3a86a65e7] `debug` is the level that admits THIS frame: the probe reads a // table that does not exist, and `engine.ts` classifies that class onto - // `debug`. Before #13273 the same control was run at `error`. The claim + // `debug`. Before commit 3a86a65e7 the same control was run at `error`. The claim // under test is unchanged — "the engine channel is only as loud as the // kernel's own level" — only the rank it is compared against moved. const seen = await probeRead('debug', UNDECLARED_TABLE, [DECLARED_TABLE]); @@ -232,7 +232,7 @@ describe('#11569 expected-read-refusal-noise: the two channels are not equally l it( 'engine pass-through: the condition is the LEVEL THRESHOLD, not the word `silent` — `fatal` drops it too', async () => { - // `ObjectLogger.isEnabled` compares rank: this frame ([#13273] `debug`, + // `ObjectLogger.isEnabled` compares rank: this frame ([commit 3a86a65e7] `debug`, // rank 0) is admitted only while the configured level is `debug`. // `fatal` (4) and `silent` (5) both refuse it — as do `info` and `warn` // — so a fixture that floats its kernel to `fatal` is just as blind as diff --git a/packages/runtime/src/expected-read-refusal-noise.ts b/packages/runtime/src/expected-read-refusal-noise.ts index 406007af3a3..51c4014d122 100644 --- a/packages/runtime/src/expected-read-refusal-noise.ts +++ b/packages/runtime/src/expected-read-refusal-noise.ts @@ -2,8 +2,8 @@ /** * ═══════════════════════════════════════════════════════════════════════════ - * [#10629] Expected `refused a read on` noise: WITHHELD from the shared log, - * and ASSERTED instead — the shape PR #10630 landed, factored out + * [commit 13a6cb4ad] Expected `refused a read on` noise: WITHHELD from the shared log, + * and ASSERTED instead — the shape commit dd8172ee2 landed, factored out * ═══════════════════════════════════════════════════════════════════════════ * * ## The defect this closes @@ -34,8 +34,8 @@ * … no such table: `, from `SqlDriver.backendStatementFault` * through the driver's own `logger.warn`; * 2. `Find operation failed {"object":"
",…}` one frame up - * (`objectql/src/engine.ts`), carrying the same fault. ⚠️ [#13273] It used - * to be `ERROR`, with a stack, for EVERY cause; since #13273 the engine + * (`objectql/src/engine.ts`), carrying the same fault. ⚠️ [commit 3a86a65e7] It used + * to be `ERROR`, with a stack, for EVERY cause; since commit 3a86a65e7 the engine * asks `isMissingTableError` and puts the "table not provisioned" class * — i.e. exactly the class this module is declared over — on `debug` * instead, with no stack and a `reason: 'table-not-provisioned'` meta. @@ -49,7 +49,7 @@ * Turbo interleaves package logs without attribution, so in the shared shard * log those are indistinguishable from a real failure. Not a hypothetical: * lines of exactly this shape were lifted VERBATIM into a p1 flake signature - * (#10293) and sent a whole dispatch cycle at the wrong mechanism. + * (a vitest teardown race, fixed by commit 92a69d813) and sent a whole dispatch cycle at the wrong mechanism. * Expected-failure noise from a green test is a diagnosis tax on every future * red shard. * @@ -91,7 +91,7 @@ * rule for all of them, and do not read a quiet engine channel in one fixture * as evidence about another. * - * ⚠️ [#13273] The threshold moved for the "table not provisioned" class, and + * ⚠️ [commit 3a86a65e7] The threshold moved for the "table not provisioned" class, and * moved DOWN: that frame is now `debug` (rank 0), so a fixture has to be at * `debug` to see an unrecognised one, where `info` used to be enough. The * asymmetry above is unchanged in shape — the engine channel is still only as @@ -124,11 +124,11 @@ * * ## Why a shared module rather than a copy per fixture * - * PR #10630 established this shape on two files and wrote it inline in each. + * Commit dd8172ee2 established this shape on two files and wrote it inline in each. * The enumerated remainder is sixteen more, across four distinct probe sites, * and sixteen copies of one predicate is sixteen places for it to drift — * including drifting *looser*, which is the direction that turns a pin back - * into a mute without anything going red. The mechanism below is #10630's + * into a mute without anything going red. The mechanism below is commit dd8172ee2's * verbatim: the same two sinks, the same "named table AND named reason" * predicate, the same pending-refusal gate on the engine frame, the same * count-and-assert discipline. Only the duplication is gone. @@ -167,7 +167,7 @@ export interface ExpectedReadRefusalCapture { * The expected channels that never fired, one sentence each — the assertion * surface. `expect(capture.silentChannels()).toEqual([])` is one call that * still makes a silent channel NAME ITSELF in the diff, which is what - * #10630's "one assertion per channel" bought at sixteen times the bulk. + * commit dd8172ee2's "one assertion per channel" bought at sixteen times the bulk. * * ⛔ Repairing a failure here means re-deriving the declared table list or * finding out why the probe stopped — NEVER relaxing this: a runtime read @@ -194,7 +194,7 @@ export interface ExpectedReadRefusalCapture { * setter, which is the same access `engine-readonly-when-parent.test.ts` * established. * - * ⚠️ [#13273] Both channels, because the engine now picks between them by + * ⚠️ [commit 3a86a65e7] Both channels, because the engine now picks between them by * cause: a read whose table was never provisioned goes to `debug`, every * other read failure to `warn` ([#17212]; it was `error`). Wrapping only one * would leave this capture blind on whichever half the engine chose. @@ -409,7 +409,7 @@ export function captureExpectedReadRefusals( target.warn(msg, meta, ...rest); }; } - // [#13273] The SAME frame, on the channel the engine now chooses for + // [commit 3a86a65e7] The SAME frame, on the channel the engine now chooses for // a read whose table was never provisioned — which is every read this // capture is declared over. `debug(msg, meta)` has no `error` // argument, so the driver's envelope arrives as `meta.error` instead; @@ -434,7 +434,7 @@ export function captureExpectedReadRefusals( /** * ═══════════════════════════════════════════════════════════════════════════ - * [#10983] A SECOND, independent predicate: cross-field `{ $field }` refusal + * [commit 6a4e929f5] A SECOND, independent predicate: cross-field `{ $field }` refusal * engine noise (#7929) — the sibling {@link captureExpectedReadRefusals} * cannot recognise, because it has no table to key on * ═══════════════════════════════════════════════════════════════════════════ diff --git a/packages/runtime/src/external-validation-checkonboot.test.ts b/packages/runtime/src/external-validation-checkonboot.test.ts index e8e2b3939cc..0bdcec5c4d5 100644 --- a/packages/runtime/src/external-validation-checkonboot.test.ts +++ b/packages/runtime/src/external-validation-checkonboot.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#13037] `datasource.external.validation.checkOnBoot` — declared with + * [commit e7dfb1d69] `datasource.external.validation.checkOnBoot` — declared with * `.default(true)` since the block was written, and read by NOTHING until this * card. An author who wrote `checkOnBoot: false` and left `onMismatch` at its * default still got the boot sweep, and a measured mismatch still threw @@ -54,7 +54,7 @@ const mismatch: SchemaDiffEntry[] = [ { kind: 'type_mismatch', remoteName: 'fact_orders', column: 'amount', expected: 'number', actual: 'text', severity: 'error' }, ]; -/** [#11166] The indeterminate row: the remote could not be read at all. */ +/** [commit 735f5c709] The indeterminate row: the remote could not be read at all. */ const unreachable: SchemaDiffEntry[] = [ { kind: 'unreachable', remoteName: 'fact_orders', actual: 'connect ECONNREFUSED 10.0.0.5:5432', severity: 'error' }, ]; @@ -136,7 +136,7 @@ describe('checkOnBoot: false — the datasource is skipped by the kernel:ready s }); /** - * [#11166]'s loud unreachable warning is part of the boot gate, so it is part + * Commit 735f5c709's loud unreachable warning is part of the boot gate, so it is part * of what `checkOnBoot: false` opts out of. Skipped means skipped — an author * who took the boot check off their datasource should not be told at every * startup that the boot check could not read it. diff --git a/packages/runtime/src/external-validation-drift-scope.test.ts b/packages/runtime/src/external-validation-drift-scope.test.ts index 49c1e87ea2e..f280538c942 100644 --- a/packages/runtime/src/external-validation-drift-scope.test.ts +++ b/packages/runtime/src/external-validation-drift-scope.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#10961] The BACKGROUND drift check does the work it was ARMED for. + * [commit 222d06fc1] The BACKGROUND drift check does the work it was ARMED for. * * ## The defect this file measures * diff --git a/packages/runtime/src/external-validation-plugin.test.ts b/packages/runtime/src/external-validation-plugin.test.ts index 9305c697cb1..fb33531858d 100644 --- a/packages/runtime/src/external-validation-plugin.test.ts +++ b/packages/runtime/src/external-validation-plugin.test.ts @@ -28,7 +28,7 @@ const sampleDiffs: SchemaDiffEntry[] = [ { kind: 'type_mismatch', remoteName: 'fact_orders', column: 'amount', expected: 'number', actual: 'text', severity: 'error' }, ]; -/** [#11166] The row `validateEach` produces when the remote could not be read. */ +/** [commit 735f5c709] The row `validateEach` produces when the remote could not be read. */ const unreachableDiffs: SchemaDiffEntry[] = [ { kind: 'unreachable', remoteName: 'fact_orders', actual: 'connect ECONNREFUSED 10.0.0.5:5432', severity: 'error' }, ]; @@ -87,7 +87,7 @@ describe('ExternalValidationPlugin (ADR-0015 Gate 2)', () => { }); /** - * [#11166] An `unreachable` row is not a schema mismatch: validation was + * [commit 735f5c709] An `unreachable` row is not a schema mismatch: validation was * indeterminate (the remote could not be read), so the default * `onMismatch: 'fail'` must NOT abort boot for it — a transient outage * during startup used to be a refusal to start. Loud logging instead, @@ -151,7 +151,7 @@ describe('ExternalValidationPlugin — background drift detection (ADR-0015 §5. afterEach(() => vi.useRealTimers()); /** - * [#10961] The fake answers the SCOPED spelling, because that is what the + * [commit 222d06fc1] The fake answers the SCOPED spelling, because that is what the * checker now calls: a timer armed for one datasource asks the service about * that datasource, instead of sweeping the farm and filtering the report. * The rows below live behind that scoping so the fixture cannot hand back a @@ -188,7 +188,7 @@ describe('ExternalValidationPlugin — background drift detection (ADR-0015 §5. }); /** - * [#11166] A briefly-unreachable remote used to raise `external.schema.drift` + * [commit 735f5c709] A briefly-unreachable remote used to raise `external.schema.drift` * events whose diffs claimed `missing_table` on every tick it stayed down. * The event is still emitted (audit/notification consumers see the outage) * but under the distinct `unreachable` kind — and the operator-facing diff --git a/packages/runtime/src/external-validation-plugin.ts b/packages/runtime/src/external-validation-plugin.ts index eb3200efad1..e7d834f77bd 100644 --- a/packages/runtime/src/external-validation-plugin.ts +++ b/packages/runtime/src/external-validation-plugin.ts @@ -28,12 +28,12 @@ interface ExternalDatasourceServiceLike { */ validateAll(): Promise; /** - * [#10961] The scoped twin: validate the federated objects bound to ONE + * [commit 222d06fc1] The scoped twin: validate the federated objects bound to ONE * datasource, driving live introspection against THAT datasource only. * * OPTIONAL, and probed rather than assumed, because it is deliberately not on - * `IExternalDatasourceService` — #10537's triage authorized the service-side - * composition, not a contract-surface expansion, and #10961's triage carried + * `IExternalDatasourceService` — commit e634ecf6a, as triaged, took the service-side + * composition, not a contract-surface expansion, and commit 222d06fc1 carried * that ruling forward unchanged. What is asserted here rather than * contract-checked is the method's NAME; nothing about the shape it returns, * which is the report type both spellings already share. @@ -155,7 +155,7 @@ interface DatasourceDef { validation?: { onMismatch?: 'fail' | 'warn' | 'ignore'; /** - * [#13037] The BOOT gate's per-datasource opt-out — read by + * [commit e7dfb1d69] The BOOT gate's per-datasource opt-out — read by * {@link bootCheckEnabled}, and by nothing else on purpose. The scope * boundary the maintainer pinned when ruling this key ENFORCED (rather * than retired) is stated at that function. @@ -187,7 +187,7 @@ export interface ExternalSchemaDriftEvent { * - `warn` → logs the diff and continues, * - `ignore` → does nothing. * - * [#13037] A datasource that sets `external.validation.checkOnBoot: false` is + * [commit e7dfb1d69] A datasource that sets `external.validation.checkOnBoot: false` is * skipped by this sweep entirely — no policy is applied to its rows, so no * mismatch on it can abort boot. Its BACKGROUND drift checking is a separate * policy and is unaffected; see {@link bootCheckEnabled} for the scope the @@ -197,7 +197,7 @@ export interface ExternalSchemaDriftEvent { * `kind: 'unreachable'` (the remote could not be read, so validation was * indeterminate — see the kind's docblock in `@objectstack/spec/shared`) never * feeds that policy: it is logged loudly and boot continues, under every - * `onMismatch` value (maintainer ruling 2026-08-23, #11166). + * `onMismatch` value (maintainer ruling 2026-08-23, landed in commit 735f5c709). * * No-op when the `external-datasource` service is not registered (federation * unused). @@ -276,7 +276,7 @@ export class ExternalValidationPlugin implements Plugin { } const metadata = safeGet(ctx, 'metadata'); - // [#13037] One definition read per datasource per sweep, shared by the + // [commit e7dfb1d69] One definition read per datasource per sweep, shared by the // `checkOnBoot` gate below and the `onMismatch` resolution after it. const loadDef = createDatasourceDefLoader(metadata); let report: Awaited>; @@ -287,7 +287,7 @@ export class ExternalValidationPlugin implements Plugin { return; } - // [#13037] Honour each datasource's `external.validation.checkOnBoot` + // [commit e7dfb1d69] Honour each datasource's `external.validation.checkOnBoot` // BEFORE any verdict is drawn from its rows. The sweep is whole-farm and // the key is per-datasource, so the opt-out can only be applied here, row // by row — a datasource that set `false` is dropped, and every other @@ -323,7 +323,7 @@ export class ExternalValidationPlugin implements Plugin { } for (const r of failures) { - // [#11166] An `unreachable` row is NOT a schema mismatch — the remote + // [commit 735f5c709] An `unreachable` row is NOT a schema mismatch — the remote // (or the object's own definition) could not be read, so validation was // indeterminate and there is no measured fact to gate on. Maintainer // ruling 2026-08-23: no `onMismatch: 'fail'` abort for unreachable — @@ -379,7 +379,7 @@ export class ExternalValidationPlugin implements Plugin { * (e.g. a second `kernel:ready`) first clears existing timers so intervals * don't accumulate. * - * ⭐ [#13037] **`external.validation.checkOnBoot` does not reach here, by + * ⭐ [commit e7dfb1d69] **`external.validation.checkOnBoot` does not reach here, by * ruling.** The maintainer pinned that gate's scope to the BOOT STEP ONLY * (2026-08-29): a datasource that set `checkOnBoot: false` still gets the * background drift checker it asked for via `checkIntervalMs`, because the @@ -426,7 +426,7 @@ export class ExternalValidationPlugin implements Plugin { * `external.schema.drift` event per mismatch. Exposed for testing; invoked * from the interval armed by {@link scheduleDriftChecks}. Never throws. * - * ## [#10961] The work is scoped by the CALL, not by a filter over a sweep + * ## [commit 222d06fc1] The work is scoped by the CALL, not by a filter over a sweep * * This body used to ask for `validateAll()` — every federated object on every * federated datasource, each validation driving a live remote-schema @@ -438,7 +438,7 @@ export class ExternalValidationPlugin implements Plugin { * two armed timers introspected six remotes per cycle where two were asked * for, and each additional tick repeated it. * - * That makes this the periodic twin of the request-gate defect #10537 named, + * That makes this the periodic twin of the request-gate defect commit e634ecf6a fixed, * and worse in the one way that matters: a request gate has a caller waiting * on the answer and paying attention to the latency, while this is * **unattended** — the fan-out repeats on every interval, forever, with @@ -536,7 +536,7 @@ export class ExternalValidationPlugin implements Plugin { } } if (drifted.length > 0) { - // [#11166] Same distinction as the boot gate, one layer down: an + // [commit 735f5c709] Same distinction as the boot gate, one layer down: an // `unreachable` row is "could not watch", not "schema changed". The // event above is still emitted for it — audit/notification consumers // discriminate on the entry's `kind` — but the operator-facing summary @@ -571,7 +571,7 @@ export function createExternalValidationPlugin(): ExternalValidationPlugin { * Reads one datasource definition per NAME per sweep, answering `undefined` for * anything it could not read. * - * [#13037] Introduced because the boot gate now asks the definition two + * [commit e7dfb1d69] Introduced because the boot gate now asks the definition two * questions — "does this datasource opt out of the boot check?" and, only for * the rows that stayed, "what is its `onMismatch` policy?" — and asking twice * would double the metadata reads for every mismatching row. Memoized per @@ -604,7 +604,7 @@ function createDatasourceDefLoader( } /** - * [#13037] Does the BOOT sweep apply to this datasource? + * [commit e7dfb1d69] Does the BOOT sweep apply to this datasource? * * ## ⭐ Scope, pinned by the maintainer at the ruling (2026-08-29) * diff --git a/packages/runtime/src/federated-boot-binding.test.ts b/packages/runtime/src/federated-boot-binding.test.ts index c3afb037d75..41301e844dc 100644 --- a/packages/runtime/src/federated-boot-binding.test.ts +++ b/packages/runtime/src/federated-boot-binding.test.ts @@ -126,7 +126,7 @@ function orphanArtifact() { } /** - * [#10629] The `OS_SKIP_SCHEMA_SYNC` case's expected read failures: WITHHELD, + * [commit 13a6cb4ad] The `OS_SKIP_SCHEMA_SYNC` case's expected read failures: WITHHELD, * and ASSERTED. * * With boot schema sync skipped, nothing creates `sys_metadata` — that IS what @@ -170,7 +170,7 @@ async function boot(bundle: Record, capture?: ExpectedReadRefus const runtime = new Runtime({ cluster: false }); const kernel = runtime.getKernel(); - // [#10629] Scoped before the driver runs a statement when the caller asked + // [commit 13a6cb4ad] Scoped before the driver runs a statement when the caller asked // for a capture; the default boot passes none and stays fully loud. const driver = await makeDefaultDriver(); capture?.captureDriver(driver); @@ -243,7 +243,7 @@ describe('#7737 federated boot binding — declared external objects are bound w await driver.execute("INSERT INTO remote_invoices (id, amount) VALUES ('i1', 100)"); expect((await engine.find('fed_customer')).map((r) => r.name)).toEqual(['Ada']); expect((await engine.find('fed_invoice')).map((r) => r.id)).toEqual(['i1']); - // [#10629] The capture is a PIN, not a mute: if boot stops reading + // [commit 13a6cb4ad] The capture is a PIN, not a mute: if boot stops reading // `sys_metadata`, or the table starts existing under this flag, the log // goes quiet AND this goes red. expect(noise.silentChannels()).toEqual([]); diff --git a/packages/runtime/src/flow-clone.ts b/packages/runtime/src/flow-clone.ts index 913d62c7494..5008277ee69 100644 --- a/packages/runtime/src/flow-clone.ts +++ b/packages/runtime/src/flow-clone.ts @@ -4,7 +4,7 @@ * # Flow clone — whole-definition copy under a new machine name (ADR-0126 §7.1) * * The copy half of ADR-0126's packaged-metadata customization model, shaped on - * the landed permission-set clone (`sys-permission-set.object.ts`, #11513): an + * the landed permission-set clone (`sys-permission-set.object.ts`, commit e170b0ae5): an * admin who cannot edit a packaged flow in place gets an ordinary, * org-authored sibling to edit instead. * @@ -18,7 +18,7 @@ * to `FlowSchema` must never require an edit here. * * That is not stylistic. The permission-set clone this is shaped on assembles - * its payload from an enumerated param list, and #11703 measured what an + * its payload from an enumerated param list, and commit 5cb62d88b records what an * enumerated list costs: three of the six facets (`system_permissions`, * `row_level_security`, `tab_permissions`) were simply not listed, so cloning a * set carrying system permissions or RLS produced a clone with NONE of them — @@ -31,7 +31,7 @@ * grows next — so the enumerated shape is not merely riskier here, it is * unmaintainable. ADR-0126 §7.1 rules it out by name. * - * `flow-clone.test.ts` asserts this as the #11703 counter-example: deep + * `flow-clone.test.ts` asserts this as the counter-example of commit 5cb62d88b: deep * equality of the cloned definition against the source, minus the three * mutated fields. A dropped facet fails that test rather than shipping. * @@ -110,7 +110,7 @@ export const FLOW_CLONE_STATUS = 'draft' as const; * * Exported so the test asserts the mutation set from the same constant the * implementation applies, rather than restating it (a second list here is the - * #11703 mechanism in miniature). + * facet-drop mechanism of commit 5cb62d88b in miniature). */ export const FLOW_CLONE_MUTATED_FIELDS = ['name', 'label', 'status'] as const; diff --git a/packages/runtime/src/flow-dispatch-status.ts b/packages/runtime/src/flow-dispatch-status.ts index 2c9eab2fdef..dd53f01f37b 100644 --- a/packages/runtime/src/flow-dispatch-status.ts +++ b/packages/runtime/src/flow-dispatch-status.ts @@ -15,7 +15,7 @@ * | ran and PAUSED | ran, suspended | not a refusal — see below | * * The `FLOW_INPUT_SCHEMA_INVALID` row TRANSCRIBES the #10025 ruling's - * spec-recorded contract (registered by the spec seat via #11504 — see + * spec-recorded contract (registered by the spec seat via commit f90e82024 — see * `ERROR_CODE_LEDGER['@objectstack/runtime']` and `AutomationResult.code`): * the definition-level guard's verdict is a pure function of the flow * definition, so the engine refuses ONCE, never enters its retry loop, and @@ -109,7 +109,7 @@ import type { AutomationResult } from '@objectstack/spec/contracts'; * `@objectstack/runtime` in `ERROR_CODE_LEDGER` — ⛔ nothing here mints one, * and a fifth row would be a spec-seat widening, never a call-site decision * (the #9384 ruling). `FLOW_INPUT_SCHEMA_INVALID` is the worked example: - * registered by the spec seat first (#11504, under the #10025 ruling), and + * registered by the spec seat first (commit f90e82024, under the #10025 ruling), and * only then transcribed here. */ export type FlowRefusalCode = 'FLOW_DISABLED' | 'FLOW_NO_START_NODE' | 'FLOW_INPUT_SCHEMA_INVALID' | 'FLOW_FAILED'; diff --git a/packages/runtime/src/http-dispatcher.actions-global-key.test.ts b/packages/runtime/src/http-dispatcher.actions-global-key.test.ts index 455b06cd694..04db04d7375 100644 --- a/packages/runtime/src/http-dispatcher.actions-global-key.test.ts +++ b/packages/runtime/src/http-dispatcher.actions-global-key.test.ts @@ -9,7 +9,7 @@ * 1. **Registration key vs lookup key.** Both writers register an * objectName-less action under the literal `'global'` — `AppPlugin` * (`action.object || 'global'`) and the ObjectQL plugin (whose copy of the - * ladder was converged into `standaloneActionOwnerKey` by #14422). The + * ladder was converged into `standaloneActionOwnerKey` by commit dc7c226b9). The * REST fallback probed `'*'`, and `engine.executeAction` is an * exact-string `Map` lookup with no wildcard semantics, so the probe could * only ever miss: `Action 'log_call' on object '*' not found`. diff --git a/packages/runtime/src/http-dispatcher.permission-denied-user-message.test.ts b/packages/runtime/src/http-dispatcher.permission-denied-user-message.test.ts index b299ecfcdba..b998c724acb 100644 --- a/packages/runtime/src/http-dispatcher.permission-denied-user-message.test.ts +++ b/packages/runtime/src/http-dispatcher.permission-denied-user-message.test.ts @@ -4,14 +4,14 @@ * [#13623] The DENIAL door carries the producer's `userMessage` — the second * door that dropped it, and the one whose refusals users most need to read. * - * ## Why this is a second door and not the one #13241 repaired + * ## Why this is a second door and not the one commit a21d2a9cf repaired * * `HttpDispatcher.dispatch`'s foot catch is **not a pure rethrow**. It * recognises `isPermissionDeniedError` — `name === 'PermissionDeniedError'` * **or** `code === 'PERMISSION_DENIED'` **or** a message starting * `[Security] Access denied` — and answers it itself, from * `packages/runtime/src/http-dispatcher.ts`. Such a throw therefore never - * reaches `dispatcher-plugin`'s `errorResponseBase`, which is the exit #13241 + * reaches `dispatcher-plugin`'s `errorResponseBase`, which is the exit commit a21d2a9cf * taught to carry the mark. Same field, same contract, different door. * * `ApiErrorSchema.userMessage` has declared the slot all along, and @@ -21,7 +21,7 @@ * * ## Why THIS door matters more than its size suggests * - * #9934 made the mark **status-agnostic** precisely so a 403 could carry it, + * Commit 79c46da90 made the mark **status-agnostic** precisely so a 403 could carry it, * and a 403 is the refusal class most likely to carry deliberately-authored * text: *"You do not have access to this report; ask an admin for the Reporting * role"* is exactly the sentence a producer marks. The one door that swallowed @@ -41,7 +41,7 @@ * * That same ruling is also why the change is owed: it makes REST's shape the * contract for BOTH transports, and REST's shape has carried the mark on this - * identical denial since #9934 (`mapDataError` = `withDeclaredUserMessage` over + * identical denial since commit 79c46da90 (`mapDataError` = `withDeclaredUserMessage` over * `classifyDataError`, pinned in * `packages/rest/src/rest-user-facing-refusal-marking.test.ts`). The * dispatcher's 403 was the one that differed. `§6` pins the parity. diff --git a/packages/runtime/src/http-dispatcher.test.ts b/packages/runtime/src/http-dispatcher.test.ts index 57b7265820d..c24826ec7fc 100644 --- a/packages/runtime/src/http-dispatcher.test.ts +++ b/packages/runtime/src/http-dispatcher.test.ts @@ -79,7 +79,7 @@ const PKG_ADMIN = () => ({ request: {}, executionContext: { userId: 'u_pkg_admin * destroys. Only the caller changes; the gate itself is pinned in * `domains/automation-write-capability-gate.test.ts`. * - * [#10243] `POST /:name/toggle` uses this caller too, since the 2026-08-23 + * [commit 266436a7f] `POST /:name/toggle` uses this caller too, since the 2026-08-23 * ruling put enablement in the same write set. The EXECUTION routes on the * domain (trigger / resume) keep `AUTHED_CALLER`, deliberately — that half of * the line did not move. @@ -141,7 +141,7 @@ describe('HttpDispatcher', () => { type: 'objects', name: 'my_obj', item: body, - // [#10888] Server-stated, and asserted here rather than relaxed + // [commit d806081dd] Server-stated, and asserted here rather than relaxed // to `objectContaining`: this door's whole claim to the face is // that it answers through `errorFromThrown`, which carries a // refusal's `issues[]` in `details` (pinned below). If the face @@ -179,10 +179,10 @@ describe('HttpDispatcher', () => { // name='views/all_leads' — the dispatcher's own compound arity, // folding every trailing segment into one slash-bearing key. // - // #12176 retired compound metadata item names (maintainer ruling - // 2026-08-25); #12194 refuses every slash-bearing name at the + // Commit 7986d973f retired compound metadata item names (maintainer ruling + // 2026-08-25); commit 311433f6b refuses every slash-bearing name at the // publish door, so the fold could only address names that can no - // longer be created; #12195 removes it. The domain now DECLINES, + // longer be created; commit 7986d973f removes it. The domain now DECLINES, // and nothing is written. const path = '/lead/views/all_leads'; @@ -202,7 +202,7 @@ describe('HttpDispatcher', () => { // nothing decodes for it, so `%2F` keeps the path at two segments // and `decodeMetaNameSegment` restores the stored key — which is // what keeps a pre-grammar residue row addressable here, per - // #12194's "any stored junk name remains listable and clearable". + // commit 311433f6b: any stored junk name stays listable and clearable. const result = await dispatcher.handleMetadata('/lead/views%2Fall_leads', context, 'PUT', body); expect(result.handled).toBe(true); @@ -424,7 +424,7 @@ describe('HttpDispatcher', () => { }); it('should toggle a flow via POST /:name/toggle', async () => { - // [#10243] `FLOW_AUTHOR`, not `AUTHED_CALLER`: toggle joined the + // [commit 266436a7f] `FLOW_AUTHOR`, not `AUTHED_CALLER`: toggle joined the // `manage_metadata` write set by ruling. This case is about ROUTING // — which service method the path reaches, with which arguments — // so only the caller changes. diff --git a/packages/runtime/src/http-dispatcher.ts b/packages/runtime/src/http-dispatcher.ts index d6ad749b8ce..ed66811dfdc 100644 --- a/packages/runtime/src/http-dispatcher.ts +++ b/packages/runtime/src/http-dispatcher.ts @@ -663,7 +663,7 @@ export class HttpDispatcher { acceptOAuthAccessToken: /^(?:\/environments\/[^/]+)?\/mcp(?:[/?]|$)/.test(cleanPath), }); } catch (err) { - // [#13906 decision 1 A / #13279] The ONE fault that must stay loud: + // [#13906 decision 1 A / commit 6a180e42d] The ONE fault that must stay loud: // an authorization input that exists and could not be read (a // failed permission-store read, a `tenancy` service that is // registered and failed to build). Swallowing it here answered an @@ -1125,7 +1125,7 @@ export class HttpDispatcher { // and parses the body against `ApiErrorSchema`, which now PASSES for // every body this door emits — the "parse every body it emits" half. const declaredCode = demotedDeclaredCode(thrown); - // [#9934] The producer-side user-facing marking rides as a declared + // [commit 79c46da90] The producer-side user-facing marking rides as a declared // sibling of `code`/`message` (`ApiErrorSchema.userMessage`), exactly // like `declaredCode` — the shared resolver already answered whether // the throw declared one (`declaredUserMessage`'s non-empty-string @@ -2794,7 +2794,7 @@ export class HttpDispatcher { console.warn(`[HttpDispatcher] PERMISSION_DENIED on ${method} ${cleanPath} — ${withheld}`); } // [#13623] The producer's marked user-facing text rides out — - // the SECOND door that dropped it. #13241 repaired the + // the SECOND door that dropped it. Commit a21d2a9cf repaired the // THROW-TRANSPARENT exit (`dispatcher-plugin.errorResponseBase`); // a marked denial never reaches that exit, because this catch is // not a pure rethrow: it recognises the denial and answers it @@ -2821,7 +2821,7 @@ export class HttpDispatcher { // FOR the caller, platform and driver code never set it, and it // lands as a declared top-level sibling of `code`/`message` // (`ApiErrorSchema.userMessage`), never inside `details`. - // The mark never moves the status or the `code` (#9934). + // The mark never moves the status or the `code` (commit 79c46da90). const userMessage = declaredUserMessage(e); return { handled: true, diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 0a21232ca24..7b32f459bab 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -11,7 +11,7 @@ export type { RuntimeConfig } from './runtime.js'; export { createStandaloneStack, resolveObjectStackHome, resolveStandaloneDatabase } from './standalone-stack.js'; export type { StandaloneStackConfig, StandaloneStackResult, ResolvedStandaloneDatabase } from './standalone-stack.js'; -// The ONE libSQL/Turso loader (#6268). Public because `@objectstack/cli` is a +// The ONE libSQL/Turso loader (commit 68f5eccb1). Public because `@objectstack/cli` is a // consumer, not a second implementation: `utils/storage-driver.ts` delegates to // `loadTursoDriverFactory` and RE-EXPORTS `MissingDriverPackageError`, so // `serve.ts`'s `e instanceof MissingDriverPackageError` fatal branch tests one diff --git a/packages/runtime/src/load-artifact-bundle.ts b/packages/runtime/src/load-artifact-bundle.ts index d5f0c6e8e7f..c78b131e624 100644 --- a/packages/runtime/src/load-artifact-bundle.ts +++ b/packages/runtime/src/load-artifact-bundle.ts @@ -180,7 +180,7 @@ export async function mergeRuntimeModule(bundle: any, artifactAbsPath: string, t // `effect: 'writes'` included — which is #4396's silent un-declaring in // the other spelling: the function still registers, still runs, and its // writes are still counted as none, so #4354's broken-sweep alert stays - // quiet on the one run that needed it. Unreachable until #6238 let the + // quiet on the one run that needed it. Unreachable until commit c8d6f6e08 let the // array form past the parse; reachable now, so it is handled here. if (Array.isArray(declaredFunctions)) { const moduleFns = fns as Record; diff --git a/packages/runtime/src/meta-compound-arity-mint-door.test.ts b/packages/runtime/src/meta-compound-arity-mint-door.test.ts index a249d2af571..eab5ea7e96c 100644 --- a/packages/runtime/src/meta-compound-arity-mint-door.test.ts +++ b/packages/runtime/src/meta-compound-arity-mint-door.test.ts @@ -1,14 +1,14 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #8421/#12194 — the COMPOUND `/meta` arity write is refused at the item-name + * #8421 / commit 311433f6b — the COMPOUND `/meta` arity write is refused at the item-name * grammar gate, pinned at the LIVE ROUTE. * * `/metadata/lead/views/all_leads` is `type='lead'`, `name='views/all_leads'`: * ONE operation reaching ONE `saveMetaItem`. Under #8421 that shape was * EXEMPTED from the unrecognised-type refusal (the `:type` segment carries an * OBJECT name no static contract can enumerate), and this file pinned the - * exemption at the wire. #12194 (stage 1 of #12176's maintainer-ruled + * exemption at the wire. Commit 311433f6b (stage 1 of the maintainer-ruled * retirement of compound-name addressing, 2026-08-25) reverses the pinned * direction: the item-name grammar refuses every slash-bearing name BEFORE the * type verdict runs, so the compound WRITE now answers `400 INVALID_REQUEST` @@ -34,7 +34,7 @@ * * ## Reverse verification, direction predicted BEFORE running * - * On the pre-#12194 tree (grammar gate absent, compound exemption present) + * On the tree before commit 311433f6b (grammar gate absent, compound exemption present) * the two compound cases run the OTHER way — `200`, row stored under the * slash key. Measured on `origin/main@22c42c9b` before the door change: this * file's two compound pins were the acceptance direction; after the door @@ -224,9 +224,9 @@ describe('#8421 — the compound `/meta` arity is not a metadata-type claim', () ); // The domain answers a LOCATED not-found rather than serving the path. - // Until #12195 it folded `views/all_leads` out of the trailing segments + // Until commit 7986d973f it folded `views/all_leads` out of the trailing segments // and answered — first by minting the row under the slash key - // (pre-#12194), then by refusing it at the grammar gate (#12194). + // (before commit 311433f6b), then by refusing it at the grammar gate (commit 311433f6b). // Neither happens now: there is no three-segment metadata route. // // ADR-0112: code AND status. A bare 404 assertion could not tell this @@ -257,7 +257,7 @@ describe('#8421 — the compound `/meta` arity is not a metadata-type claim', () // A caller who genuinely means the name `views/all_leads` percent-encodes // it, which keeps the path at TWO segments. `decodeMetaNameSegment` - // restores the stored spelling, and #12194's grammar is what answers — + // restores the stored spelling, and the grammar of commit 311433f6b is what answers — // 400 with the dotted prescription, the caller's mistake named as such. // // This is the pin that separates "the route is gone" from "the name is @@ -296,7 +296,7 @@ describe('#8421 — the compound `/meta` arity is not a metadata-type claim', () // [#6245] spec-valid body — `webhook` resolves a schema through // UNREGISTERED_KIND_SCHEMAS, and this control measures the ARITY // door, so a malformed body would 422 and misread it. (`theme` was - // the specimen until #10485 retired that kind.) + // the specimen until commit 35ad101bc retired that kind.) const res = responseOf(await dispatcher.handleMetadata( '/webhook/midnight_hook', ctx(), 'PUT', { name: 'midnight_hook', label: 'Midnight', object: 'task', triggers: ['create'], url: 'https://example.com/hook' }, @@ -308,7 +308,7 @@ describe('#8421 — the compound `/meta` arity is not a metadata-type claim', () it('CONTROL — the capability gate still fires first at the SIMPLE arity', async () => { // #7019's gate is what masked this site, and it must keep masking an - // UNAUTHORIZED caller. [#12195] Driven at the simple arity now: the + // UNAUTHORIZED caller. [commit 7986d973f] Driven at the simple arity now: the // compound form this used to use is no longer handled at all, so it // would answer ROUTE_NOT_FOUND before any gate — which would make this // a control over nothing. diff --git a/packages/runtime/src/meta-field-overlay-lock.test.ts b/packages/runtime/src/meta-field-overlay-lock.test.ts index 9bc3c5be745..5b03b07146f 100644 --- a/packages/runtime/src/meta-field-overlay-lock.test.ts +++ b/packages/runtime/src/meta-field-overlay-lock.test.ts @@ -701,7 +701,7 @@ describe('#7743 — PUT /meta/field/. honours the registry overla // [#6245] spec-valid bodies — `webhook` resolves a schema through // UNREGISTERED_KIND_SCHEMAS, and this control measures the #7894 // PERMISSION verdict, so a malformed body would 422 and misread it. - // (`theme` was the specimen until #10485 retired that kind out of the + // (`theme` was the specimen until commit 35ad101bc retired that kind out of the // spelling contract.) const singular = responseOf(await dispatcher.handleMetadata( '/webhook/midnight_hook', ctx(), 'PUT', diff --git a/packages/runtime/src/meta-overlay-read-your-writes.test.ts b/packages/runtime/src/meta-overlay-read-your-writes.test.ts index 13e5f1dd011..1c44013843e 100644 --- a/packages/runtime/src/meta-overlay-read-your-writes.test.ts +++ b/packages/runtime/src/meta-overlay-read-your-writes.test.ts @@ -202,7 +202,7 @@ describe('#4521 — read-your-writes between saveMeta and the dispatch path', () // `restoreArtifactRegistryView` removes on delete. Pinned here because // the write-through is what makes that separation load-bearing. // - // #6483 rolled `action`'s `allowOrgOverride` back to `false` + // Commit ee58392e1 rolled `action`'s `allowOrgOverride` back to `false` // (ADR-0005: page/app/action are ❌ in the amendment table), so // overriding this PACKAGED action needs the one documented door that // remains — the `OS_METADATA_WRITABLE` operator escape hatch. The @@ -362,7 +362,7 @@ describe('#5079 — list / get / dispatch agree immediately after deleteMeta', ( // "reset to artifact default" would delete the artifact instead of // revealing it. // - // #6483 rolled `action`'s `allowOrgOverride` back to `false` + // Commit ee58392e1 rolled `action`'s `allowOrgOverride` back to `false` // (ADR-0005: page/app/action are ❌ in the amendment table), so // overriding this PACKAGED action needs the one documented door that // remains — the `OS_METADATA_WRITABLE` operator escape hatch, exactly diff --git a/packages/runtime/src/meta-write-org-scope.test.ts b/packages/runtime/src/meta-write-org-scope.test.ts index ca373026a43..af0fedd48c1 100644 --- a/packages/runtime/src/meta-write-org-scope.test.ts +++ b/packages/runtime/src/meta-write-org-scope.test.ts @@ -72,7 +72,7 @@ import { } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; -// [#10503] The URL spelling contract itself — the map storage folds through, +// [commit 67ceb9aef] The URL spelling contract itself — the map storage folds through, // and the fold the transport was missing. Imported so the sweep below is // quantified over the CONTRACT rather than over a hand-copied specimen list // (Prime Directive #8): a future spelling limb arrives inside the quantifier. @@ -213,7 +213,7 @@ function makeDispatcher( protocol: unknown, engine: any, activeOrganizationId: string | undefined, - // [#10503] The `metadata` CORE-SERVICE slot, absent by default. The + // [commit 67ceb9aef] The `metadata` CORE-SERVICE slot, absent by default. The // `/published` route consults the protocol's layered overlay first and // only then falls back to THIS slot — the code/package store. Registering // it unconditionally would change which branch every #7018 case above @@ -360,7 +360,7 @@ describe('#7018 — the registry decides whether a metadata write carries the se expect(declaresOrgOverride('flows')).toBe(declaresOrgOverride('flow')); // A runtime-registered type with no registry entry has no per-org read // channel either, so it is env-wide too. (`webhook` took this slot - // from `theme` at #10485 — the retired kind left the contract.) + // from `theme` at commit 35ad101bc — the retired kind left the contract.) expect(declaresOrgOverride('webhook')).toBe(false); // No active org in, no org out — for every type. expect(organizationIdForMetaWrite('view', undefined)).toBeUndefined(); @@ -505,8 +505,8 @@ describe('#7018 — the registry decides whether a metadata write carries the se }); /** - * #10503 — the dispatcher `/metadata` transport decided ORGANIZATION SCOPE - * from the RAW path segment. The #10340 defect, one transport over. + * Until commit 67ceb9aef the dispatcher `/metadata` transport decided ORGANIZATION SCOPE + * from the RAW path segment. The defect commit 26f3588fb fixed, one transport over. * * ── What was broken ─────────────────────────────────────────────────────── * @@ -532,7 +532,7 @@ describe('#7018 — the registry decides whether a metadata write carries the se * store, which is keyed by CANONICAL type. Handed the raw segment it answered * 404 under a recognised plural and 200 under the singular twin. * - * The correction is the one #10340 landed for REST and the one + * The correction is the one commit 26f3588fb landed for REST and the one * `packages/spec/src/meta-spelling/metadata-url-spelling.ts` mandates: fold * the segment through `canonicalMetaUrlType` AT THE BOUNDARY, before the scope * decision. ⛔ NOT by widening `declaresOrgOverride` — a predicate below the @@ -580,7 +580,7 @@ describe('#10503 the dispatcher /metadata transport decides org scope on the FOL plural: 'translations', singular: 'translation', item: { - // [#12194] The addressing name is snake_case — the item-name + // [commit 311433f6b] The addressing name is snake_case — the item-name // grammar refuses `zh-CN` as an ADDRESSING key (uppercase + // dash). The BCP-47 spelling lives in `locale`, which is this // type's required identity; the name was always free to choose. diff --git a/packages/runtime/src/metadata-list-ambient-vs-bare-transaction.integration.test.ts b/packages/runtime/src/metadata-list-ambient-vs-bare-transaction.integration.test.ts index 0fd696764e4..b21379cd781 100644 --- a/packages/runtime/src/metadata-list-ambient-vs-bare-transaction.integration.test.ts +++ b/packages/runtime/src/metadata-list-ambient-vs-bare-transaction.integration.test.ts @@ -75,7 +75,7 @@ const SEEDED_NAME = 'thing'; const STALLED_OBJECT = 'sys_metadata'; // ═══════════════════════════════════════════════════════════════════════════ -// [#10380] The BARE case's expected error output: WITHHELD from the shared +// [commit dd8172ee2] The BARE case's expected error output: WITHHELD from the shared // log, and ASSERTED instead // ═══════════════════════════════════════════════════════════════════════════ // @@ -92,7 +92,7 @@ const STALLED_OBJECT = 'sys_metadata'; // // Turbo interleaves package logs without attribution, so in that shard log // these are indistinguishable from a real failure. Not a hypothetical: they -// were lifted VERBATIM into a p1 flake signature (#10293) and sent a whole +// were lifted VERBATIM into a p1 flake signature (a vitest teardown race, fixed by commit 92a69d813) and sent a whole // dispatch cycle at the wrong mechanism. Expected-failure noise from a green // test is a diagnosis tax on every future red shard. // @@ -203,7 +203,7 @@ interface Fixture { loader: DatabaseLoader; /** Every `driver.find` the fixture has observed, and whether it carried a transaction. */ reads: () => Array<{ object: string; hasTx: boolean }>; - /** [#10380] What this fixture withheld from the shared log, per channel. */ + /** [commit dd8172ee2] What this fixture withheld from the shared log, per channel. */ withheld: WithheldNoise; } @@ -220,7 +220,7 @@ afterEach(async () => { }); async function boot(): Promise { - // [#10380] Installed BEFORE the driver exists, because knex's logger is + // [commit dd8172ee2] Installed BEFORE the driver exists, because knex's logger is // baked into the client at construction. const noise = newNoiseCapture(); @@ -230,10 +230,10 @@ async function boot(): Promise { useNullAsDefault: true, // See the header: shortens the wait, not the shape. acquireConnectionTimeout: ACQUIRE_MS, - // [#10380] Channel 1 of 3 — knex's own `Acquire connection error`. + // [commit dd8172ee2] Channel 1 of 3 — knex's own `Acquire connection error`. log: { warn: noise.knexWarn }, }); - // [#10380] Channel 2 of 3 — the driver's read-exit envelope. Assignment + // [commit dd8172ee2] Channel 2 of 3 — the driver's read-exit envelope. Assignment // rather than a constructor option because `logger` is a protected field // with a `console` default; this is the idiom the field's own doc comment // names ("Tests inject a spy") and that ~20 sibling driver suites use. @@ -252,7 +252,7 @@ async function boot(): Promise { }); const engine = new ObjectQL(); - // [#10380] Channel 3 of 3 — the engine frame above the driver's exit. A + // [commit dd8172ee2] Channel 3 of 3 — the engine frame above the driver's exit. A // Proxy on ONE method, the idiom `engine-readonly-when-parent.test.ts` // established: every other logger method resolves to the engine's own. // [#17212] That method is `warn` — the level the engine reports this frame at. @@ -362,7 +362,7 @@ describe('#7842 metadata list under an open transaction: ambient vs bare (real O // the acquire bound the bare case exhausts. expect(elapsed).toBeLessThan(STALL_CEILING_MS); - // ── [#10380] The capture's own anti-vacuity guard, on the side that is + // ── [commit dd8172ee2] The capture's own anti-vacuity guard, on the side that is // expected to be SILENT. The ambient path must produce none of the three // features — so if it ever started stalling, the sinks installed for the // bare case would swallow the evidence and this case would still pass on @@ -422,7 +422,7 @@ describe('#7842 metadata list under an open transaction: ambient vs bare (real O expect(bare.length).toBeGreaterThan(0); expect(bare.every((r) => !r.hasTx)).toBe(true); - // ── [#10380] The capture is a PIN, not a mute. These three lines used + // ── [commit dd8172ee2] The capture is a PIN, not a mute. These three lines used // to reach the shared `Test Core` log out of a PASSING test and were // read there as a real failure; they are withheld now, and asserted // here instead. If the stall stops happening, the log goes quiet AND diff --git a/packages/runtime/src/notification-schema-conformance.integration.test.ts b/packages/runtime/src/notification-schema-conformance.integration.test.ts index 299cd3b37ae..4e8bcb57ceb 100644 --- a/packages/runtime/src/notification-schema-conformance.integration.test.ts +++ b/packages/runtime/src/notification-schema-conformance.integration.test.ts @@ -65,7 +65,7 @@ const declaredMarkReadKeys = () => new Set(Object.keys((MarkNotificationsReadRes const declaredMarkAllReadKeys = () => new Set(Object.keys((MarkAllNotificationsReadResponseSchema as any).shape)); // ═══════════════════════════════════════════════════════════════════════════ -// [#10380 → #10629 → #13325] The authz resolver's expected read failures: +// [commits dd8172ee2 → 13a6cb4ad → 2e0b7b18f] The authz resolver's expected read failures: // WITHHELD from the shared log, and ASSERTED instead // ═══════════════════════════════════════════════════════════════════════════ // @@ -75,7 +75,7 @@ const declaredMarkAllReadKeys = () => new Set(Object.keys((MarkAllNotificationsR // one by design — the resolver is fail-closed and must always resolve — but on // the way out the driver and the engine each log it. // -// ⚠️ [#13273] WHICH ENGINE CHANNEL — and why this file stopped rolling its own +// ⚠️ [commit 3a86a65e7] WHICH ENGINE CHANNEL — and why this file stopped rolling its own // capture. `ObjectQL.reportFindFailure` now picks the level from the CAUSE: a // read whose table was never provisioned — i.e. every read this block is // declared over — is logged at `debug`, carrying a @@ -88,11 +88,11 @@ const declaredMarkAllReadKeys = () => new Set(Object.keys((MarkAllNotificationsR // which satisfied that arm's own predicate. Dead suppression that read as live // protection, and the file stayed green throughout because everything it // asserted was fed by the DRIVER channel. It now uses the shared -// `captureExpectedReadRefusals` (#10629), which wraps BOTH channels, so which +// `captureExpectedReadRefusals` (commit 13a6cb4ad), which wraps BOTH channels, so which // channel a frame arrives on is the ENGINE's classification and never this // fixture's problem. // -// Counts RE-MEASURED on this tree (#13325), not transcribed: +// Counts RE-MEASURED on this tree (commit 2e0b7b18f), not transcribed: // // pnpm --filter @objectstack/runtime exec vitest run \ // src/notification-schema-conformance.integration.test.ts @@ -108,7 +108,7 @@ const declaredMarkAllReadKeys = () => new Set(Object.keys((MarkAllNotificationsR // // Turbo interleaves package logs without attribution, so in the `Test Core` // shard log those are indistinguishable from a real failure — they were lifted -// verbatim into a p1 flake signature (#10293) and cost a full dispatch cycle +// verbatim into a p1 flake signature (a vitest teardown race, fixed by commit 92a69d813) and cost a full dispatch cycle // aimed at the wrong mechanism. // // ⛔ Not a mute. A capture that only silences would make this file blind: if @@ -278,7 +278,7 @@ describe('[#5792] the notification wire bodies conform to the schemas the catalo let baseUrl: string; let messaging: MessagingService; /** - * [#10629] The expected-noise capture, asserted in `afterAll`. The SHARED + * [commit 13a6cb4ad] The expected-noise capture, asserted in `afterAll`. The SHARED * one — see the block above for what the per-fixture copy this replaced * could no longer do. */ @@ -286,7 +286,7 @@ describe('[#5792] the notification wire bodies conform to the schemas the catalo beforeAll(async () => { kernel = new ObjectKernel({ logger: { level: 'silent' } }); - // [#10380] The driver is named rather than inlined so its logger can be + // [commit dd8172ee2] The driver is named rather than inlined so its logger can be // scoped before it ever runs a statement. const driver = new SqliteWasmDriver({ filename: ':memory:' }); noise.captureDriver(driver); @@ -299,7 +299,7 @@ describe('[#5792] the notification wire bodies conform to the schemas the catalo await kernel.use(createDispatcherPlugin({ prefix: '/api/v1', securityHeaders: false, requireAuth: false })); await kernel.bootstrap(); - // [#10380] The engine only exists once the kernel has bootstrapped; the + // [commit dd8172ee2] The engine only exists once the kernel has bootstrapped; the // reads this scopes all happen later, per request. noise.captureEngine(kernel.getService('objectql')); @@ -326,7 +326,7 @@ describe('[#5792] the notification wire bodies conform to the schemas the catalo }, 60_000); afterAll(async () => { - // ── [#18070] The #10380 / #13325 pin, turned around. It used to assert + // ── [#18070] The commits dd8172ee2 / 2e0b7b18f pin, turned around. It used to assert // that the five resolver reads were still being REFUSED here — the symptom // pinned, not the defect closed. They are provisioned now, so the // assertion is that they SUCCEED, and `[]` means an empty table rather @@ -481,19 +481,19 @@ describe('[#5792] the notification wire bodies conform to the schemas the catalo // parse and the KEY assertion (⊆, not =) cannot see it either. // // Both were pinned here as the measured behaviour of `origin/main`, on the - // note that whichever way #6361 / #6363 were ruled, these assertions are the + // note that whichever way the two cards were ruled (landed as commits 90bbf2510 / 17d095413), these assertions are the // ones that must flip. BOTH have now been ruled (2026-08-07, Option A, and // ruled JOINTLY — one capability's two halves are never half-deleted), and // both assertions have flipped: // - // * #6363 made the declaration true — `unreadCount` really is the total; - // * #6361 removed the declaration instead — `cursor` is gone from the + // * commit 17d095413 made the declaration true — `unreadCount` really is the total; + // * commit 90bbf2510 removed the declaration instead — `cursor` is gone from the // request half, the response half and the SDK producer, because there was // no implementation to make it true ABOUT. Opposite repairs, same rule: // declared must equal enforced. // // The two directions are why the pair is worth keeping side by side. Note the - // #6361 assertion below now pins something subtler than the #6363 one: the + // `cursor` assertion below (commit 90bbf2510) now pins something subtler than the `unreadCount` one (commit 17d095413): the // WIRE did not change (an unknown `?cursor=` was ignored before and is // ignored now), so what it proves is that the CONTRACT stopped promising the // thing the wire never delivered. A test that only checked "page2 === page1" @@ -515,7 +515,7 @@ describe('[#5792] the notification wire bodies conform to the schemas the catalo // The LIST is still windowed — that half never changed. expect(windowed.notifications).toHaveLength(1); // The BADGE is not: declared 'Total number of unread notifications', and - // now delivered as one. Before #6363 this read `1` — the window's size, + // now delivered as one. Before commit 17d095413 this read `1` — the window's size, // which is what a user with more unread than the page size was told // forever. The parse was green either way; only this assertion can tell. expect(windowed.unreadCount).toBe(all.unreadCount); diff --git a/packages/runtime/src/notification-schema-conformance.test.ts b/packages/runtime/src/notification-schema-conformance.test.ts index fdfdcb5044f..a3801b6fe46 100644 --- a/packages/runtime/src/notification-schema-conformance.test.ts +++ b/packages/runtime/src/notification-schema-conformance.test.ts @@ -198,7 +198,7 @@ describe('[#5792] /notifications conforms to the schemas the catalog declares', }); it('[#6361] the declaration no longer states a `limit` default the route never applies', async () => { - // FLIPPED by #6361 (maintainer ruling 2026-08-07, Option A). This pin + // FLIPPED by commit 90bbf2510 (maintainer ruling 2026-08-07, Option A). This pin // used to record the DEFECT: `limit` was `z.number().default(20)` while // the route forwarded `undefined` and the provider applied its own 50, // so the declared default had never once been in effect. diff --git a/packages/runtime/src/notifications.hono.integration.test.ts b/packages/runtime/src/notifications.hono.integration.test.ts index 9f7158bc933..574e1a1629a 100644 --- a/packages/runtime/src/notifications.hono.integration.test.ts +++ b/packages/runtime/src/notifications.hono.integration.test.ts @@ -200,7 +200,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () let kernel: ObjectKernel; let baseUrl: string; let messaging: MessagingService; - /** [#10629] The expected-noise capture, asserted by every authed test below. */ + /** [commit 13a6cb4ad] The expected-noise capture, asserted by every authed test below. */ const noise = captureExpectedReadRefusals([...ABSENT_AUTHZ_TABLES]); beforeAll(async () => { @@ -210,7 +210,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () // MessagingServicePlugin registers the `notification` service the dispatcher // resolves and owns the inbox tables. Inline delivery (reliableDelivery:false) // writes the inbox row synchronously so `emit()` is observable immediately. - // [#10629] The driver is named rather than inlined so its logger can be + // [commit 13a6cb4ad] The driver is named rather than inlined so its logger can be // scoped before it ever runs a statement. const driver = new SqliteWasmDriver({ filename: ':memory:' }); noise.captureDriver(driver); @@ -230,7 +230,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () await kernel.bootstrap(); - // [#10629] The engine only exists once the kernel has bootstrapped; the + // [commit 13a6cb4ad] The engine only exists once the kernel has bootstrapped; the // reads this scopes all happen later, per request. noise.captureEngine(kernel.getService('objectql')); @@ -339,7 +339,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () expect(served.status).toBe(200); expect((await served.json() as { success: boolean }).success).toBe(true); - // ── [#18070] The #10629 pin, turned around: this used to assert that the + // ── [#18070] The commit 13a6cb4ad pin, turned around: this used to assert that the // five resolver reads were still being REFUSED here. They are provisioned // now, so the assertion is that they SUCCEED. Kept per authed test rather // than moved to `afterAll` for the reason the old one was — two tests in @@ -392,7 +392,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () expect(receipts.length).toBe(2); expect(receipts.every((r: any) => r.state === 'read')).toBe(true); - // ── [#18070] The #10629 pin, turned around: this used to assert that the + // ── [#18070] The commit 13a6cb4ad pin, turned around: this used to assert that the // five resolver reads were still being REFUSED here. They are provisioned // now, so the assertion is that they SUCCEED. Kept per authed test rather // than moved to `afterAll` for the reason the old one was — two tests in @@ -409,7 +409,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () // POST /api/v1/notifications/read/all → { readCount: 200 } // GET /api/v1/notifications → { unreadCount: 150 } // - // #6363 did not cause that — it removed the cover. While `unreadCount` was + // Commit 17d095413 did not cause that — it removed the cover. While `unreadCount` was // window-scoped the shortfall was self-consistent and invisible; once the // badge became a true total the same request pair states it out loud, which // is why this pin lives at the wire and not only under the service. @@ -433,7 +433,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () } const before = await (await as(BULK_USER, '/api/v1/notifications')).json(); - expect(before.data.unreadCount).toBe(TOTAL); // the true total (#6363) + expect(before.data.unreadCount).toBe(TOTAL); // the true total (commit 17d095413) expect(before.data.notifications).toHaveLength(50); // the list is still one window const readAll = await (await as(BULK_USER, '/api/v1/notifications/read/all', { method: 'POST' })).json(); @@ -450,7 +450,7 @@ describe('in-app notifications over a real hono server (integration, #3362)', () expect(receipts.length).toBe(TOTAL); expect(receipts.every((r: any) => r.state === 'read')).toBe(true); - // ── [#18070] The #10629 pin, turned around: this used to assert that the + // ── [#18070] The commit 13a6cb4ad pin, turned around: this used to assert that the // five resolver reads were still being REFUSED here. They are provisioned // now, so the assertion is that they SUCCEED. Kept per authed test rather // than moved to `afterAll` for the reason the old one was — two tests in diff --git a/packages/runtime/src/package-door-namespace-conflict-code.test.ts b/packages/runtime/src/package-door-namespace-conflict-code.test.ts index 80d25514c2a..55c1fb815fc 100644 --- a/packages/runtime/src/package-door-namespace-conflict-code.test.ts +++ b/packages/runtime/src/package-door-namespace-conflict-code.test.ts @@ -1,14 +1,14 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#14748] `POST /api/v1/packages` answers a namespace collision with + * [commit 92b5d7f00] `POST /api/v1/packages` answers a namespace collision with * `error.code: NAMESPACE_CONFLICT` — the wire half of registering the code in * `ERROR_CODE_LEDGER`. * * ## What changed, and why a pin belongs here rather than beside the throw * * `NamespaceConflictError` (`packages/objectql/src/registry.ts`) has carried - * the ADR-0112 envelope (`code` + `status: 422`) since #14474, and + * the ADR-0112 envelope (`code` + `status: 422`) since commit df657d9df, and * `packages/objectql/src/registry-namespace-install-gate.test.ts` asserts both * fields ON THE THROW. That is a different claim from this one. Until the * ledger row landed, `NAMESPACE_CONFLICT` was not an `ErrorCode` member, so the diff --git a/packages/runtime/src/package-list-commits-org-scope.integration.test.ts b/packages/runtime/src/package-list-commits-org-scope.integration.test.ts index becfc655c07..0bd185005b9 100644 --- a/packages/runtime/src/package-list-commits-org-scope.integration.test.ts +++ b/packages/runtime/src/package-list-commits-org-scope.integration.test.ts @@ -97,7 +97,7 @@ const ACTIVE_ORG = 'org_active'; const OTHER_ORG = 'org_other'; /** - * [#10629] Every publish this fixture makes runs the metadata-protocol build + * [commit 13a6cb4ad] Every publish this fixture makes runs the metadata-protocol build * probes (`metadata-protocol/src/build-probes.ts`), and the views it publishes * are bound to the placeholder object `anything` — the #7741 inline arm * requires an object binding pair, and nothing here creates that table. The @@ -110,12 +110,12 @@ const UNBOUND_PROBE_OBJECT = 'anything'; let cleanup: Array<() => void> = []; -/** [#10629] The expected-noise capture belonging to the latest `boot()`. */ +/** [commit 13a6cb4ad] The expected-noise capture belonging to the latest `boot()`. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(() => { for (const c of cleanup) c(); cleanup = []; - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave an engine running. Every test in this file publishes at // least once, so the probe fires for each of them: this holds for a single // `-t` run as well as for the whole file. @@ -141,7 +141,7 @@ async function boot() { SysMetadataAuditObject, SysMetadataCommitObject, ] as any[]; - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([UNBOUND_PROBE_OBJECT]); noise.captureDriver(driver); diff --git a/packages/runtime/src/package-revert-commit-attribution-org-scope.integration.test.ts b/packages/runtime/src/package-revert-commit-attribution-org-scope.integration.test.ts index 54073e8b359..629e26de5fe 100644 --- a/packages/runtime/src/package-revert-commit-attribution-org-scope.integration.test.ts +++ b/packages/runtime/src/package-revert-commit-attribution-org-scope.integration.test.ts @@ -88,7 +88,7 @@ const ACTIVE_ORG = 'org_active'; const OTHER_ORG = 'org_other'; /** - * [#10629] Every publish this fixture makes runs the metadata-protocol build + * [commit 13a6cb4ad] Every publish this fixture makes runs the metadata-protocol build * probes (`metadata-protocol/src/build-probes.ts`), and the views it publishes * are bound to the placeholder object `anything` — the #7741 inline arm * requires an object binding pair, and nothing here creates that table. The @@ -101,12 +101,12 @@ const UNBOUND_PROBE_OBJECT = 'anything'; let cleanup: Array<() => void> = []; -/** [#10629] The expected-noise capture belonging to the latest `boot()`. */ +/** [commit 13a6cb4ad] The expected-noise capture belonging to the latest `boot()`. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(() => { for (const c of cleanup) c(); cleanup = []; - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave an engine running. Every test in this file publishes at // least once, so the probe fires for each of them: this holds for a single // `-t` run as well as for the whole file. @@ -130,7 +130,7 @@ async function boot() { SysMetadataAuditObject, SysMetadataCommitObject, ] as any[]; - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([UNBOUND_PROBE_OBJECT]); noise.captureDriver(driver); diff --git a/packages/runtime/src/package-revert-commit-org-scope.integration.test.ts b/packages/runtime/src/package-revert-commit-org-scope.integration.test.ts index c0d98723294..963874e8f6c 100644 --- a/packages/runtime/src/package-revert-commit-org-scope.integration.test.ts +++ b/packages/runtime/src/package-revert-commit-org-scope.integration.test.ts @@ -115,7 +115,7 @@ const ACTIVE_ORG = 'org_active'; const OTHER_ORG = 'org_other'; /** - * [#10629] Every publish this fixture makes runs the metadata-protocol build + * [commit 13a6cb4ad] Every publish this fixture makes runs the metadata-protocol build * probes (`metadata-protocol/src/build-probes.ts`), and the views it publishes * are bound to the placeholder object `anything` — the #7741 inline arm * requires an object binding pair, and nothing here creates that table. The @@ -128,12 +128,12 @@ const UNBOUND_PROBE_OBJECT = 'anything'; let cleanup: Array<() => void> = []; -/** [#10629] The expected-noise capture belonging to the latest `boot()`. */ +/** [commit 13a6cb4ad] The expected-noise capture belonging to the latest `boot()`. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(() => { for (const c of cleanup) c(); cleanup = []; - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave an engine running. Every test in this file publishes at // least once, so the probe fires for each of them: this holds for a single // `-t` run as well as for the whole file. @@ -160,7 +160,7 @@ async function boot() { SysMetadataAuditObject, SysMetadataCommitObject, ] as any[]; - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([UNBOUND_PROBE_OBJECT]); noise.captureDriver(driver); diff --git a/packages/runtime/src/package-service.null-seam.test.ts b/packages/runtime/src/package-service.null-seam.test.ts index 5bac666f0bf..01e8b6f956b 100644 --- a/packages/runtime/src/package-service.null-seam.test.ts +++ b/packages/runtime/src/package-service.null-seam.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * #10965 — the `service-package` seam guard, on a REAL booted driver. + * Commit ab47f6974 — the `service-package` seam guard, on a REAL booted driver. * * The card established the conflation by reading and named the boot path as * unverified: *"Whether the DevPlugin zero-install stack (a real @@ -37,7 +37,7 @@ * ⚠️ **What the double does NOT model.** It is not evidence about * `@objectstack/driver-memory`'s behaviour. That the real driver logs * `Raw execution not supported in InMemory driver` and returns `null` was - * measured on a real boot while triaging #10965, and it stays pinned on a real + * measured on a real boot in the triage behind commit ab47f6974, and it stays pinned on a real * booted driver by `packages/cli/src/commands/migrate/duplicates.null-seam.test.ts` * (#10677), which reaches it through the datasource factory rather than by * importing it. Nothing about that fact is re-asserted here, and this file would diff --git a/packages/runtime/src/preserve-audit-real-driver.integration.test.ts b/packages/runtime/src/preserve-audit-real-driver.integration.test.ts index 90097cb92c4..8cb010df0a2 100644 --- a/packages/runtime/src/preserve-audit-real-driver.integration.test.ts +++ b/packages/runtime/src/preserve-audit-real-driver.integration.test.ts @@ -47,7 +47,7 @@ const TICKET = { }; /** - * [#10629] This fixture provisions `ticket` and nothing else, so the engine's + * [commit 13a6cb4ad] This fixture provisions `ticket` and nothing else, so the engine's * own single-tenant probe (`ObjectQL.probeInstallOrganizations`, memoised once * per engine) reads a `sys_organization` that was never created. The probe is * fail-soft by construction — it catches `isMissingTableError` and only that — @@ -59,14 +59,14 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; describe('preserveAudit end-to-end on a REAL SqlDriver (#3493 / #3549)', () => { let engine: ObjectQL | null = null; let dir: string | null = null; - /** [#10629] The expected-noise capture belonging to the latest boot. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest boot. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave the engine running. Every test in this file // boots and writes, so the probe fires for each of them: this holds for a // single `-t` run as well as for the whole file. @@ -77,7 +77,7 @@ describe('preserveAudit end-to-end on a REAL SqlDriver (#3493 / #3549)', () => { async function boot() { dir = mkdtempSync(join(tmpdir(), 'os-preserveaudit-')); const driver = new SqlDriver({ client: 'better-sqlite3', connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true }); - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); noise.captureDriver(driver); diff --git a/packages/runtime/src/resolve-project-database.ts b/packages/runtime/src/resolve-project-database.ts index 894a8bb7014..d96a7a10f62 100644 --- a/packages/runtime/src/resolve-project-database.ts +++ b/packages/runtime/src/resolve-project-database.ts @@ -110,7 +110,7 @@ export interface ResolveProjectDatabaseUrlOptions { * Explicit driver selection (`--database-driver` / config). Only `memory` * changes URL resolution (no file default is imposed for an explicitly * in-memory boot); other values select engines, not URLs, and their - * vocabulary is #6345's seam — deliberately not judged here. + * vocabulary is the shared table's seam (commit e2798fab7) — deliberately not judged here. */ explicitDriver?: string; /** Environment to read (`process.env` by default; tests inject their own). */ @@ -180,7 +180,7 @@ function resolveDatabaseStateDir(opts: { * through to the unified default, which is what those projects got before * this tier existed. (Driver-id spellings resolve through the spec's ONE * alias table, `resolveDriverId` — including `turso`/`libsql`, which became - * rows in it in #6345 and no longer need a local special-case here.) + * rows in it in commit e2798fab7 and no longer need a local special-case here.) */ function readConfigDeclaredDefault(opts: { artifactPath?: string; @@ -237,7 +237,7 @@ function readConfigDeclaredDefault(opts: { /** Express a declared datasource's connection as a database URL, or `undefined`. */ function datasourceUrlOf(ds: { driver?: unknown; config?: unknown }, projectRoot?: string): string | undefined { const config = (ds.config ?? {}) as { filename?: unknown; url?: unknown }; - // Since #6345 `turso`/`libsql` are rows in the shared table like every other + // Since commit e2798fab7 `turso`/`libsql` are rows in the shared table like every other // builtin, so the local special-case they needed while turso had no config // contract is gone — one lookup answers for all of them. const canonical = resolveDriverId(ds.driver); @@ -289,7 +289,7 @@ export function resolveProjectDatabaseUrl( // An explicitly in-memory boot gets no file default imposed on it. Only // `memory` is judged here; unknown driver values are refused downstream // (`resolveExplicitDriver`) with the full legal-values list. - // Resolved through the shared table (#6345): `OS_DATABASE_DRIVER=mingo` is an + // Resolved through the shared table (commit e2798fab7): `OS_DATABASE_DRIVER=mingo` is an // accepted spelling of `memory` on both hosts, so it must reach this rung // too — a raw string compare would have imposed the unified default FILE on // a boot that explicitly asked for the in-memory engine. diff --git a/packages/runtime/src/route-ledger.conformance.test.ts b/packages/runtime/src/route-ledger.conformance.test.ts index 6a9e3c6ecfb..6acbc610deb 100644 --- a/packages/runtime/src/route-ledger.conformance.test.ts +++ b/packages/runtime/src/route-ledger.conformance.test.ts @@ -38,7 +38,7 @@ * tracked in #17041; this paragraph states today's coverage, not a plan for * tomorrow's. Deliberately no row/domain counts here: a hand-typed number in * this prose is exactly the unguarded-count defect this lane spent the same - * day eliminating elsewhere (#16919, #17039), and nothing in this file would + * day eliminating elsewhere (commits 2cd4c548e, edf59e359), and nothing in this file would * ever notice it going stale. */ diff --git a/packages/runtime/src/route-ledger.ts b/packages/runtime/src/route-ledger.ts index e1674d9f6fa..0229afa9be0 100644 --- a/packages/runtime/src/route-ledger.ts +++ b/packages/runtime/src/route-ledger.ts @@ -285,7 +285,7 @@ export const NON_DISPATCH_MOUNT_PREFIXES = [ * digits and nothing else. It exists because this list is CENSUS-SHAPED: its * value is its completeness, and a WRONG row fails a gate that reads rows while * a MISSING row fails only a gate that knows how many rows there should be. - * #16758 filed the second kind, after an index-slice edit meant to add two rows + * Commit 6e9bee640 gated the second kind, after an index-slice edit meant to add two rows * removed 105 lines — route rows plus the whole `/actions` section — and exited * 0, caught only because an unrelated gate happened to redden. * @@ -448,7 +448,7 @@ export const ROUTE_LEDGER: readonly RouteLedgerEntry[] = [ // route, no CLI command, and until the contract half landed (PR #16563, card #16495) // not on `IAutomationService` either. #15981 is the correction this gate is built on // at birth: the platform-operator test is the ADR-0095 rung, never the `positions[]` - // name. #13909 is the parent card the repair verb belongs to; #10243 / #12156 are the + // name. #13909 is the parent card the repair verb belongs to; commit 266436a7f / #12156 are the // toggle and clone arms whose `trigger` exclusion this predicate copies; #5519 is the // anonymous floor that answers first. { route: 'POST /automation/:name/runs/:runId/cancel', domain: '/automation', disposition: 'server-only', diff --git a/packages/runtime/src/sandbox/body-runner.test.ts b/packages/runtime/src/sandbox/body-runner.test.ts index c68900f89fb..ec041d7c58e 100644 --- a/packages/runtime/src/sandbox/body-runner.test.ts +++ b/packages/runtime/src/sandbox/body-runner.test.ts @@ -212,7 +212,7 @@ describe('hookBodyRunnerFactory', () => { }); }); - // [#6316] `ctx.user` is seeded from `engineCtx.user` and from nothing else. + // [commit 448ac9565] `ctx.user` is seeded from `engineCtx.user` and from nothing else. // `buildSandboxContext` used to spell `engineCtx?.user ?? engineCtx?.session?.user`; // the second limb was unreachable, because `HookContext['session']` declares // no `user` key and its sole producer — `buildSession()` in objectql, called @@ -524,7 +524,7 @@ describe('actionBodyRunnerFactory', () => { }); }); - // [#6316] The action face of the same removal. `ActionSession` declares + // [commit 448ac9565] The action face of the same removal. `ActionSession` declares // `userId` / `organizationId` / `positions` / `roles` and no `user`, and its // sole producer `buildActionSession()` writes exactly those four — for both // action ctx assembly sites (MCP `run_action` in `action-execution.ts`, REST diff --git a/packages/runtime/src/sandbox/body-runner.ts b/packages/runtime/src/sandbox/body-runner.ts index b15bbd1ed3c..49cfdfb8465 100644 --- a/packages/runtime/src/sandbox/body-runner.ts +++ b/packages/runtime/src/sandbox/body-runner.ts @@ -84,7 +84,7 @@ interface FactoryOptions { * body's own `ctx.log.info('task completed: …')` absent. * * That is the third limb of this shape removed from this file, not the first: - * `doc` / `previousDoc` (#5906) and `session.user` (#6316) were also keys no + * `doc` / `previousDoc` (#5906) and `session.user` (commit 448ac9565) were also keys no * producer ever wrote, deleted rather than left as a second de-facto contract * (Prime Directive #12). The remedy is the same — read the source that exists. * `opts.logger` is the engine's own `Logger`, handed to the factory by all four @@ -505,7 +505,7 @@ function vmVisibleEntryKeys(entryInput: unknown): string[] { } /** - * [#14760] The entry value as the VM could actually have seen it, or `ok: + * [commit ee32e1cb8] The entry value as the VM could actually have seen it, or `ok: * false` for a host value the round-trip cannot evaluate at all. * * Leg 2 of {@link carriedInputKeys} compares an entry snapshot against the VM's @@ -527,7 +527,7 @@ function vmVisibleEntryKeys(entryInput: unknown): string[] { * readonly. Normalising the comparison closes both, because an untouched key is * no longer carried at all and the host simply keeps its own value. * - * ⛔ The fail-open is NOT reversed. #14758 chose "anything we cannot prove + * ⛔ The fail-open is NOT reversed. Commit 84199cb87 chose "anything we cannot prove * equal is reported as changed and therefore CARRIED" deliberately, and a value * that throws here — a cycle, a bigint, a `toJSON` returning `undefined` — still * takes exactly that path. What changes is that the fail-open stops firing on @@ -538,14 +538,14 @@ function jsonSeenByVm(value: unknown): { ok: true; value: unknown } | { ok: fals try { return { ok: true, value: JSON.parse(JSON.stringify(value)) as unknown }; } catch { - /* unrepresentable (cycle, bigint) — #14758's fail-open, for this key only */ + /* unrepresentable (cycle, bigint) — commit 84199cb87's fail-open, for this key only */ return { ok: false }; } } /** - * [#14758] Which keys of the exit dump the write-back should re-assert, or - * `undefined` to assert all of them (the pre-#14758 behaviour). + * [commit 84199cb87] Which keys of the exit dump the write-back should re-assert, or + * `undefined` to assert all of them (the behaviour before commit 84199cb87). * * Two sources, unioned, and neither is sufficient alone: * @@ -565,7 +565,7 @@ function jsonSeenByVm(value: unknown): { ok: true; value: unknown } | { ok: fals * whose ENTRY value is an object because a primitive cannot be mutated in * place — every change to one is an assignment (1) already saw — and * confining it there is what keeps this leg from re-widening into the value - * diff #14099's ruling refused. [#14760] Normalising the entry side is what + * diff #14099's ruling refused. [commit ee32e1cb8] Normalising the entry side is what * makes the comparison answer "did the body write through this?" instead of * "is this host value already JSON?"; without it every `Date`-valued key * answered the second question, in the wrong direction, forever. @@ -603,7 +603,7 @@ function carriedInputKeys( * preserves insertion order for string keys but reorders integer-like ones, and * a reorder is not a write. * - * [#14760] BOTH sides are JSON values by the time they reach here: `b` is the + * [commit ee32e1cb8] BOTH sides are JSON values by the time they reach here: `b` is the * VM's exit dump, and `a` is the entry snapshot already put through * {@link jsonSeenByVm}. So this compares like for like, and it no longer stands * in for the round-trip itself. It used to: an unequal verdict meant either @@ -668,7 +668,7 @@ function sameJsonValue(a: unknown, b: unknown): boolean { * returns it (`delete ctx.input.x; return { x: 1 };`) keeps the explicit patch * — the return value is the later, more deliberate statement of the two. * - * ## [#14758] Why the merge is a KEY SET and no longer the whole dump + * ## [commit 84199cb87] Why the merge is a KEY SET and no longer the whole dump * * `mutatedInput` is the whole post-run `ctx.input`, so `Object.assign(target, * mutated)` re-asserted every key a body could see, touched or not. `target` is @@ -709,7 +709,7 @@ function sameJsonValue(a: unknown, b: unknown): boolean { * itself ever fires, so the recorder cannot list `meta`. The dump is the only * witness for those, and {@link carriedInputKeys} reads it the narrowest way * available: an OBJECT-valued entry key whose dumped value no longer matches - * the entry snapshot — [#14760] as {@link jsonSeenByVm} shows it to the VM — + * the entry snapshot — [commit ee32e1cb8] as {@link jsonSeenByVm} shows it to the VM — * was written through, and is carried. Primitives need no such leg: a * primitive cannot be mutated in place, so every change to one is an * assignment the recorder saw. @@ -732,7 +732,7 @@ function applyMutationsToInput( } const carried = carriedInputKeys(mutated, result.mutatedInputKeys, entryInput); if (carried === undefined) { - // The recorder could not speak — pre-#14758 behaviour, verbatim. + // The recorder could not speak — the behaviour before commit 84199cb87, verbatim. Object.assign(target, mutated); } else { for (const key of carried) { @@ -877,7 +877,7 @@ function buildSandboxContext( // reliably distinguish create (`!ctx.previous`) from update/delete. previous: unwrapProxyToPlain(previousRaw), // `engineCtx.user` is the ONLY source, and the `?? engineCtx?.session?.user` - // limb that used to follow it was removed in #6316 (same family as #5906 + // limb that used to follow it was removed in commit 448ac9565 (same family as #5906 // above, and as #4984): `HookContext['session']` declares no `user` key // (`packages/spec/src/data/hook.zod.ts`) and its sole producer — // ObjectQL's `buildSession()` (`packages/objectql/src/engine.ts`), which @@ -907,7 +907,7 @@ function buildSandboxContext( // dispatches for one write, and its params bag has no caller options. dispatch, inputOptions, - // [#13644] The declared referential-cleanup marker, carried across the + // [commit 34ce8e7db] The declared referential-cleanup marker, carried across the // sandbox boundary BY CONTRACT — copied only in its declared shape // (`true`), the same unrecognised-shape rule as `dispatch` above: anything // else is left ABSENT, so `ctx.referentialFieldClear === true` reads "not @@ -935,7 +935,7 @@ function buildActionSandboxContext( return { input: unwrapProxyToPlain(actionCtx?.params ?? {}), previous: undefined, - // Same removal as the hook face above (#6316), measured on this face's own + // Same removal as the hook face above (commit 448ac9565), measured on this face's own // shapes: `ActionSession` (`packages/spec/src/ui/action-params.zod.ts`) // declares `userId` / `organizationId` / `positions` / `roles` and no // `user`, and its sole producer `buildActionSession()` @@ -953,7 +953,7 @@ function buildActionSandboxContext( // downstream writes it back. `warnDiscardedRecordWrites` reports the writes // a body makes to it rather than letting them vanish. record: unwrapProxyToPlain(actionCtx?.record), - // [#14143] The caller-scope load's verdict, marshalled EXPLICITLY for the + // [commit f19475c0a] The caller-scope load's verdict, marshalled EXPLICITLY for the // same reason `dispatch` / `referentialFieldClear` are on the hook face: a // body cannot reach the dispatcher's locals, and `ctx.record.id` is stamped // even when the caller cannot read the row, so without this key an action diff --git a/packages/runtime/src/sandbox/error-passthrough.test.ts b/packages/runtime/src/sandbox/error-passthrough.test.ts index d37925095cc..458b6329d48 100644 --- a/packages/runtime/src/sandbox/error-passthrough.test.ts +++ b/packages/runtime/src/sandbox/error-passthrough.test.ts @@ -239,7 +239,7 @@ describe('[#7867] an error that names its own HTTP status keeps it across the bo }); /* ──────────────────────────────────────────────────────────────────────────── - * [#9934] `userMessage` — the fourth allowlisted property: the producer-side + * [commit 79c46da90] `userMessage` — the fourth allowlisted property: the producer-side * user-facing marking (objectui#5210 ruling). A sandboxed BODY is the authoring * surface the marking exists for, so the author's opt-in must survive the VM * flattening the throw to a string — in both directions, like the other three. diff --git a/packages/runtime/src/sandbox/hook-input-writeback-key-set.integration.test.ts b/packages/runtime/src/sandbox/hook-input-writeback-key-set.integration.test.ts index fc8bbdea5c4..8c9caf56bd9 100644 --- a/packages/runtime/src/sandbox/hook-input-writeback-key-set.integration.test.ts +++ b/packages/runtime/src/sandbox/hook-input-writeback-key-set.integration.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#14758] The sandbox write-back carries back the keys the BODY wrote — so + * [commit 84199cb87] The sandbox write-back carries back the keys the BODY wrote — so * #14099's per-row divergence refusal is true for shipped hook bodies too, in * either row order. * diff --git a/packages/runtime/src/sandbox/hook-input-writeback-readonly-provenance.integration.test.ts b/packages/runtime/src/sandbox/hook-input-writeback-readonly-provenance.integration.test.ts index f4ba6adf895..6a86924b164 100644 --- a/packages/runtime/src/sandbox/hook-input-writeback-readonly-provenance.integration.test.ts +++ b/packages/runtime/src/sandbox/hook-input-writeback-readonly-provenance.integration.test.ts @@ -1,12 +1,12 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#14760] A caller-supplied `readonly` field that no hook body ever names must + * [commit ee32e1cb8] A caller-supplied `readonly` field that no hook body ever names must * NOT survive `stripReadonlyFields` just because a sandboxed body ran. * * ## What was measured broken * - * #14758 narrowed the sandbox write-back to the keys the body wrote. Its leg 2 + * Commit 84199cb87 narrowed the sandbox write-back to the keys the body wrote. Its leg 2 * — "did the body write THROUGH this object-valued key?" — compared the HOST * entry snapshot against the VM's exit dump. The dump is JSON; the snapshot was * not. So a host `Date` was compared against its own ISO projection, could not @@ -376,8 +376,8 @@ describe('#14760 — an untouched readonly key is not laundered by the sandbox w // // ⚠️ That fault is a REFUSAL, not a silent no-op: a `body` hook's default // `onError` is `abort`, so the caller's whole write is rejected and the row - // is untouched. Loud beats silent — and #17219 supplied the second half the - // refusal was missing. Measured here before that card, through this very + // is untouched. Loud beats silent — and commit 706ad0fcc supplied the second half the + // refusal was missing. Measured here before that commit, through this very // harness, at both doors: // // direct SandboxError: hook 'guard_task_body' threw: @@ -391,7 +391,7 @@ describe('#14760 — an untouched readonly key is not laundered by the sandbox w // that can tell "the platform took this away" from "nobody sent it". // // ⛔ Still no `ctx.submitted` on the sandbox face: that face is assembled - // key by key and the shape was measured and refused in PR #17195. The + // key by key and the shape was measured and refused in commit d2c1d1980. The // supported source for a derived column is `ctx.previous`, which is what // the message now says. const { engine, driver } = await boot(WRITES_THROUGH_SOURCE); @@ -445,7 +445,7 @@ describe('#14760 — an untouched readonly key is not laundered by the sandbox w * - the SECOND harm — a carried key is re-asserted FROM THE DUMP, so an * untouched host `Date` used to be replaced by its ISO string and an object * used to lose its `undefined` member even where nothing was readonly; - * - the FAIL-OPEN, which #14758 chose deliberately and this card does not + * - the FAIL-OPEN, which commit 84199cb87 chose deliberately and this card does not * reverse. `safeJsonStringify` lets a cyclic or bigint-bearing value cross * into the VM in degraded form, so such a key IS in the exit dump and DOES * reach the comparison — where a plain round-trip of the host value throws. @@ -490,7 +490,7 @@ describe('#14760 — write-back fidelity and the preserved fail-open', () => { const fn = bind("ctx.input.touched_by = 'hook';"); // `safeJsonStringify` drops the back-edge on the way in, so the VM sees // `{ tag: 'cyclic' }` and dumps it — but a plain round-trip of the HOST - // value throws, which is exactly the case #14758's fail-open exists for. + // value throws, which is exactly the case commit 84199cb87's fail-open exists for. const cyclic: Record = { tag: 'cyclic' }; cyclic.self = cyclic; const engineCtx = { input: { status: 'done', meta: cyclic } } as any; @@ -499,7 +499,7 @@ describe('#14760 — write-back fidelity and the preserved fail-open', () => { expect(engineCtx.input.touched_by).toBe('hook'); // Carried: the host key now holds the dump's degraded copy, byte for byte - // the pre-#14760 behaviour for a value JSON cannot represent. + // the behaviour before commit ee32e1cb8 for a value JSON cannot represent. expect(Object.is(engineCtx.input.meta, cyclic)).toBe(false); expect(engineCtx.input.meta).toEqual({ tag: 'cyclic' }); }); diff --git a/packages/runtime/src/sandbox/nested-hook-refusal-is-a-rejection.test.ts b/packages/runtime/src/sandbox/nested-hook-refusal-is-a-rejection.test.ts index 976fac860e0..207f5f8cef2 100644 --- a/packages/runtime/src/sandbox/nested-hook-refusal-is-a-rejection.test.ts +++ b/packages/runtime/src/sandbox/nested-hook-refusal-is-a-rejection.test.ts @@ -172,7 +172,7 @@ describe('[#17265] a nested sandboxed hook refusal keeps its business message', // The fault branch dropped the whole `__errorInfo` payload, not just // `innerMessage`, so a hook declaring `{ status: 409, code: // 'RECORD_LOCKED' }` lost both and was flattened to 500. `/data` - // answers `declared ?? 400` for this producer (#9967); the action door + // answers `declared ?? 400` for this producer (commit 8f266f1cd); the action door // honours a declared status at its own first arm (#7867), so once the // classification is right the two agree without a second rule. const locked = () => { diff --git a/packages/runtime/src/sandbox/nested-write-real-sqlite.integration.test.ts b/packages/runtime/src/sandbox/nested-write-real-sqlite.integration.test.ts index 52f10dbe1ed..eb53d7f6b11 100644 --- a/packages/runtime/src/sandbox/nested-write-real-sqlite.integration.test.ts +++ b/packages/runtime/src/sandbox/nested-write-real-sqlite.integration.test.ts @@ -73,7 +73,7 @@ const ROLLUP_HOOK = { }; /** - * [#10629] This fixture provisions `expense_report` / `expense_line` and + * [commit 13a6cb4ad] This fixture provisions `expense_report` / `expense_line` and * nothing else, so the engine's own single-tenant probe * (`ObjectQL.probeInstallOrganizations`, memoised once per engine) reads a * `sys_organization` that was never created. That read is fail-soft by @@ -86,7 +86,7 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; describe('#1867 nested cross-object write — REAL SqlDriver (better-sqlite3, on-disk)', () => { let engine: ObjectQL | null = null; let dir: string | null = null; - /** [#10629] The expected-noise capture belonging to the latest {@link boot}. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest {@link boot}. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { @@ -98,7 +98,7 @@ describe('#1867 nested cross-object write — REAL SqlDriver (better-sqlite3, on async function boot() { dir = mkdtempSync(join(tmpdir(), 'os-nested-1867-')); const driver = new SqlDriver({ client: 'better-sqlite3', connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true }); - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); noise.captureDriver(driver); @@ -131,7 +131,7 @@ describe('#1867 nested cross-object write — REAL SqlDriver (better-sqlite3, on parent = (await e.find('expense_report', { where: { id: report.id } }))[0]; expect(parent.total_amount).toBe(175); - // ── [#10629] The capture is a PIN, not a mute. These two lines used to + // ── [commit 13a6cb4ad] The capture is a PIN, not a mute. These two lines used to // reach the shared `Test Core` log out of a PASSING test and were read // there as a real failure; they are withheld now and asserted here. If the // probe stops running, or `sys_organization` starts resolving, the log goes diff --git a/packages/runtime/src/sandbox/perrow-dispatch-signal.integration.test.ts b/packages/runtime/src/sandbox/perrow-dispatch-signal.integration.test.ts index 02a8bba425c..140ecf1f6c3 100644 --- a/packages/runtime/src/sandbox/perrow-dispatch-signal.integration.test.ts +++ b/packages/runtime/src/sandbox/perrow-dispatch-signal.integration.test.ts @@ -213,7 +213,7 @@ describe('#11552 — a shipped body observes the per-row dispatch signal and the // predicate write from inside a body. expect(single[0].optionsMulti).not.toBe(true); - // [#10629] Withheld-noise pin, same as the sibling real-SQLite harness. + // [commit 13a6cb4ad] Withheld-noise pin, same as the sibling real-SQLite harness. expect(noise?.silentChannels() ?? ['no capture was installed']).toEqual([]); }, 30000); }); diff --git a/packages/runtime/src/sandbox/quickjs-runner.ts b/packages/runtime/src/sandbox/quickjs-runner.ts index 3bec6358b00..aaefa344b37 100644 --- a/packages/runtime/src/sandbox/quickjs-runner.ts +++ b/packages/runtime/src/sandbox/quickjs-runner.ts @@ -420,7 +420,7 @@ export class QuickJSScriptRunner implements ScriptRunner { // Capture mutated ctx.input so the host can write through. const mutatedInput = readCtxInputJson(vm); // …and, on the hook path, WHICH of those keys the body actually - // wrote (#14758), so the write-back carries the body's own key set + // wrote (commit 84199cb87), so the write-back carries the body's own key set // rather than re-asserting the whole dump onto the engine's payload. const mutatedInputKeys = args.origin.kind === 'hook' ? readInputWritesJson(vm) : undefined; @@ -538,7 +538,7 @@ export class QuickJSScriptRunner implements ScriptRunner { if (ctx.result !== undefined) { setObjectJson(vm, ctxObj, 'result', ctx.result); } - // [#13644] The declared referential-cleanup marker — installed only in its + // [commit 34ce8e7db] The declared referential-cleanup marker — installed only in its // declared shape (`true`), absent otherwise, so a body reads // `ctx.referentialFieldClear === true` with the spec's own back-compatible // absence semantics. A plain boolean: no freeze/graft ceremony needed — @@ -547,7 +547,7 @@ export class QuickJSScriptRunner implements ScriptRunner { if (ctx.referentialFieldClear === true) { vm.setProp(ctxObj, 'referentialFieldClear', vm.true); } - // [#14143] The action face's caller-scope load verdict — same true-only + // [commit f19475c0a] The action face's caller-scope load verdict — same true-only // installation, same reason: a body reads `ctx.recordLoadDenied === true` // and an absent key means "nothing was refused". A plain boolean, so no // freeze/graft ceremony is needed (the write-back channel reads only @@ -878,7 +878,7 @@ export class QuickJSScriptRunner implements ScriptRunner { } sugar.value.dispose(); - // [#14758] The hook path's INPUT write-recorder — the instrument that lets + // [commit 84199cb87] The hook path's INPUT write-recorder — the instrument that lets // `applyMutationsToInput` carry back the keys the body wrote instead of // every key it could see. // @@ -1243,7 +1243,7 @@ function safeJsonStringify(v: unknown): string { * nothing downstream needed teaching; the number simply never arrived. A * number, like `code`, carries no host state. * - * [#9934] `userMessage` is the fourth member — the producer-side user-facing + * [commit 79c46da90] `userMessage` is the fourth member — the producer-side user-facing * marking (see `declaredUserMessage` in `@objectstack/types`). A hook or * action BODY is the authoring surface the marking exists for: an app author * writes `const e = new Error(msg); e.userMessage = msg; throw e`, and the @@ -1289,7 +1289,7 @@ function hostErrorToVm(vm: QuickJSContext, err: unknown): QuickJSHandle { vm.setProp(errH, 'status', h); h.dispose(); } - // [#9934] Non-empty strings only, same one-read rule as every other + // [commit 79c46da90] Non-empty strings only, same one-read rule as every other // boundary (`declaredUserMessage`): a blank or non-string value is not a // declaration and must not become one by crossing the VM. if (typeof e?.userMessage === 'string' && e.userMessage.trim().length > 0) { @@ -1532,7 +1532,7 @@ function readRecordWritesJson(vm: QuickJSContext): string[] | undefined { } /** - * [#14758] After the script has settled, dump the keys the write-recorder proxy + * [commit 84199cb87] After the script has settled, dump the keys the write-recorder proxy * saw on `ctx.input` — the keys the BODY assigned, defined or deleted, as * opposed to every key `readCtxInputJson` can see. * @@ -1619,7 +1619,7 @@ export class SandboxError extends Error { */ readonly status?: number; /** - * [#9934] The user-facing refusal text the error that crossed OUT of the VM + * [commit 79c46da90] The user-facing refusal text the error that crossed OUT of the VM * was marked with — the producer-side opt-in of the objectui#5210 ruling. A * body that throws `e.userMessage = '…'` is saying that exact text is * addressed to the END USER; the HTTP boundaries carry it to the wire's @@ -1645,7 +1645,7 @@ export interface SandboxErrorInfo { fields?: unknown[]; /** [#7867] See {@link SandboxError.status}. */ status?: number; - /** [#9934] See {@link SandboxError.userMessage}. */ + /** [commit 79c46da90] See {@link SandboxError.userMessage}. */ userMessage?: string; /** * [#4431] The error that crossed `__error` was the SANDBOX's own fault — a @@ -1686,7 +1686,7 @@ function readErrorInfo(vm: QuickJSContext): SandboxErrorInfo | undefined { // number JSON-round-trips to `null`, and `NaN` would satisfy `typeof` while // making `errorFromThrown` emit a nonsense status line. if (typeof p?.status === 'number' && Number.isFinite(p.status)) info.status = p.status; - // [#9934] Non-empty strings only — the same "what counts as marked" rule as + // [commit 79c46da90] Non-empty strings only — the same "what counts as marked" rule as // `declaredUserMessage` (`@objectstack/types`), applied at this boundary too. if (typeof p?.userMessage === 'string' && p.userMessage.trim().length > 0) info.userMessage = p.userMessage; if (p?.sandboxFault === true) info.sandboxFault = true; diff --git a/packages/runtime/src/sandbox/referential-field-clear-signal.integration.test.ts b/packages/runtime/src/sandbox/referential-field-clear-signal.integration.test.ts index e44768b052d..9f74662ad77 100644 --- a/packages/runtime/src/sandbox/referential-field-clear-signal.integration.test.ts +++ b/packages/runtime/src/sandbox/referential-field-clear-signal.integration.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * [#13644] The declared referential-cleanup marker, OBSERVED FROM INSIDE A + * [commit 34ce8e7db] The declared referential-cleanup marker, OBSERVED FROM INSIDE A * SHIPPED BODY — the sandbox-reachability mandate of the adoption ruling. * * ## What is pinned, and why a kernel rig could not pin it @@ -124,7 +124,7 @@ describe('#13644 — a shipped body observes ctx.referentialFieldClear across th body: { language: 'js', source: PROBE_SOURCE, capabilities: ['log'] }, } as any], { packageId: 'probe' }); - // The REST-shaped caller envelope — the corrected #13644 measurement's + // The REST-shaped caller envelope — the corrected measurement's (commit 34ce8e7db) // row 1, on which every other context member is identical between the // engine's cascade and the user's hand-clear. const CALLER = { userId: 'u_probe', isSystem: true }; @@ -169,7 +169,7 @@ describe('#13644 — a shipped body observes ctx.referentialFieldClear across th const cleared = (await engine.findOne('probe_rfc_note', { where: { id: n.id } })) as any; expect(cleared.account).toBeNull(); - // [#10629] Withheld-noise pin, same as the sibling harnesses. + // [commit 13a6cb4ad] Withheld-noise pin, same as the sibling harnesses. expect(noise?.silentChannels() ?? ['no capture was installed']).toEqual([]); }, 30000); }); diff --git a/packages/runtime/src/sandbox/script-runner.ts b/packages/runtime/src/sandbox/script-runner.ts index 2a92d9643b8..66e258cc7c2 100644 --- a/packages/runtime/src/sandbox/script-runner.ts +++ b/packages/runtime/src/sandbox/script-runner.ts @@ -96,7 +96,7 @@ export type ScriptSession = ActionSession | HookContext['session']; * `ActionSession`) and neither producer writes one (`buildSession()` in * objectql, `buildActionSession()` in `../action-execution.ts`) — and left it * alone, because typing a seam does not get to re-decide a runtime expression. - * #6316 re-ran that sweep across every producer on both faces, confirmed it, + * Commit 448ac9565 re-ran that sweep across every producer on both faces, confirmed it, * and deleted both limbs (the #4984 dead-limb family). So the union's arms are * the two REAL producer shapes and nothing else; if a session ever should * carry a user, DECLARE it on the session contract rather than restoring a @@ -224,7 +224,7 @@ export interface ScriptContext { dispatch?: { mode: 'record' | 'per-row'; index: number }; /** * The engine's referential-cleanup marker, marshalled for the HOOK face - * (#13644) — `true` exactly when this write is the engine's own reference + * (commit 34ce8e7db) — `true` exactly when this write is the engine's own reference * cleanup (the `set_null` cascade UPDATE clearing, or on a `multiple: true` * lookup member-removing, a lookup that references a record being deleted). * Mirrors the declared `HookContextSchema.referentialFieldClear` @@ -305,7 +305,7 @@ export interface ScriptContext { /** * Action only: `true` exactly when the dispatcher ATTEMPTED to load the * subject row in the CALLER's own scope and that load did not deliver it - * (#14143). Absent otherwise — including on every record-less / new-record + * (commit f19475c0a). Absent otherwise — including on every record-less / new-record * action, which never attempts a load — so read it as * `ctx.recordLoadDenied === true`, the same absence semantics as * {@link referentialFieldClear}. @@ -418,7 +418,7 @@ export interface ScriptResult { */ mutatedInput?: Record; /** - * [#14758] Hook path only: the keys of {@link mutatedInput} the BODY actually + * [commit 84199cb87] Hook path only: the keys of {@link mutatedInput} the BODY actually * assigned, defined or deleted — as opposed to every key the dump can see. * * `mutatedInput` alone cannot answer that question: it is the whole @@ -437,7 +437,7 @@ export interface ScriptResult { * nothing. * - `undefined` — this runner cannot say (no recorder installed, the runner * predates this field, the read failed). Carry back the whole dump, which - * is the pre-#14758 behaviour: narrowing on a key set that cannot speak + * is the behaviour before commit 84199cb87: narrowing on a key set that cannot speak * would silently drop a write the body really made. * * Keys reachable only THROUGH a value on `ctx.input` — `ctx.input.meta.x = 1` diff --git a/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts b/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts index ab96141e49a..6af053153b5 100644 --- a/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts +++ b/packages/runtime/src/sandbox/undeclared-field-write-driver-split.integration.test.ts @@ -21,7 +21,7 @@ * It neither rejects the unknown key nor strips it. * 3. `engine.ts` hands the row to `driver.create` / the driver's update. * - * ...and, until #13657, the driver decided — so the two families disagreed: + * ...and, until commit b003cf2e8, the driver decided — so the two families disagreed: * * • SQL — the stray column reached the statement and the WHOLE write failed. * Nothing was stored, and the error named a column, not a field, far from @@ -29,7 +29,7 @@ * • Schemaless (memory, and MongoDB on the same `...data` spread) — the key * WAS persisted, as an undeclared column nothing downstream reads. * - * [#13657] That divergence is CLOSED. The declared-field door now has a + * [commit b003cf2e8] That divergence is CLOSED. The declared-field door now has a * POST-hook half (`undeclaredWriteFieldErrors`, run again over the payload the * `before*` hooks produced, before any statement is built), so a body-written * undeclared key is refused by the object's FIELD MAP — `INVALID_FIELD` / 400, @@ -83,7 +83,7 @@ * sentences fail until they are rewritten — which is the half a sentence could * never do for itself (#6664, ruling C). * - * Why it has to stay — and the reason survives #13657 intact, one word over. + * Why it has to stay — and the reason survives commit b003cf2e8 intact, one word over. * This file used to pin a PRODUCT DIVERGENCE between two driver families * (rejected as a whole statement by SQL, accepted verbatim by the schemaless * family); it now pins the CONVERGENCE that replaced it. Either way the claim @@ -93,7 +93,7 @@ * behaves the same on the same `...data` spread, but would put a real database * in CI's path). Delete this arm and the guardrail silently becomes a one-sided * assertion about SQL — and "identical on every driver", the whole point of - * #13657, stops being pinned at all. ⚠️ If anything, the schemaless arm matters + * commit b003cf2e8, stops being pinned at all. ⚠️ If anything, the schemaless arm matters * MORE now: it is the family that used to accept the key, so it is the arm that * would witness a regression first. * @@ -220,9 +220,9 @@ const CORRECT_HOOK = { * The subject is unchanged and still measured on both families: a key a BODY * writes is added AFTER the PRE-hook door, so `applyMutationsToInput` → * `validateRecord`'s `if (!def) continue` is still intact and still proved - * here. [#13657] What it reaches is no longer the driver: the POST-hook half of + * here. [commit b003cf2e8] What it reaches is no longer the driver: the POST-hook half of * the door refuses it first, on both families. The caller-payload half has its - * own cases below, pinning the pre-hook door — which #13657 deliberately did + * own cases below, pinning the pre-hook door — which commit b003cf2e8 deliberately did * NOT move, since #8737 put it ahead of the hooks so a refused payload consumes * no autonumber. */ @@ -234,7 +234,7 @@ const UPDATE_TYPO_HOOK = { }; /** - * [#10629] The SQL half of this fixture provisions `deal` and nothing else, so + * [commit 13a6cb4ad] The SQL half of this fixture provisions `deal` and nothing else, so * the engine's single-tenant probe (`ObjectQL.probeInstallOrganizations`, * memoised once per engine) reads a `sys_organization` that was never created. * The probe is fail-soft by construction — it catches `isMissingTableError` and @@ -249,19 +249,19 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; describe('#4271 / #13657 an undeclared field written by an L2 body — one answer on both families', () => { let engine: ObjectQL | null = null; let dir: string | null = null; - /** [#10629] The expected-noise capture belonging to the latest boot. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest boot. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave the engine running. Unconditional on purpose: // a memory boot declares an EMPTY expectation, so this still fails loudly if // a boot ever forgets to install a capture at all. // - // [#13657] `required` is narrowed to nothing — the documented remedy for + // [commit b003cf2e8] `required` is narrowed to nothing — the documented remedy for // "a table read on only SOME of a file's paths", which is what // `sys_organization` became here. The single-tenant probe runs on the way // to the STATEMENT, and the post-hook door now refuses the body-written @@ -282,7 +282,7 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true, }); - // [#10629] Installed before the driver runs a statement — the sink the + // [commit 13a6cb4ad] Installed before the driver runs a statement — the sink the // expected refusal's first half travels out on. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); noise.captureDriver(driver); @@ -291,7 +291,7 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe } async function bootMemory(hook?: unknown) { - // [#10629] A schemaless driver never refuses a read on a missing table, so + // [commit 13a6cb4ad] A schemaless driver never refuses a read on a missing table, so // this family expects no noise at all — an EMPTY declaration rather than a // skipped one, which keeps the shared `afterEach` assertion honest. noise = captureExpectedReadRefusals([]); @@ -300,7 +300,7 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe async function boot(driver: unknown, hook?: unknown) { engine = new ObjectQL(); - // [#10629] The engine frame that sits directly above the driver's refusal. + // [commit 13a6cb4ad] The engine frame that sits directly above the driver's refusal. noise?.captureEngine(engine); engine.registerDriver(driver as any, true); await engine.init(); @@ -312,12 +312,12 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe return engine; } - // ─── [#13657] Both families, one answer ─────────────────────────────────── + // ─── [commit b003cf2e8] Both families, one answer ───────────────────────── /** - * [#13657] What this block used to pin, and why it does not any more. + * [commit b003cf2e8] What this block used to pin, and why it does not any more. * - * Until #13657 these were two arms because the runtime gave two answers to + * Until commit b003cf2e8 these were two arms because the runtime gave two answers to * one question. A key an L2 body wrote was added AFTER the declared-field * door (#8682 / #8738, moved ahead of the hooks by #8737), so nothing between * `applyMutationsToInput` and the driver judged it, and the DRIVER decided: @@ -331,7 +331,7 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe * name, one that field-level security can never gate. * * One app, one body, two meanings decided by which driver a deployment - * happened to run — and nothing in the app could tell which. #13657 added the + * happened to run — and nothing in the app could tell which. Commit b003cf2e8 added the * POST-hook half of the door, so the key is now refused by the object's FIELD * MAP before any statement is built. There is no driver left to disagree. * @@ -354,7 +354,7 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe const err: any = await e.insert('deal', { stage: 'open', amount: 10 }).catch((x: unknown) => x); - // The caller path's answer, on both families. Before #13657 this read + // The caller path's answer, on both families. Before commit b003cf2e8 this read // `code: 'SQLITE_ERROR', status: undefined` on SQL and no error at all on // memory. expect(err?.code).toBe('INVALID_FIELD'); @@ -479,7 +479,7 @@ describe('#4271 / #13657 an undeclared field written by an L2 body — one answe * from, and they are about DIFFERENT call shapes: * * • the L2 BODY block mutates `ctx.input`, which the engine folds into the - * CALLER's payload — refused by the POST-hook half of the door (#13657); + * CALLER's payload — refused by the POST-hook half of the door (commit b003cf2e8); * • the CALLER block hands the engine a payload directly — refused by the * PRE-hook half (#8682 / #8738). * diff --git a/packages/runtime/src/security/artifact-granted-permissions.test.ts b/packages/runtime/src/security/artifact-granted-permissions.test.ts index e2346356ad8..5304f9922bf 100644 --- a/packages/runtime/src/security/artifact-granted-permissions.test.ts +++ b/packages/runtime/src/security/artifact-granted-permissions.test.ts @@ -15,7 +15,7 @@ // through the binding record alone — the binding record is what this module // says it did, the enforcer is what actually happened. // -// ⛔ VERB DISCIPLINE (#17147). Every case here reads a permission BAG and +// ⛔ VERB DISCIPLINE (commit aaacf1d5c). Every case here reads a permission BAG and // asserts what it ANSWERS. None of them asserts that anything was refused, and // none of them could: nothing on this tree queries the registry these entries // land in — `SecurePluginContext` has no production construction site, and the diff --git a/packages/runtime/src/security/artifact-granted-permissions.ts b/packages/runtime/src/security/artifact-granted-permissions.ts index bf2cf9801c8..252a36a39e1 100644 --- a/packages/runtime/src/security/artifact-granted-permissions.ts +++ b/packages/runtime/src/security/artifact-granted-permissions.ts @@ -3,7 +3,7 @@ /** * The artifact→enforcer seam: bind the install-time GRANTED permission set an * environment artifact carries to the plugins that artifact materializes - * (ADR-0025 §3.5 step 2 / F4, #11333 option A phase 1). + * (ADR-0025 §3.5 step 2 / F4; option A phase 1, landed in commit ea4d16420). * * ## What this is the consumer half of * diff --git a/packages/runtime/src/security/resolve-execution-context.test.ts b/packages/runtime/src/security/resolve-execution-context.test.ts index d5895607b9b..c029f7f524f 100644 --- a/packages/runtime/src/security/resolve-execution-context.test.ts +++ b/packages/runtime/src/security/resolve-execution-context.test.ts @@ -13,7 +13,7 @@ import { hashApiKey } from './api-key.js'; * tests isolate the API-key verify path. */ /** - * [#10978] Enforce the caller's `limit`, the way a real driver does. + * [commit 4c9780c7a] Enforce the caller's `limit`, the way a real driver does. * * A double that matches `where` and returns every matched row cannot tell a read * bounded at 200 from the same read bounded at 1000, or from an unbounded one — @@ -741,7 +741,7 @@ describe('[#13906 decision 1 A, runtime door] the tenancy posture seam tells "ne }); // ------------------------------------------------------------------------- - // [#17114] The classification above is now `classifyAdmissionTenancyPosture` + // [commit 4af758d47] The classification above is now `classifyAdmissionTenancyPosture` // (`@objectstack/core`) rather than a hand-written copy of it — one of the // two seams #16013 left behind. The RESOLUTION stayed here: this facade's // `opts.getService` is handed in as the thunk. diff --git a/packages/runtime/src/security/resolve-execution-context.ts b/packages/runtime/src/security/resolve-execution-context.ts index 21dbf185c68..38358ad5349 100644 --- a/packages/runtime/src/security/resolve-execution-context.ts +++ b/packages/runtime/src/security/resolve-execution-context.ts @@ -19,7 +19,7 @@ * guest envelope (`{ isSystem: false, positions: [], permissions: [] }`) — * and throws `AuthzStoreUnavailableError` (503) for the one class of fault * that leaves the answer undetermined: an authorization INPUT that exists and - * could not be read (a permission-store read that failed, #13279; a `tenancy` + * could not be read (a permission-store read that failed, commit 6a180e42d; a `tenancy` * service that is registered and failed to build, #13906 decision 1 A). The * dispatcher's net (`HttpDispatcher.resolveRequestScope`) re-raises exactly * that class and degrades everything else to anonymous, as before. @@ -194,7 +194,7 @@ export async function resolveExecutionContext(opts: ResolveOptions): Promise { let dir: string | null = null; let engine: ObjectQL | null = null; - /** [#10629] The expected-noise capture belonging to the latest boot. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest boot. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave the engine running. The single test in this // file boots and writes, so the probe fires for it. expect(noise?.silentChannels() ?? ['no capture was installed']).toEqual([]); @@ -120,7 +120,7 @@ describe('[#8442] a REAL driver constraint violation is withheld from the seed r connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true, }); - // [#10629] Installed on the REAL driver (the one that logs) before it runs + // [commit 13a6cb4ad] Installed on the REAL driver (the one that logs) before it runs // a statement — the `Object.create(real)` wrapper below resolves `logger` // through the prototype chain to this sink. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); diff --git a/packages/runtime/src/seed-multi-value-lookup-real-driver.integration.test.ts b/packages/runtime/src/seed-multi-value-lookup-real-driver.integration.test.ts index 303c63e089e..4d5e23c5b89 100644 --- a/packages/runtime/src/seed-multi-value-lookup-real-driver.integration.test.ts +++ b/packages/runtime/src/seed-multi-value-lookup-real-driver.integration.test.ts @@ -64,7 +64,7 @@ const SEEDS = [ ]; /** - * [#10629] This fixture provisions the seeded business objects and nothing else, so the engine's + * [commit 13a6cb4ad] This fixture provisions the seeded business objects and nothing else, so the engine's * own single-tenant probe (`ObjectQL.probeInstallOrganizations`, memoised once * per engine) reads a `sys_organization` that was never created. The probe is * fail-soft by construction — it catches `isMissingTableError` and only that — @@ -76,14 +76,14 @@ const ABSENT_TENANCY_TABLE = 'sys_organization'; describe('multi-value lookup seeds on a REAL SqlDriver (framework#3911)', () => { let dir: string | null = null; let engine: ObjectQL | null = null; - /** [#10629] The expected-noise capture belonging to the latest boot. */ + /** [commit 13a6cb4ad] The expected-noise capture belonging to the latest boot. */ let noise: ExpectedReadRefusalCapture | null = null; afterEach(async () => { try { await engine?.destroy(); } catch { /* noop */ } engine = null; if (dir) { rmSync(dir, { recursive: true, force: true }); dir = null; } - // [#10629] The capture is a PIN, not a mute — asserted after teardown so a + // [commit 13a6cb4ad] The capture is a PIN, not a mute — asserted after teardown so a // failure here can never leave the engine running. Every test in this file // boots and writes, so the probe fires for each of them: this holds for a // single `-t` run as well as for the whole file. @@ -98,7 +98,7 @@ describe('multi-value lookup seeds on a REAL SqlDriver (framework#3911)', () => connection: { filename: join(dir, 'data.sqlite') }, useNullAsDefault: true, }); - // [#10629] Installed before the driver runs a statement and before the + // [commit 13a6cb4ad] Installed before the driver runs a statement and before the // engine issues a read — the two sinks the expected refusal travels out on. noise = captureExpectedReadRefusals([ABSENT_TENANCY_TABLE]); noise.captureDriver(driver); diff --git a/packages/runtime/src/seed-tenancy-autonumber-split.integration.test.ts b/packages/runtime/src/seed-tenancy-autonumber-split.integration.test.ts index 364727e8971..95ff7cb1d17 100644 --- a/packages/runtime/src/seed-tenancy-autonumber-split.integration.test.ts +++ b/packages/runtime/src/seed-tenancy-autonumber-split.integration.test.ts @@ -529,7 +529,7 @@ describe('#8686 seed/API tenancy split — autonumber scope', () => { expect(await readSequences(driver)).toEqual([{ tenant: GLOBAL_TENANT, lastValue: 3 }]); }); /** - * #10789 — PRESERVED-BEHAVIOUR control for the `absent`/`no-split` separation. + * Commit 38bc74ed1 — PRESERVED-BEHAVIOUR control for the `absent`/`no-split` separation. * * `backfillSeedTenancy` used to answer `no-split` over a seam it never * queried: a no-op `execute` returns `null`, `normalizeRows(null)` is `[]`, @@ -573,7 +573,7 @@ describe('#8686 seed/API tenancy split — autonumber scope', () => { expect(result.status).toBe('no-split'); expect(result.detail).toBeUndefined(); - // Nothing moved: the SQL path is untouched by #10789. + // Nothing moved: the SQL path is untouched by commit 38bc74ed1. expect(await readSequences(driver)).toEqual([{ tenant: ORG_ID, lastValue: 2 }]); expect(await countUntenanted(driver)).toBe(0); }); diff --git a/packages/runtime/src/standalone-stack-seeder-declaration-copy.test.ts b/packages/runtime/src/standalone-stack-seeder-declaration-copy.test.ts index bb5455b2844..a0aebe7c0a7 100644 --- a/packages/runtime/src/standalone-stack-seeder-declaration-copy.test.ts +++ b/packages/runtime/src/standalone-stack-seeder-declaration-copy.test.ts @@ -26,7 +26,7 @@ // 4. which copy wins in the persisted `sys_*` row. // // ⛔ This file changes NO production behaviour and asserts no repair. It is a -// divergence pin in the style of PR #14398's +// divergence pin in the style of commit 317132495's // `standalone-stack-security-registrar.test.ts`: one real boot, both copies // read at the same moment, key by key, beside the row that survived. // @@ -85,8 +85,8 @@ import '@objectstack/service-datasource'; /** * The probe artifact. `engines.protocol` sits one minor below the runtime spec - * so the door's ADR-0087 forward-conversion window is open — the same lever PR - * #14398's probe uses, and the reason the two copies can differ at all. + * so the door's ADR-0087 forward-conversion window is open — the same lever + * commit 317132495's probe uses, and the reason the two copies can differ at all. * * Each declaration isolates one axis of triage's question: * @@ -97,7 +97,7 @@ import '@objectstack/service-datasource'; * - `capabilities[0]` — no `scope`, so the door's schema default is observable * (triage question 3). * - `sharingRules[0]` `share_legacy_deals` — BOTH legacy spellings at once - * (`sharedWith.type: 'role'`, `accessLevel: 'full'`), the PR #14398 probe + * (`sharedWith.type: 'role'`, `accessLevel: 'full'`), the commit 317132495 probe * bytes. * - `sharingRules[1]` `share_legacy_level` — the legacy `accessLevel` ALONE, * over a recipient type the seeder accepts, so the `accessLevel` axis is not diff --git a/packages/runtime/src/standalone-stack.libsql.test.ts b/packages/runtime/src/standalone-stack.libsql.test.ts index 7f75ee884a5..da057411eb4 100644 --- a/packages/runtime/src/standalone-stack.libsql.test.ts +++ b/packages/runtime/src/standalone-stack.libsql.test.ts @@ -21,7 +21,7 @@ // // No test here touches a real Turso endpoint. Every loader-level case // substitutes the package through `importDriverPackage`; the whole-boot case in -// ③ has no such seam and stages absence with `vi.doMock` instead (#12943). +// ③ has no such seam and stages absence with `vi.doMock` instead (commit 090f2302e). // Both make the "package missing" arm testable in a workspace where the package // IS installed — which, since `@objectstack/driver-turso` became a declared // optional peer of this package, is now every workspace. @@ -294,7 +294,7 @@ describe('loadTursoDriverFactory — the OPTIONAL driver package, both ways (#58 // // ⭐ This case's old comment predicted its own future and was right: "Should the // package ever become a dependency of this one, this case turns red and names -// exactly why in this comment." #12943 declared `@objectstack/driver-turso` an +// exactly why in this comment." Commit 090f2302e declared `@objectstack/driver-turso` an // OPTIONAL PEER of `@objectstack/runtime` — install-time honesty for a // relationship the source already had, installing nothing for a consumer — and // pnpm LINKS an optional workspace peer. Measured on that change: the boot diff --git a/packages/runtime/src/standalone-stack.mysql.test.ts b/packages/runtime/src/standalone-stack.mysql.test.ts index 268e8146749..d3b87d2a9a4 100644 --- a/packages/runtime/src/standalone-stack.mysql.test.ts +++ b/packages/runtime/src/standalone-stack.mysql.test.ts @@ -1,6 +1,6 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. // -// #6265 — two halves of one defect family in `standalone-stack.ts`, pinned +// Commit cfb549db8 — two halves of one defect family in `standalone-stack.ts`, pinned // together because they close the same hole from opposite sides: a driver // selection this stack could not dispatch. // @@ -254,7 +254,7 @@ describe('the existing schemes are untouched (positive controls, #6265)', () => expect(resolveStandaloneDatabase({ databaseUrl: url }).driver).toBe(kind); }); - // #6220's e2e pins this exit path from the CLI end — the new mysql arm must + // Commit 83df2fd73's e2e pins this exit path from the CLI end — the new mysql arm must // not have turned the trailing throw into a catch-all. it('an unknown scheme still throws, and the message now lists mysql://', () => { expect(() => resolveStandaloneDatabase({ databaseUrl: 'wat://nope' })) diff --git a/packages/runtime/src/standalone-stack.ts b/packages/runtime/src/standalone-stack.ts index b10937d600c..97e7597b66c 100644 --- a/packages/runtime/src/standalone-stack.ts +++ b/packages/runtime/src/standalone-stack.ts @@ -24,7 +24,7 @@ * Unknown URL schemes throw — we never silently fall back to sqlite, since * that historically created bogus directories on disk (e.g. `mongodb:/`) * when an unsupported URL was treated as a file path. The SAME refusal now - * covers an unknown `OS_DATABASE_DRIVER` value (#6265): that env var used to be + * covers an unknown `OS_DATABASE_DRIVER` value (commit cfb549db8): that env var used to be * a bare `as` cast, so a typo — or `mysql` before this stack could dispatch it * — fell through the driver chain's trailing `else` into SQLite without a word. * @@ -42,7 +42,7 @@ * comes through here — refused it as an unsupported scheme. * * NOTE: `mysql://` is the same family with none of the optional-package weight - * (#6265). The CLI has classified it as `mysql` since forever + * (commit cfb549db8). The CLI has classified it as `mysql` since forever * (`inferDriverTypeFromUrl`), the SHARED factory has always been able to build * it (`kind === 'mysql'` → SqlDriver on `mysql2`), and only this file was * missing the arm — so one `OS_DATABASE_URL=mysql://…` booted under `os start` @@ -96,16 +96,16 @@ export function resolveObjectStackHome(): string { /** * The driver kinds a standalone boot can dispatch — the ONE list, and the only - * one (#6265), now shared with the CLI rather than merely singular here (#6345). + * one (commit cfb549db8), now shared with the CLI rather than merely singular here (commit e2798fab7). * * Three consumers read it and every one of them used to carry its own answer: * the `databaseDriver` config key (a zod enum that rejected loudly), the * `OS_DATABASE_DRIVER` env var (a bare `as` cast that validated nothing, so an * unknown value fell through the dispatch chain's trailing `else` into SQLite), - * and the `ResolvedDriverKind` union (a hand-written third copy). #6265 made + * and the `ResolvedDriverKind` union (a hand-written third copy). Commit cfb549db8 made * them one declaration. * - * What #6265 could not fix from inside this file is that the CLI had a FOURTH + * What commit cfb549db8 could not fix from inside this file is that the CLI had a FOURTH * answer. This enum listed canonical spellings only, while * `packages/cli/src/utils/storage-driver.ts` accepted `pg`, `mysql2`, `mongo`, * `libsql`, `wasm`, `sql`, `mingo`, … — measured on `main`, **10 of 21 spellings @@ -121,7 +121,7 @@ export const StandaloneDatabaseDriverSchema = z.enum(BUILTIN_DRIVER_IDS); /** * The `databaseDriver` CONFIG key's schema — an alias-accepting front door onto - * {@link StandaloneDatabaseDriverSchema} (#6345). + * {@link StandaloneDatabaseDriverSchema} (commit e2798fab7). * * `databaseDriver` and `OS_DATABASE_DRIVER` are two spellings of one decision, * so accepting `pg` from the environment and refusing it from a programmatic @@ -318,7 +318,7 @@ type ResolvedDriverKind = z.infer; function detectDriverFromUrl(dbUrl: string): ResolvedDriverKind { if (/^memory:\/\//i.test(dbUrl)) return 'memory'; if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return 'postgres'; - // MySQL / MariaDB (#6265). Character-for-character the regex the CLI uses + // MySQL / MariaDB (commit cfb549db8). Character-for-character the regex the CLI uses // (`utils/storage-driver.ts` `inferDriverTypeFromUrl`), for the same reason // the turso arm below copies its spellings: the two functions answer the // same question about the same `OS_DATABASE_URL`, so any divergence IS the @@ -354,7 +354,7 @@ function detectDriverFromUrl(dbUrl: string): ResolvedDriverKind { /** * The explicit driver selection for this boot, or `undefined` when none was made. * - * Two sources, ONE vocabulary (#6265). `cfg.databaseDriver` has always been + * Two sources, ONE vocabulary (commit cfb549db8). `cfg.databaseDriver` has always been * parsed by {@link StandaloneDatabaseDriverSchema}; `OS_DATABASE_DRIVER` was * `process.env.OS_DATABASE_DRIVER?.trim() as ResolvedDriverKind` — an assertion, * which checks nothing at runtime. An unknown value therefore reached the @@ -380,8 +380,8 @@ function resolveExplicitDriver( if (cfg.databaseDriver) return cfg.databaseDriver; const raw = process.env.OS_DATABASE_DRIVER?.trim(); if (!raw) return undefined; - // #6345: the ACCEPTED SPELLINGS are the spec table's selection aliases, not - // this file's canonical list. Lower-casing stays for the reason #6265 gave — + // Commit e2798fab7: the ACCEPTED SPELLINGS are the spec table's selection aliases, not + // this file's canonical list. Lower-casing stays for the reason commit cfb549db8 gave — // the CLI's reader of this same variable lower-cases — and is now redundant // with `resolveDatabaseDriverId`'s own normalization rather than the only // normalization there is. @@ -392,7 +392,7 @@ function resolveExplicitDriver( /** * Refuse a driver whose database lives somewhere this process cannot guess when - * nothing named where that is (#6345 fork 2). + * nothing named where that is (fork 2 of commit e2798fab7). * * The URL ladder always produces SOMETHING — its last rung is the unified * default file — so before this check a `postgres`/`mysql`/`mongodb`/`turso` @@ -502,7 +502,7 @@ function resolveArtifactPathInput(cfg: z.output { - // ⭐ STAGED absence since #12943. `@objectstack/driver-turso` is now an + // ⭐ STAGED absence since commit 090f2302e. `@objectstack/driver-turso` is now an // OPTIONAL PEER of `@objectstack/service-datasource` and of this package — // the honest install-time declaration of a relationship the source already // had. It installs nothing for a consumer, but pnpm LINKS an optional diff --git a/packages/runtime/src/turso-driver-factory.ts b/packages/runtime/src/turso-driver-factory.ts index fc73f767906..4649eeebb5a 100644 --- a/packages/runtime/src/turso-driver-factory.ts +++ b/packages/runtime/src/turso-driver-factory.ts @@ -1,7 +1,7 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. /** - * libSQL/Turso driver loading — the SINGLE owner for both hosts (#6268). + * libSQL/Turso driver loading — the SINGLE owner for both hosts (commit 68f5eccb1). * * `@objectstack/driver-turso` drags `@libsql/client` (native bindings included), * so it is an OPTIONAL install rather than a dependency. Neither host can @@ -25,14 +25,14 @@ * engine), and it is the ruling both halves landed under (#5602 / PR #5819 for * the CLI, #5820 for the standalone stack). * - * ## #6268 — why this module owns it, and what the hosts still own + * ## Commit 68f5eccb1 — why this module owns it, and what the hosts still own * - * Until #6268 this shape existed TWICE: here, and in + * Until commit 68f5eccb1 this shape existed TWICE: here, and in * `packages/cli/src/utils/storage-driver.ts`. They were kept equal by hand * because the dependency direction forbids the reverse import (cli → runtime, * never runtime → cli) and each of the two rulings that created them had a * single-package file face. Hand alignment had already started to fail — the CLI - * half moved onto `@objectstack/spec`'s shared driver vocabulary in #6345 while + * half moved onto `@objectstack/spec`'s shared driver vocabulary in commit e2798fab7 while * this half still carried a private `Set(['turso', 'libsql'])` — which is the * #3741 → #3758 shape: one decision, two implementations, one of them fixed. * @@ -42,7 +42,7 @@ * * - **{@link LoadTursoDriverFactoryOptions.importDriverPackage} — the module * resolution root.** `@objectstack/driver-turso` is an OPTIONAL PEER of - * `@objectstack/cli` and, since #12943, of `@objectstack/runtime` too. An + * `@objectstack/cli` and, since commit 090f2302e, of `@objectstack/runtime` too. An * optional peer NAMES the relationship and installs nothing, so the package * still sits in whichever tree the operator installed it into — and a bare * `import('@objectstack/driver-turso')` resolves from the node_modules tree @@ -55,7 +55,7 @@ * own root, for the standalone stack. * ⚠️ Inside THIS workspace pnpm links an optional peer, so the default thunk * resolves here. Every test covering the missing-package arm therefore stages - * the absence rather than relying on the layout to supply it (#12943). + * the absence rather than relying on the layout to supply it (commit 090f2302e). * - **{@link LoadTursoDriverFactoryOptions.missingUrlError} — the error TYPE * for a config with no url.** The CLI raises its own `UnsupportedDriverError` * (a CLI-only semantic: `serve.ts` re-throws it as a fatal boot error), which @@ -70,7 +70,7 @@ * * ## #7314 — and the THIRD loader, one layer down * - * #6268 converged the two HOST-injected loaders. It could not reach the + * Commit 68f5eccb1 converged the two HOST-injected loaders. It could not reach the * open-core one: `createDefaultDatasourceDriverFactory`'s `turso` arm in * `@objectstack/service-datasource`, which serves every door that is not a * host's `default` — a datasource created in Setup, `testConnection`, a declared @@ -136,7 +136,7 @@ export { TURSO_DRIVER_PACKAGE, TURSO_DRIVER_INSTALL_COMMAND, MissingDriverPackag * Resolved through `@objectstack/spec`'s shared driver table rather than a local * `Set`, so "which spellings mean libSQL" has ONE answer across the CLI, the * standalone stack, the open-core factory and the metadata gate. The private - * `Set(['turso', 'libsql'])` this replaced (#6268) happened to agree with the + * `Set(['turso', 'libsql'])` this replaced (commit 68f5eccb1) happened to agree with the * table on the day it was written — the table's `turso` row lists exactly those * two aliases — and would have silently stopped agreeing the moment a third * spelling was added on one side only. @@ -155,7 +155,7 @@ export interface LoadTursoDriverFactoryOptions { * * NOT merely a test seam: the specifier resolves from the node_modules tree of * whichever module evaluates the `import()`, and the package is an optional - * peer of BOTH `@objectstack/cli` and `@objectstack/runtime` (#12943) — a + * peer of BOTH `@objectstack/cli` and `@objectstack/runtime` (commit 090f2302e) — a * declaration that installs nothing, so which tree actually holds the package * is still decided by where the operator installed it. The CLI passes its own * thunk so its operators keep resolving the package they installed next to the @@ -173,7 +173,7 @@ export interface LoadTursoDriverFactoryOptions { * * Host-chosen because the TYPE is host semantics: the CLI raises its own * `UnsupportedDriverError`, which `serve.ts` re-throws as a fatal boot error - * and which by the #6268 ruling stays in the CLI. The MESSAGE is passed in + * and which by the ruling commit 68f5eccb1 landed stays in the CLI. The MESSAGE is passed in * from here, so the wording is still single-sourced. * * Defaults to the standalone stack's plain `Error` with its `[StandaloneStack]` @@ -203,7 +203,7 @@ export async function loadTursoDriverFactory( ): Promise { // `as any` on the specifier: the package is an OPTIONAL PEER of // `@objectstack/runtime`, never a dependency (that is what "optional" means - // here — #12943 declared the relationship, and an optional peer installs + // here — commit 090f2302e declared the relationship, and an optional peer installs // nothing), so the literal must not be type-resolved: a consumer who did not // install it must still compile. Same shape the shared factory uses for the // other optional drivers (`default-datasource-driver-factory.ts`). @@ -219,7 +219,7 @@ export async function loadTursoDriverFactory( driverType: 'turso', packageName: TURSO_DRIVER_PACKAGE, installCommand: TURSO_DRIVER_INSTALL_COMMAND, - // One wording for both hosts (#6268). It names BOTH consequences rather + // One wording for both hosts (commit 68f5eccb1). It names BOTH consequences rather // than picking one, because one message now answers a failed `os serve` // boot and a failed `os migrate` / embedded `createStandaloneStack` alike, // and an operator who is told only about the other host's symptom would