Skip to content

39 hook-ctx call sites across 14 test files still build ctx.input inline, so they keep the plain-object blind spot #1295 closed everywhere else #1298

Description

@hotlong

Filed by the repo:hotcrm PM seat from a measurement reported in PR #1297 (#1295). It is the residual half of that card, deliberately left outside its fence and reported rather than swept in.

The gap

#1295 routed test/helpers/hook-harness.ts's makeCtx through the engine's real wrapper (wrapDeclarativeHook), so a hook handler now receives the flat-record Proxy production hands it instead of a plain object. That closed the blind spot for every call site that goes through makeCtx.

39 call sites across 14 test files do not. They build a hook ctx inline:

const ctx = { event: 'beforeInsert', input, user: undefined, api: harness.api };

so input is a plain object and those assertions keep exactly the under-approximation #1295 removed.

file sites
test/hooks-runtime.test.ts 18
test/flow-scheduled.test.ts 2
test/forecast-period-boundary.test.ts 2
test/knowledge-deflection.test.ts 2
test/knowledge-feedback.test.ts 2
test/ownership-model.test.ts 2
action-sandbox · demo-staffing · forecast-period-end-boundary · priority-rank-parity · quote-accepted-lookups · quote-accepted-payment-terms · territory-seed-coverage 1 each

(test/case-assignment.test.ts's 4 were converted in PR #1297 — the two the card named plus their handler calls.)

Why it is worth doing rather than noting

This is the shape that produced #1133: fifteen delete statements were silent no-ops in production while the tests asserting them passed, because a plain object honours delete and the engine's Proxy does not. Those tests were not merely failing to catch the defect — they were certifying the opposite of production for as long as it existed.

⚠️ test/hooks-runtime.test.ts alone holds 18 of the 39, and it is a hooks-runtime file — the highest-density place in the repo for exactly the class of defect this shape hides.

The failure also generalises past delete: ownKeys ordering, getOwnPropertyDescriptor, has on an absent key, and the non-enumerable reserved keys all diverge between the two shapes, with the same green tests either way.

Direction

Most of these files carry a single local ctxFor-style builder, so the conversion is roughly one line per file — point the builder at makeCtx (or at the exported engineFlatInput) instead of an object literal.

⛔ Every assertion that changes verdict is a finding to READ, not noise to suppress. #1295 changed no verdict because PR #1294 had already retired the last live delete; these 39 may not be so lucky, and a red here is the instrument finally telling the truth. ⛔ Never weaken, skip or delete a test to get green — if a red is a genuine defect outside this card's scope, stop and report it.

⚠️ Note the one disclosed divergence in the new harness before relying on it: id is hoisted onto the wrapper by copy, so a record carrying id has it in both places and Object.keys lists it where a real per-row update dispatch would not. Approximate in the enumerable direction only — if a converted assertion trips on exactly that, it is the harness, not the hook.

Acceptance

  • All 39 sites build their ctx through the shared helper, or each exception is named with a measured reason.
  • ⚠️ A pin, or an existing gate extended, that makes a new inline plain-object ctx visible — otherwise the 40th call site re-opens this silently. test/hook-input-shape.test.ts is the natural home.

Refs #1295 · PR #1297 · #1133 · PR #1294 · objectstack#12277

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions