You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0583520
Browse filesBrowse the repository at this point in the historyBrowse files
fix(objectql,spec)!: a hook's `handler` name resolves inside the hook's own package only (#21604)
7
+
8
+
Clause-②: yes (narrowing)
9
+
10
+
<!-- adr-0087: not-required (no-migration-prescription) no authorable key, spelling, export of a published release or stored shape moves: `HookSchema`'s shape is unchanged (only `HookSchema.handler`'s doc changes), so `objectstack migrate meta` has nothing to rewrite. What changes is which function a string `handler` may bind to at registration. Census of compositions relying on cross-package resolution by name, at the claim: zero in objectstack `examples/**` (15fe567c9c, whose only string `handler` is a job's), hotcrm (f24c196588) and objectos (7612ffebd1); this repository commits no `--artifact` runtime module; cloud is NOT MEASURED (unreachable from the claim's session). The other categories are closed on facts: both packages publish (not `unpublished`); no ADR-0087 id covers a binding rule (not `registered` / `already-registered`); and the change is runtime behaviour, not a declaration (not `runtime-interface-only` / `type-surface-only`). -->
11
+
12
+
**BREAKING**: a hook whose `handler` is a function NAME (the deprecated form, `handler: 'my_fn'`, with no `body`) now binds only to a function its own package holds. It used to fall back to the engine-wide function registry, which is keyed by bare name, so the hook could bind to a function another package registered under the same name and run that package's code on its own events.
13
+
14
+
-**Accepted before:** a string `handler` resolved against the functions handed to the hook's bind, then against every function any package had registered on the engine. A name found nowhere was skipped with a `warn`.
15
+
-**Accepted now:** a string `handler` resolves against the functions handed to the hook's bind (the package's `functions`, which an `--artifact` runtime module supplies), then against the functions the same package (`packageId`) registered on the engine. Nothing else.
16
+
-**Refused now, at registration:** a name the hook's own package does not hold, whether another package registered it or nobody did. The hook is not bound. The refusal carries `INVALID_REFERENCE` with status `400` (ADR-0112), names the hook, the function and the package, and is recorded on the bind result (`BindHooksResult.errors[]` gains `code` and `status`) and logged at `error`. Under `strict` (`OBJECTQL_STRICT_HOOKS=1`) it is thrown.
17
+
-**The doors:** a hook authored at runtime through the metadata API (`PUT /api/v1/meta/hook/:name`) ships with no code package and holds no functions, so a `handler`-only hook authored there is refused when the door binds it; the save itself still answers as before. In a composition of several apps, one app's hook can no longer bind to another app's function. A bind that names no owning package (direct `bindHooksToEngine` use without `packageId`) resolves only the functions handed to it.
18
+
-**Unchanged:** a hook with a `body` binds as before. An app's hook naming its own `defineStack({ functions })` entry, or a function its own `--artifact` runtime module exports, binds as before. The install-local door's refusal of a hook with no `body` is unchanged.
19
+
20
+
What to do with a refused hook: give it a `body` (sandboxed JS), or declare the function in the hook's own package's `functions`. To reuse another package's function, import it from the package that owns it and declare it there. This ships as `minor`, under the launch-window convention for narrowings of an accept set.
`os migrate value-shapes` and `os migrate files-to-references` record the deployment-level ADR-0104 flag only from a run over every object, and every command in the `os migrate` data-migration family refuses an `--object` name the deployment does not declare (#21644).
7
+
8
+
Clause-②: no
9
+
10
+
-**A narrowed `--apply` records no deployment flag.** The flag attests the stored data of every object and turns strict enforcement on, but a run narrowed by `--object` reads only the named objects. Such a run still applies its fixes: `files-to-references` converts the named objects' values. It records no flag, whether it passes or fails, and leaves a flag that an earlier full-scope run recorded exactly as it was. Its output says why and names the run that records the flag: the same command without `--object`. The `--json` document carries `filter: { objects }`, which is `null` on a full-scope run, so a narrowed run is never mistaken for a full one. Any `--object` narrows, even a list that names every object. A full-scope `--apply` records the flag as before.
11
+
-**`runFilesToReferencesMigration`** (`@objectstack/service-storage`) skips the flag write when it is given `objects`. That includes `[]`, which walks nothing. Its `flag` result is `null` on a narrowed run.
12
+
-**The column step of `files-to-references` does not run on a narrowed run.** It retypes every single-value media column in the database on the authority of the gate, and a narrowed gate vouches only for the named objects. Before this change, a narrowed `--apply` or a misspelled one moved those columns and stamped `columns_moved_at`.
13
+
-**An unknown `--object` is an error.** This applies to `value-shapes`, `files-to-references`, `summary-nulls` and `duplicates`. A name the booted registry does not declare exits 1 with `OBJECT_NOT_FOUND`, and the error names that name and the declared objects. The check runs before anything is read or written. Until now, such a name was filtered out of the scan without a word, so a typo scanned nothing and read as a clean run. `duplicates` reports the refusal as `{ error: 'report_failed', detail, code }`. A declared object that the command has nothing to check on is still accepted.
A seed row's authored `created_at` is kept when the row is first inserted, the same as when a later boot replays it (#21646).
6
+
7
+
Clause-②: no
8
+
9
+
-**Before.** The built-in audit stamp (`sys_stamp_audit_insert`) replaced a seed row's authored `created_at` with the boot instant on insert. A later boot's upsert update then wrote the authored value, so a fresh or reset database showed every seeded record as created at boot until the next restart. This held for a literal instant and for a `cel` value such as ``cel`daysAgo(5)` ``.
10
+
-**After.** Under the seed write context (`ExecutionContext.seedReplay`, set by `SEED_WRITE_EXECUTION_CONTEXT`), the insert stamp keeps an authored `created_at` and stamps the boot instant only when the row has none. Both paths now store the authored value. The update stamp is unchanged, so `updated_at` still moves on a replay. All three seed writers pass that context: `SeedLoaderService`, `AppPlugin`'s replay of a stack's `data[]`, and `@objectstack/verify`'s `seed()`.
11
+
-**Unchanged.** A REST create, a create from a bare `isSystem` context and every other caller still have `created_at` stamped now. `preserveAudit` is unchanged, and the seed context does not gain it. A non-system create that requests `preserveAudit` gets the same warning as before. `created_by` is not stamped on a seed write, because the seed context has no user. An authored value is kept on insert and on replay, as it was before this change.
12
+
- ⛔ No schema, key, export or error code is added or removed.
0 commit comments