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 c333daf
Browse filesBrowse the repository at this point in the historyBrowse files
fix(runtime): every PUT and PATCH route the dispatcher mounts answers with an `X-Request-Id` and reports its 5xx to the error reporter, as its GET, POST and DELETE routes always did
6
+
7
+
Clause-②: no
8
+
9
+
The dispatcher wraps each route it mounts in its observability instrumentation. That wrapper echoes a valid inbound `X-Request-Id` (and mints a `req_`-prefixed hex id otherwise), sets `req.requestId`, hands a 5xx to the configured `observability.errorReporter`, and gives the `[5xx]` log line its method, route and request id. It wrapped routes registered through `get`, `post` and `delete` only, so every route mounted through `put` or `patch` answered without any of that: `PUT` and `PATCH /api/v1/keys`, the `PUT` and `PATCH` mounts of the three `/notifications` paths, `PATCH /packages/:id` (and its `/enable` and `/disable`), `PUT /automation/:name`, the `PUT` and `PATCH /ai/*` wildcards, and PATCH routes a service emits on `ai:routes`. It now wraps all five verbs.
10
+
11
+
-**On the wire:** a `PUT` or `PATCH` answer from these routes now carries the `X-Request-Id` header (or the header `observability.requestIdHeader` names), as "Debugging with Request IDs" in the error-handling guide describes.
12
+
-**For an operator:** a 5xx on one of these routes now reaches `observability.errorReporter`, and its `[5xx]` log line now carries the method, route and request id.
13
+
-**Metrics:** on the standalone Hono server nothing changes. The transport already counted and timed these requests through `afterResponse`, and it still does, once per request. On a transport without `afterResponse`, `PUT` and `PATCH` requests on these routes are now counted in `http_requests_total` and timed in `http_request_duration_ms`, as the other three verbs were.
fix(plugin-audit): a read of the activity stream, the compliance ledger or comments that names its parent objects writes one parent-record branch per named object, not one per registered object
8
+
9
+
-**What changed.** The parent-record read gate on `sys_activity`, `sys_audit_log` and `sys_comment` ANDs one branch per parent object into every read: a `ReadableIds` leaf, or the bounded probe for an on-behalf-of caller, a middleware-narrowed parent or a parent on another datasource. It wrote one for every registered object, whatever the read asked for. When the read's own `where` names the objects its rows are about (`object_name` as a plain value, `$eq` or `$in` of machine names, at the top level or inside a top-level `$and`), the gate now writes branches for those objects only, and the bounded probe pre-scans only the named objects of its classes, or does not run. The activity stream's withheld-update rule, which wrote one branch per enumerated object too, narrows the same way.
10
+
-**What it costs now.** Measured on SQLite with 148 registered objects: a newest-first 20-row activity read filtered to 3 objects went from a 711.8 KB statement with 2,629 bindings to 14.9 KB with 60, for the rows and again for the total, and its two probe pre-scans no longer run.
11
+
-**Unchanged:** the rows, the totals and the grouped counts every reader is served. A read of any other shape (no `object_name` filter, an `$or`, a `$not`, another operator, a value that is not a machine name) keeps every branch, as before. No export, option or stored shape changes.
12
+
-**One failure mode is gone:** a leaf or a probe for an object the read does not name is no longer composed or run, so a refusal composing it, or a failing pre-scan for it, no longer fails or denies that read.
fix(cloud-connection): an install-local uninstall takes the package's objects out of `GET /api/v1/meta/object` and `GET /api/v1/meta/object/NAME` at once, not at the next restart
8
+
9
+
-**What was wrong.** An install-local install registers the package through the `manifest` service, and that register does two things: it puts the package in the engine's registry, and it copies each of the package's objects into the `metadata` service, stamped with the package's id. `DELETE /api/v1/marketplace/install-local/:manifestId` withdrew the registry half only. The object listing merges the `metadata` service into its answer and the by-name read asks that service first, so both kept serving every object of the uninstalled package, with its `_packageId`, until the runtime restarted, while `GET /api/v1/data/OBJECT` already answered `404`. The console's object pickers and Studio's object list offered objects that no longer existed.
10
+
-**What changes.** Right after the registry withdrawal, the DELETE removes from the `metadata` service each object copy stamped with the package's id whose name the registry no longer serves. The object listing and the by-name read stop serving the package's objects in the same process, as its data route, `GET /api/v1/meta/app` and `GET /api/v1/meta/permission` already did.
11
+
-**Not touched.** A same-name object the package did not copy there (one without its stamp) stays. The package's tables and rows are untouched, as before. A refused registry withdrawal still leaves the whole package loaded until the next restart, its copies included.
12
+
-**A copy the service refuses to remove** is reported on the DELETE answer as a failed `cleanups` entry named `metadata.unregister`, the way a refused registry withdrawal is reported, and the operator log names the objects kept and the remedy: restart the runtime. The uninstall cleanups still run, and the answer is still `200`. When nothing is refused, `cleanups` is unchanged.
fix(rest)!: a schema-derived export skips the fields declared `hidden`, so the hidden `__search` search companion no longer adds an empty "Search Index" column
6
+
7
+
Clause-②: no (narrowing)
8
+
9
+
<!-- adr-0087: not-required (no-migration-prescription) a runtime column-selection narrowing at the REST export door, not a metadata change: no spec key, export, option, config field or stored shape is removed, renamed or re-shaped, so `objectstack migrate meta` has nothing to rewrite; an explicit `?fields=` request is answered exactly as before -->
10
+
11
+
**BREAKING** (a served-set narrowing), shipped as `minor` under the launch-window convention for breaking changes.
12
+
13
+
`GET /api/v1/data/:object/export` without `?fields=` builds its columns from the object schema. It took every field of the object, so the hidden `__search` companion, which the search-normalization seam declares on every object with an eligible name field whenever pinyin search is on, and whose value the data reads strip from every row, became a "Search Index" column that was empty on every row. The default columns are now the fields the object shows by default: a field declared `hidden` (`FieldSchema.hidden`, "Hidden from default UI") is not one.
14
+
15
+
-**Served less now:** the CSV and XLSX default header, and its zero-row header, no longer carry a column for a field declared `hidden`. Measured on a dev boot of `examples/app-showcase`, over every object with a hidden field that the export serves: `Search Index` (`__search`, 64 objects, empty on every row), `Organization` (`organization_id`, 53 objects, the one that carries a value: the record's organization), `Owning Business Unit` (`owning_business_unit_id`, 24 objects, empty on every row because nothing stamps it yet), and `Session Token` (`sys_session`), `Previous Password Hashes` (`sys_account`) and `Hashed Key` (`sys_api_key`), all three empty because the read omits their values. No other column moved.
16
+
-**Unchanged:** an explicit `?fields=` list is answered as asked, a hidden field included: the header names it and its cells carry what the read returns (empty for `__search`, which the read strips). The field-level-security narrowing of the default columns is unchanged, and so are the zero-row header rules. `format=json` streams each row as the read returns it, has no column set, and is unchanged. `?template=true` keeps its own column rule.
17
+
18
+
What changes for you: a consumer that wants a hidden field's column in an export names the field in `?fields=`.
feat(spec)!: `record:json` is retired — refused by name at the schema door; the approval request page's raw JSON panel it was declared for was dropped (#24162, ADR-0049)
**BREAKING** — an accept-set narrowing on a published authoring surface, shipped as `minor` under the repo's launch-window convention for accept-set narrowings (the `user:profile`, `element:filter`, `element:form` and `ai:chat_window` retirements shipped the same way).
12
+
13
+
`record:json` was added to `PageComponentType` in `18.0.0-next.3`, with a strict `ComponentPropsMap` row, `RecordJsonProps` (`field`, `label`, `requiredPermissions`). It was declared spec first for one face: the approval request page's raw JSON panel. The maintainer then dropped that panel — the person deciding an approval has no business need to read the request as JSON — so no renderer was built and no page placed the type: zero consumers in objectstack and objectui, and its one planned producer was closed unmerged. A declared element that nothing draws is a capability claim nothing keeps, so it is retired under ADR-0049 enforce-or-remove, refused by name, the `ai:chat_window` way. The `18.0.0-next.3` entry below records what that prerelease shipped; this entry is its retirement.
14
+
15
+
**What is refused:** an authored `record:json` component node, at `PageComponentSchema.type`. That covers `definePage()`, `PageSchema`, and every door that parses pages: `os validate`, `os build`, `os lint` and the metadata save door. The issue is located at the node's own path, with `code: 'custom'` and `params.retiredComponentType`, and its message is the retirement prescription. `PageComponentType`'s own error map refuses the name with the same text when the enum is parsed alone. `ComponentPropsMap['record:json']` stays as a row, so every reader that dispatches on it keeps recognising the name: the component-props gate, `check-yaml-examples` and the type vocabulary's known set. The row now refuses every props bag, `{}` included, with the same prescription. One prescription string, `RETIRED_PAGE_COMPONENT_TYPES` in `@objectstack/spec/ui`, answers at all three doors. The authoring rule `component-type-unknown` reports the node by name, and stops suggesting `record:json` for a misspelling in the `record:` namespace.
16
+
17
+
**What is removed from the exports:**`RecordJsonProps` (`@objectstack/spec/ui`), the props schema the element no longer has. Its JSON Schema (`ui/RecordJsonProps`) is no longer published. Its print classification row (`PRINT_REFUSED_PAGE_COMPONENT_TYPES`) leaves with it: a retired type is refused at the parse before any print rule reads it.
18
+
19
+
**What stays accepted:** every other member of `PageComponentType` and `ComponentPropsMap`, byte-identically, including the four record blocks' own `requiredPermissions` gate, which `record:json` never changed. The open string arm also stays open: custom and plugin-registered types keep parsing. The only string refused is the retired name itself.
20
+
21
+
## FROM → TO
22
+
23
+
| you wrote | write instead |
24
+
|:--|:--|
25
+
| a `{ type: 'record:json' }` component node in a page region, slot or container | nothing: delete the node. No replacement panel exists, by ruling |
26
+
|`properties: { field, label, requiredPermissions }` on that node | nothing: none of them was ever read |
27
+
28
+
The one-line fix: delete the `record:json` component node. No ADR-0087 conversion is registered, because the only edit is deleting an authored page node, and a mechanical conversion does not delete page nodes: which region closes up is a layout decision. The D3 entry `ui-record-json-retired` carries that delegation, so `os migrate meta --from 17` lists it as a manual change for every stack that still names the type.
29
+
30
+
## Who is affected, measured
31
+
32
+
-**objectstack** at `eda6f14b7b`: zero authored `record:json` nodes in `examples/**`, `packages/apps/**`, `apps/**`, `skills/**` and `content/docs/**` code samples. The only hits were the spec's own type list, row and print row, its tests, the lint accept pin and the generated reference docs. A tree-scoped absence pin now holds that zero.
33
+
-**objectui**`main`: zero hits (the card's census); the `.objectui-sha` pin is not moved.
34
+
-**Deployed metadata** was not measured; the type was published in one prerelease only.
35
+
36
+
The retirement kit:
37
+
38
+
- the retired-type map entry and the enum value removed (`packages/spec/src/ui/page.zod.ts`), its print classification row removed, and the row turned into a whole-bag refusal, with `RecordJsonProps` removed (`packages/spec/src/ui/component.zod.ts`)
39
+
- the D3 semantic entry `ui-record-json-retired`, its step-18 rationale fragment, and the `RETIRED_DEFS_BY_MAJOR` entry `ui/RecordJsonProps`
40
+
- pin tests: `component-record-json-retirement.test.ts` pins `code`, `path`, `params` and the first sentence at each door (the map, the row with empty and populated bags, `PageComponentSchema`, `PageSchema` at the element path, the enum error map), with `record:approvals` as the live control, plus a tree-scoped absence walk; `component-type-vocabulary.test.ts` pins the type known, out of the typo candidates, and `record:` still reserved; the lint accept pin `validate-record-json-23745.test.ts` is flipped into a refusal pin at both lint rules and the shared pipeline
41
+
- generated baselines and docs follow the schema: `api-surface/`, `export-origins/`, `declaration-map/`, `authorable-surface/`, `json-schema.manifest/`, the strictness-ledger counts, `spec-changes.json`, the upgrade guide and the reference docs
0 commit comments