From 63549ad2adf4fc74334b9bad1e9571d40eef91f6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 21 Aug 2026 12:17:13 +0000 Subject: [PATCH] docs(runtime): repair six false API claims found by hand-auditing the README's unread call sites (#10368) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hand-adjudicated every call site in `packages/runtime/README.md` that `check:published-readme-exports` reports under its `NOT read:` line — receivers bound to free variables, parameters and globals, which neither the gate nor a human reader can type by looking. Population, derived from the gate's own `countUnreadCalls` over the same `publishedDocs()` it runs on: 30 sites on 17 receivers (the whole-repo line reads `NOT read: 120 ... on 72 receiver(s)`). Verdicts: 24 sites resolvable and correct, 5 genuinely unadjudicable (receiver is a reader-owned illustrative object with no type anywhere), 1 fabricated member — `reply.code(429)`, which is Fastify, against a package whose HTTP contract spells the step `IHttpResponse.status(code)`. Two further sites name a real member with the wrong call shape (`engine.update` / `engine.delete`), a defect class member-existence cannot see, and three defects outside the call population turned up in the same read (`res.statusCode`, `PluginContext.logger`, `PluginContext.getKernel`). `NOT read` moves 120 -> 119 calls and 72 -> 71 receivers: the `reply` receiver is gone, and `res.status` / `res.json` were already counted in this document. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt --- .../runtime-readme-unread-call-site-audit.md | 41 +++++++++++++++++++ packages/runtime/README.md | 17 ++++---- 2 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 .changeset/runtime-readme-unread-call-site-audit.md diff --git a/.changeset/runtime-readme-unread-call-site-audit.md b/.changeset/runtime-readme-unread-call-site-audit.md new file mode 100644 index 0000000000..73e8b53457 --- /dev/null +++ b/.changeset/runtime-readme-unread-call-site-audit.md @@ -0,0 +1,41 @@ +--- +"@objectstack/runtime": patch +--- + +Repair six false API claims in the published `@objectstack/runtime` README +(#10368). The README is in the package's `files` array, so it is the page npm +renders — a reader following it wrote code that could not compile. + +Found by hand-adjudicating every call site in that document that +`check:published-readme-exports` reports under `NOT read:` — receivers built +from free variables, parameters and globals, which neither the gate nor a human +reader can type by looking. 30 sites on 17 receivers were read; the repairs below +are what came out. + +- `engine.update('user', user.id, { name: 'Jane' })` → `engine.update('user', + { id: user.id, name: 'Jane' })`. `IDataEngine.update` is + `(objectName, data, options?)`; there is no `id` parameter. A by-id update is + identified by a truthy scalar `data.id` (or `options.where.id`) — the rule + `resolveEngineUpdateDispatch` in `@objectstack/metadata-core` defines. +- `engine.delete('user', user.id)` → `engine.delete('user', { where: { id: user.id } })`. + `IDataEngine.delete` is `(objectName, options?)`; the id belongs in + `options.where.id` (`assertEngineDeleteDispatch`). Passing it positionally + landed the id in the options bag. +- The **Interface Methods** bullet list restated both wrong signatures, so it is + corrected in the same edit — a repaired example beside a bullet list that still + contradicts it is not a repair. +- `reply.code(429).send({ retryAfterMs })` in the rate-limiting recipe → + `res.status(429).json({ retryAfterMs })`. `reply.code()` is Fastify; this + package's HTTP contract is `IHttpResponse`, which spells the step + `status(code)` and whose `send` takes `string | Uint8Array | ArrayBuffer`, not + an object. The `docs/HARDENING.md` recipe the same section links to already + answers 429 through the framework's own JSON responder. +- `status: res.statusCode` in the middleware example → dropped. + `IHttpResponse` has no `statusCode`; a response's status is observed through + `IHttpServer.afterResponse` (`HttpResponseObservation.status`), not read off + the response inside middleware. +- The `PluginContext` interface block declared `logger: Console` and + `getKernel?(): any`. The real contract (`@objectstack/core`) is + `logger: Logger` and a required `getKernel(): ObjectKernel`. + +Documentation only — no runtime, type or export change. diff --git a/packages/runtime/README.md b/packages/runtime/README.md index ef10e371ec..3e68de42cb 100644 --- a/packages/runtime/README.md +++ b/packages/runtime/README.md @@ -203,8 +203,8 @@ class MyBusinessPlugin implements Plugin { // CRUD operations - works with any data layer const user = await engine.insert('user', { name: 'John' }); const users = await engine.find('user', { filter: { active: true } }); - await engine.update('user', user.id, { name: 'Jane' }); - await engine.delete('user', user.id); + await engine.update('user', { id: user.id, name: 'Jane' }); + await engine.delete('user', { where: { id: user.id } }); } } ``` @@ -212,8 +212,10 @@ class MyBusinessPlugin implements Plugin { **Interface Methods:** - `insert(objectName, data)` - Create a record - `find(objectName, query?)` - Query records -- `update(objectName, id, data)` - Update a record -- `delete(objectName, id)` - Delete a record +- `update(objectName, data, options?)` - Update a record (one row when `data.id` is a + truthy scalar, or `options.where.id` is; `options.multi` for a bulk update) +- `delete(objectName, options?)` - Delete a record (`options.where.id` for one row, + `options.multi` for a bulk delete) ### ObjectKernel @@ -247,8 +249,8 @@ interface PluginContext { getService(name: string): T; hook(name: string, handler: Function): void; trigger(name: string, ...args: any[]): Promise; - logger: Console; - getKernel?(): any; + logger: Logger; + getKernel(): ObjectKernel; } ``` @@ -481,7 +483,6 @@ export class LoggingMiddleware implements Plugin { ctx.logger.info('Response', { method: req.method, path: req.path, - status: res.statusCode, duration }); }); @@ -607,7 +608,7 @@ import { RateLimiter, DEFAULT_RATE_LIMITS } from '@objectstack/runtime'; const limiter = new RateLimiter(DEFAULT_RATE_LIMITS.auth); const decision = limiter.consume(`ip:${ip}`); -if (!decision.allowed) reply.code(429).send({ retryAfterMs: decision.retryAfterMs }); +if (!decision.allowed) res.status(429).json({ retryAfterMs: decision.retryAfterMs }); ``` ### Observability (opt-in adapters)