Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/console-088e0f705520.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@objectstack/console": minor
---

Console (objectui) refreshed to `088e0f705520`. Frontend changes in this range:

Derived from the changesets objectui declared over the range — 3 releasing of 3 changesets added across 3 non-merge commits.

- **minor** — A record-form field can name one item of a metadata registry by its machine name: a `text` field that declares `widget: 'position-ref'` lists the position registry, and one that d… (objectui `088e0f705`)
- **patch** — A position approver is read through the spec's registry binding, `{ source: 'registry', type }` (objectstack#22710): its readable label and its designer picker come from the posit… (objectui `83b9fade2`)
- **patch** — A rich-text field no longer draws hint lines above its editor (objectui#12110, ruled B). The `markdown`, `html` and `richtext` editors used to show "Format: markdown" (or "Format:… (objectui `2498a0753`)

Clause-②: no

objectui range: `e5311165a8d6...088e0f705520`
19 changes: 19 additions & 0 deletions .changeset/objectui-pin-citations-088e0f705520.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'@objectstack/spec': patch
---

The spec's objectui citations, and the shipped description text that names the `.objectui-sha` pin (the `FormField.span` describe and six migration-entry descriptions), are re-measured against the new console pin, objectui `088e0f705520`.

Clause-②: no

Every anchor was mapped through the objectui diff `e5311165a8d6..088e0f705520`: 54 paths over 3 commits (objectui#12110's rich-text hint lines, objectui#12174 and objectui#12175). Files that three records cite changed on the hop, all for objectui#12175, and every cited line in them held or moved with its text byte-identical:

- `form.tsx` (+3, registering the `position-ref` / `permission-ref` widget hints): `spanLadderFor` held at `:275-302`, and its one call site moved `:3326` -> `:3329` with the call unchanged. So `FormField.span: 'full'` still takes the whole row at every multi-column tier.
- `data-objectstack/src/index.ts` (+33 at `:5335`, the adapter's `listMetadataItems`): this lands below both reads the curated-public-blocks record cites, so `serializeOrderBy` `869-895` and the `translateFilterArray` arm `5066-5077` are unmoved.
- The `en` / `zh` / `de` packs (`fields.registryRef` keys, +4 each): the calendar record's `calendar.configRequired` strings moved by +4 and did not change.

Every other record cites only files that are byte-identical across the hop (`git diff --quiet`, checked file by file), and each gains a hop sentence that says so.

The six migration entries' corpus counts were re-taken with `git grep -o -F`, the method that reproduces every `e5311165a8d6` number. The corpus is now 8519 tracked files, and every retired name each entry counts still reads 0. The lit controls moved with the corpus, for example `objectstack` from 18355 to 18400 and `useState` from 2659 to 2661.

No key, default, enum member or export moves.
48 changes: 36 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1066,17 +1066,27 @@ jobs:
# second red on wall time against `timeout-minutes`. Both constants, their
# measured basis and a self-test battery each live in the script.
#
# THE RED IS A `schedule` RED ALONE (C2, both timing steps, ruling
# https://github.com/objectstack-ai/objectstack/issues/22949#issuecomment-6119186511):
# the dataset's weights are measured on the hourly `schedule` runs, so
# only those exit 1 on DRIFT. On `merge_group`, `pull_request`, `push`
# and `workflow_dispatch` the step prints the same verdict, raises the
# DRIFT as a `::warning::` annotation and exits 0. The event reaches the
# script as `--event "$GITHUB_EVENT_NAME"`, which it requires; the rule
# and its self-test live there (TIMING_GRADED_EVENT, timingGateMode).
#
# EXECUTED WINDOWS ONLY. Measurements come from samplesFromSummary() in
# measure-test-shard-timings.mjs, which drops cache HITs and failed
# suites, and the prediction is summed over the same executed packages.
# A replay's near-zero window would read as a shard far FASTER than
# predicted and vouch for a rotted dataset, so a shard whose packages all
# replayed is NOT MEASURED, never "fast".
#
# NO `if:` and NO `continue-on-error` (the red is the point), and ABOVE
# the attestation pair for the #6082 reason documented on the upload
# above: a failed unguarded step skips that pair, so a drift red also
# withholds this shard's attestation, the fail-closed direction. A shard
# NO `if:` and NO `continue-on-error` (the red is the point, and the
# `schedule`-only red is the script's `--event`, so neither is needed),
# and ABOVE the attestation pair for the #6082 reason documented on the
# upload above: a failed unguarded step skips that pair, so a drift red
# also withholds this shard's attestation, the fail-closed direction. A shard
# with no packages runs no turbo and writes no summary; that is NOT
# MEASURED here rather than a usage error from the script.
#
Expand Down Expand Up @@ -1109,7 +1119,7 @@ jobs:
exit 0
fi
node scripts/partition-test-shards.mjs --check-drift "${SUMMARIES[@]}" \
--label "Test Core (${{ matrix.shard }}/6)"
--label "Test Core (${{ matrix.shard }}/6)" --event "$GITHUB_EVENT_NAME"

# Runs even when the suite failed — that is when it earns its keep. It
# answers TWO questions about a red suite, and needs both to be able to
Expand Down Expand Up @@ -1486,12 +1496,12 @@ jobs:
# ── The per-package suite-duration ratchet (#16468) ──────────────────
#
# A GATE, unlike the two reporting steps above: NO `continue-on-error`,
# so a package whose suite ran past its ceiling reds `Test Core`, naming
# the package and its slowest test files. The ceiling is the package's
# slowest executed run in the refresh window x 1.25, generated into
# scripts/test-shard-timings.json (`ceilings`) by the refresh lane and
# held by every later refresh; it rises only by a ruled entry in the
# script's RULED_CEILING_RAISES. A `provisional` package prints "no
# so on a `schedule` run a package whose suite ran past its ceiling reds
# `Test Core`, naming the package and its slowest test files. The
# ceiling is the package's slowest executed run in the refresh window
# x 1.25, generated into scripts/test-shard-timings.json (`ceilings`) by
# the refresh lane and held by every later refresh; it rises only by a
# ruled entry in the script's RULED_CEILING_RAISES. A `provisional` package prints "no
# ceiling: provisional" and is not red; a package absent from the dataset
# prints "no ceiling: new package" and is not red until the first refresh
# after it lands gives it a ceiling, while a package the dataset knows
Expand All @@ -1505,6 +1515,20 @@ jobs:
# samplesFromSummary, and every vitest file line); a capture that did not
# arrive leaves its packages ungraded and says so, never red.
#
# EXIT-GRADED ON `schedule` ALONE (C2, both timing steps, ruling
# https://github.com/objectstack-ai/objectstack/issues/22949#issuecomment-6119186511):
# the ceilings come from the hourly `schedule` runs, so only those red
# this job on a package over its ceiling. On `merge_group`,
# `pull_request`, `push` and `workflow_dispatch` the step prints the same
# table, raises each package over its ceiling as a `::warning::`
# annotation and exits 0; a real slowdown merged to `main` reds the next
# hourly run. A package whose ceiling is under the absolute floor (20s,
# CEILING_FLOOR_SECONDS) prints "below floor" and is never red. The
# event reaches the script as `--event "$GITHUB_EVENT_NAME"`, which it
# requires; a refusal (a malformed table or raise record) is red on every
# event. The rule, the floor's reading and their self-tests live in the
# script.
#
# NOT MEASURED, exit 0, while the dataset carries no `ceilings`: they are
# generated only where the run-summary artifacts are downloadable (the
# refresh lane), so the first refresh after this lands writes them, and
Expand All @@ -1515,7 +1539,7 @@ jobs:
# captured, so a red shard's packages are graded too.
- name: Check the per-package suite-duration ceilings
if: always()
run: node scripts/check-test-suite-ceilings.mjs --captures "$RUNNER_TEMP/test-timings" --label 'Test Core'
run: node scripts/check-test-suite-ceilings.mjs --captures "$RUNNER_TEMP/test-timings" --label 'Test Core' --event "$GITHUB_EVENT_NAME"


# ── Temporal conformance against live, non-UTC servers (ADR-0053 D-A3) ─────
Expand Down
2 changes: 1 addition & 1 deletion .objectui-sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e5311165a8d6aa77b5cb7d9fd05da8451a2c21aa
088e0f705520e82bee1d65a5fa3c1f7a26672dde
4 changes: 2 additions & 2 deletions content/docs/references/ui/view.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ Column footer summary configuration
| **required** | `boolean` | optional | Required override |
| **hidden** | `boolean` | optional | Hidden override |
| **colSpan** | `integer` | optional | Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (`colSpan: 4` in a 3-column grid renders as 3); a `colSpan` within the column count renders as authored, and `colSpan: 1` emits no span class at all. |
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `e5311165a8d6`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `088e0f705520`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
| **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) |
| **language** | `string` | optional | Code editor language (for type=code) |
| **keyField** | `{ field?: string; label?: string \| Record<string, string>; placeholder?: string \| Record<string, string>; helpText?: string \| Record<string, string>; … }` | optional | Key column config for record-typed fields |
Expand Down Expand Up @@ -343,7 +343,7 @@ Form-view select option — the object-field option shape minus the per-option `
| **required** | `boolean` | optional | Required override |
| **hidden** | `boolean` | optional | Hidden override |
| **colSpan** | `integer` | optional | Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (`colSpan: 4` in a 3-column grid renders as 3); a `colSpan` within the column count renders as authored, and `colSpan: 1` emits no span class at all. |
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `e5311165a8d6`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `088e0f705520`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. |
| **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) |
| **language** | `string` | optional | Code editor language (for type=code) |
| **keyField** | `{ field?: string; label?: string \| Record<string, string>; placeholder?: string \| Record<string, string>; helpText?: string \| Record<string, string>; … }` | optional | Key column config for record-typed fields |
Expand Down
6 changes: 3 additions & 3 deletions packages/sdui-parser/objectui-lockstep.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
],
"objectui": {
"repo": "https://github.com/objectstack-ai/objectui.git",
"rev": "e5311165a8d6aa77b5cb7d9fd05da8451a2c21aa",
"revDate": "2026-10-12T01:48:21+00:00",
"rev": "088e0f705520e82bee1d65a5fa3c1f7a26672dde",
"revDate": "2026-10-12T03:19:24+00:00",
"source": "packages/sdui-parser/src",
"files": [
"packages/sdui-parser/src/body-dialect.ts",
Expand All @@ -21,7 +21,7 @@
"packages/sdui-parser/src/validate.ts"
]
},
"recordedAgainstPin": "e5311165a8d6aa77b5cb7d9fd05da8451a2c21aa",
"recordedAgainstPin": "088e0f705520e82bee1d65a5fa3c1f7a26672dde",
"grammarRegion": {
"file": "packages/sdui-parser/src/parse.ts",
"delimiter": "/* ---------------------- the JS literal subset (#6614) ---------------------- */",
Expand Down
5 changes: 4 additions & 1 deletion packages/spec/src/data/api-methods-batch-conformance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
// `revoked` on ONE key. The multi-select surface this rule protects does not
// exist for API keys, and the shape a future one would take does not need
// `bulk` either — both read off the console build this release pins
// (`.objectui-sha` = `e5311165a`, re-read there 2026-10-12:
// (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12:
// every objectui file this record cites is byte-identical across the hop from
// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
// `e5311165a`, re-read there 2026-10-12:
// in `packages/plugin-grid`, on the hop off `499799502`, `ObjectGrid.tsx`
// changed again (27 insertions, 11 deletions: objectui#12110's authored
// column label and objectui#12143's grouped-pager button names), none of it
Expand Down
23 changes: 20 additions & 3 deletions packages/spec/src/kernel/functional-completeness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,15 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* English sentence. So the loss is total rather than partial — every
* record, on every object — and the author is told at render time as well
* as here. Both reads hold at the pin this repo builds against
* (`.objectui-sha` = `e5311165a`, re-read there 2026-10-12:
* (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12:
* on the hop off `e5311165a` `ObjectCalendar.tsx` and `ListView.tsx` are
* byte-identical (`git diff --quiet`), so `getCalendarConfig` `:311`, the
* `if (!calendarConfig)` arm `:1354` with its `tt(…)` lines `:1361-1362` and
* the `case 'calendar'` at `3813` did not move; and the `en` / `zh` / `de`
* packs changed (objectui#12175's `fields.registryRef` keys, +4 each, so
* `en.ts` `:945` -> `:949`, `zh.ts` `:721` -> `:725`, `de.ts` `:701` ->
* `:705`) but not their `calendar.configRequired` strings. At `e5311165a`,
* re-read there 2026-10-12:
* on the hop off `499799502` `ObjectCalendar.tsx` and `ListView.tsx` are
* byte-identical (`git diff --quiet`), so `getCalendarConfig` `:311`, the
* `if (!calendarConfig)` arm `:1354` with its `tt(…)` lines `:1361-1362` and
Expand Down Expand Up @@ -432,7 +440,10 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* This repo already records the same deletion one door over: the #13817
* check in `../ui/view.zod.ts` names objectui#7029 as its runtime half.
* - `gantt` → NO fallback, and no silence [#19630]. Measured at the pin
* this repo builds against (`.objectui-sha` = `e5311165a`, re-read there 2026-10-12:
* this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12:
* every objectui file this record cites is byte-identical across the hop from
* `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
* `e5311165a`, re-read there 2026-10-12:
* every objectui file this record cites is byte-identical across the hop from
* `499799502` (`git diff --quiet`), so every anchor held unmoved. At
* `499799502`, re-read there 2026-10-11:
Expand Down Expand Up @@ -534,6 +545,9 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* requires. So the view does not draw a blank chart: it refuses, by name.
* - `timeline` → date axis: NO fallback [#19630]; title: `titleField || 'name'`,
* which still stands. Measured at the same pin (`.objectui-sha` =
* `088e0f705`, re-read there 2026-10-12:
* every objectui file this record cites is byte-identical across the hop from
* `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
* `e5311165a`, re-read there 2026-10-12:
* every objectui file this record cites is byte-identical across the hop from
* `499799502` (`git diff --quiet`), so every anchor held unmoved. At
Expand Down Expand Up @@ -633,7 +647,10 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* block does render; the warning still fires there, because the block the
* view TYPE names is the one that is missing. Unchanged by this row.
* - `map` → NO fallback, and no silence [#19630]. Measured at the same
* pin (`.objectui-sha` = `e5311165a`, re-read there 2026-10-12:
* pin (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12:
* every objectui file this record cites is byte-identical across the hop from
* `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
* `e5311165a`, re-read there 2026-10-12:
* every objectui file this record cites is byte-identical across the hop from
* `499799502` (`git diff --quiet`), so every anchor held unmoved. At
* `499799502`, re-read there 2026-10-11:
Expand Down
Loading
Loading