Skip to content

Commit 920cecf

Browse files
committed
wip(objectql): temporary measurement probe for undeclared row keys
Env-gated recorder (OS_PROBE_21571_OUT) at the engine's read sites and the by-id update result. Reverted before the fix lands. Claude-Session: https://claude.ai/code/session_017ErfyP2Rx7XWHJA27QjyUi Co-authored-by: Claude <noreply@anthropic.com>
1 parent a7ab047 commit 920cecf

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

‎packages/objectql/src/engine.ts‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,42 @@ import { readonlyWhenFkJudgementReadsParent } from './validation/rule-validator.
287287
// total over the MASTER's declared fields before it leaves this engine — the
288288
// same helper every other server seam materialises with (#1871/#4649/#4953).
289289
import { materializeDeclaredFields } from './declared-fields.js';
290+
291+
// ---- [#21571 MEASUREMENT PROBE — temporary, reverted before the fix] ----
292+
// Records every row a driver hands the engine that carries a key the object's
293+
// field map (plus id/created_at/updated_at) does not know. OS_PROBE_21571_OUT
294+
// names the JSONL sink; OS_PROBE_21571_TRIM=1 also deletes those keys.
295+
import { appendFileSync as __probe21571Append } from 'node:fs';
296+
function __probe21571(site: string, object: string, schema: any, rows: unknown): void {
297+
const out = typeof process !== 'undefined' ? process.env.OS_PROBE_21571_OUT : undefined;
298+
if (!out) return;
299+
const fields = schema?.fields;
300+
if (!fields || typeof fields !== 'object' || Array.isArray(fields)) return;
301+
const known = new Set(Object.keys(fields));
302+
if (known.size === 0) return;
303+
known.add('id'); known.add('created_at'); known.add('updated_at');
304+
const list = Array.isArray(rows) ? rows : rows ? [rows] : [];
305+
const extra = new Set<string>();
306+
for (const r of list) {
307+
if (!r || typeof r !== 'object' || Array.isArray(r)) continue;
308+
for (const k of Object.keys(r as object)) if (!known.has(k)) extra.add(k);
309+
}
310+
if (extra.size === 0) return;
311+
const frames = String(new Error().stack ?? '').split('\n').slice(2)
312+
.map((l) => l.trim())
313+
.filter((l) => !l.includes('objectql/src/engine.ts') && !l.includes('objectql/dist/') && !l.includes('node_modules') && !l.includes('node:'))
314+
.slice(0, 6);
315+
try {
316+
__probe21571Append(out, JSON.stringify({ site, object, extra: [...extra], frames }) + '\n');
317+
} catch { /* probe only */ }
318+
if (process.env.OS_PROBE_21571_TRIM === '1') {
319+
for (const r of list) {
320+
if (!r || typeof r !== 'object') continue;
321+
for (const k of extra) delete (r as Record<string, unknown>)[k];
322+
}
323+
}
324+
}
325+
// ---- [/#21571 MEASUREMENT PROBE] ----
290326
import { applyInMemoryAggregation } from './in-memory-aggregation.js';
291327
import {
292328
resolveEngineDeleteDispatch,
@@ -11910,6 +11946,7 @@ export class ObjectQL implements IObjectQLEngine {
1191011946

1191111947
try {
1191211948
let result = await driver.find(object, hookContext.input.ast as QueryAST, hookContext.input.options as any);
11949+
__probe21571('find', object, _findSchema, result);
1191311950

1191411951
// Post-process: evaluate formula virtual fields against the raw rows.
1191511952
// [#20082] With the caller's permission map when a formula calls
@@ -12186,6 +12223,7 @@ export class ObjectQL implements IObjectQLEngine {
1218612223
hookContext.input.options = this.buildDriverOptions(objectName, opCtx.context, hookContext.input.options as any);
1218712224

1218812225
let result = await driver.findOne(objectName, hookContext.input.ast as QueryAST, hookContext.input.options as any);
12226+
__probe21571('findOne', objectName, _findOneSchema, result);
1218912227

1219012228
// Post-process: evaluate formula virtual fields against the raw row
1219112229
// ([#20082] with the caller's permission map when a formula calls `can`).
@@ -14387,6 +14425,7 @@ export class ObjectQL implements IObjectQLEngine {
1438714425
const priorAst: QueryAST = { object, where: { id }, limit: 1 };
1438814426
const preOpts = this.buildDriverOptions(object, opCtx.context, hookContext.input.options as any);
1438914427
priorRecord = await driver.findOne(object, priorAst, preOpts);
14428+
__probe21571('update-prior', object, this._registry.getObject(object), priorRecord);
1439014429
// ── [#7867] The not-found gate ──────────────────────────────────
1439114430
//
1439214431
// A by-id update whose id names no row was a SILENT NO-OP that
@@ -14510,6 +14549,7 @@ export class ObjectQL implements IObjectQLEngine {
1451014549
if (!priorRowsRead) {
1451114550
priorRowsRead = true;
1451214551
priorRows = (await driver.find(object, ast, preOpts) as Record<string, unknown>[]) ?? [];
14552+
__probe21571('updateMany-prior', object, this._registry.getObject(object), priorRows);
1451314553
}
1451414554
return priorRows;
1451514555
};
@@ -15032,6 +15072,7 @@ export class ObjectQL implements IObjectQLEngine {
1503215072
// call inside a hook to THIS object.
1503315073
try {
1503415074
result = await driver.update(object, hookContext.input.id as string, hookContext.input.data as Record<string, unknown>, hookContext.input.options as any);
15075+
__probe21571('update-result', object, this._registry.getObject(object), result);
1503515076
} catch (driverError) {
1503615077
throw envelopeUniqueViolation(driverError, object);
1503715078
}
@@ -16832,6 +16873,7 @@ export class ObjectQL implements IObjectQLEngine {
1683216873
if (perRowBeforeHooks || perRowAfterHooks) {
1683316874
const preOpts = this.buildDriverOptions(object, opCtx.context, hookContext.input.options as any);
1683416875
const doomed = (await driver.find(object, ast, preOpts) as Record<string, unknown>[]) ?? [];
16876+
__probe21571('deleteMany-prior', object, this._registry.getObject(object), doomed);
1683516877
// [D6] One ceiling, both phases, BEFORE the first per-row dispatch
1683616878
// and before the driver call.
1683716879
this.assertBulkPerRowHookBudget(

0 commit comments

Comments
 (0)