Skip to content

Commit 4008475

Browse files
committed
Merge origin/main into the rules-only rewrite of the ledger, REST table and lanes
Two sibling rules-only PRs landed on main and re-pin rows in the same ratchet map this branch edits, which is what turned the PR dirty in the queue. One conflicted file, two hunks, both resolved by keeping BOTH sides — the map is a list of independent rows and the two branches move disjoint ones: scripts/pm/check-skill-line-ratchet.mjs hunk 1: ours rest-channel.md 88 -> 82 (with its note) kept, and theirs review-checklist.md 84 -> 77 and landing-operations.md 80 -> 69 (with their notes) kept hunk 2: ours release-aftercare.md 58 -> 50 (with its note) kept, and theirs seat-post-protocol.md 105 -> 91 (with its note) kept Everything the automatic merge already took is unchanged: their SKILL.md 1005 -> 811, dispatch-runbook 280 -> 241, state-machine 44 -> 42, contract-review 68 -> 60, decision-analysis 54 -> 50 and the SKILL.md widest-table-row pin 642 -> 342; our remaining eleven rows and the retired third-increment ruled-raise record on the cross-file move. The thirteen markdown files this branch rewrites are byte-identical to the pre-merge commit — main touched none of them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
2 parents ddf47bd + fa125f3 commit 4008475

91 files changed

Lines changed: 4981 additions & 2030 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
---
2+
"@objectstack/client": minor
3+
---
4+
5+
fix(client)!: the `oauth.*` family declares the wire shapes better-auth actually sends — four published `Promise< any >` returns narrowed (#14312)
6+
7+
**BREAKING** for a typed caller, and it breaks nothing that ever worked at runtime. No request bytes, no URL and no response handling change: this is a declaration catching up with what the routes have always answered. It ships as `minor` under the lockstep launch-window convention (`scripts/check-changeset-no-major.mjs`) — the version number is not the migration signal here, this entry is.
8+
9+
<!-- adr-0087: not-required (type-surface-only packages/client/src/index.ts#register, packages/client/src/index.ts#getPublic, packages/client/src/index.ts#consent) A published TYPE-SURFACE narrowing. Each member was UNANNOTATED at the merge base, so lib.dom's `Response.json()` published it as an erased `any`; each now declares the shape its route already answered. No method body changed, so no request or response byte moves, and the diff touches no `packages/spec` path and no ADR-0087 shape surface. The affected party is a TypeScript consumer and the compiler delivers the break at their own call site; `objectstack migrate meta`, `spec-changes.json` and the upgrade guide have nothing to rewrite, so a ledger entry would be false data in the one ledger this gate keeps true. DISCLOSURE, not an omission: the fourth narrowed member of this changeset is `oauth.applications.get` (index.ts line 3184; unannotated at base, `Promise` of `OAuthApplication` at HEAD). It satisfies this same predicate on a direct reading, but it is deliberately NOT named above, because the reference `packages/client/src/index.ts#get` does not address it: this file declares 13 members named `get`, predicate 4 reads the FIRST one (line 1928), and that member is unrelated and unannotated at both revs. Naming it would assert a verified fact about the wrong member; the ambiguity is filed as its own card. -->
10+
11+
Card 1 of 3 of the #12104 family, under the maintainer's 2026-08-31 ruling: the wire contract is the only source of truth, and better-auth's own `Date`-typed fields are the pre-serialization SERVER shape, not the wire fact.
12+
13+
## What changed
14+
15+
Four methods ended `return res.json()` with no return annotation, so `lib.dom`'s `Response.json(): Promise< any >` was their published type. Each now declares the shape its route serves, and its `exported-any-returns.json` entry is deleted in the same change:
16+
17+
| method | resolved to (before) | resolves to (now) |
18+
|:--|:--|:--|
19+
| `client.oauth.applications.register(req)` | `any` | `OAuthApplicationRegistration` |
20+
| `client.oauth.applications.get(id)` | `any` | `OAuthApplication` |
21+
| `client.oauth.applications.getPublic(id)` | `any` | `OAuthApplicationPublic` |
22+
| `client.oauth.consent(req)` | `any` | `OAuthConsentResult` |
23+
24+
`OAuthApplication`, `OAuthApplicationRegistration`, `OAuthApplicationPublic` and `OAuthConsentResult` are newly exported from `@objectstack/client`. These four routes are served BARE by better-auth (`auth-route-ledger.ts` records them `source: 'better-auth'`) — there is no `{ success, data }` envelope to unwrap, and none is introduced.
25+
26+
## The exact reads that stop compiling
27+
28+
Everything below compiled before only because `any` is assignable to, and indexable by, everything.
29+
30+
```ts
31+
const app = await client.oauth.applications.get('c_1');
32+
app.data; // was fine; now TS2339 — these routes carry NO envelope
33+
app.anythingAtAll; // was fine; now TS2339
34+
35+
const pub = await client.oauth.applications.getPublic('c_1');
36+
pub.client_secret; // now TS2339 — the public projection hand-picks 7 columns
37+
pub.grant_types; // now TS2339 — same reason
38+
pub.disabled; // now TS2339 — same reason
39+
40+
const decision = await client.oauth.consent({ accept: true });
41+
decision.client_id; // now TS2339 — consent answers `{ redirect, url }`
42+
43+
// Timestamps are RFC 7591 NUMBERS (Unix epoch seconds), so a caller that
44+
// guessed `Date` or ISO `string` now fails:
45+
new Date(app.client_id_issued_at!).toISOString(); // TS2769: number is not a Date arg
46+
app.client_id_issued_at!.slice(0, 10); // TS2339: not a string
47+
new Date(app.client_id_issued_at! * 1000); // the correct rewrite
48+
```
49+
50+
A caller that only read `client_id`, `client_secret`, `redirect_uris` or `url` needs no change.
51+
52+
## Timestamps: `number`, not `Date` and not ISO-8601
53+
54+
The ruling ordered every `Date`-typed field declared as an ISO `string` and forbade both a `Date` declaration and a runtime revival layer. **This family has no `Date` field to convert.** RFC 7591 carries `client_id_issued_at` and `client_secret_expires_at` as Unix-epoch SECONDS, and the provider converts its stored `Date` to a number before serialising, so the wire sends neither a `Date` nor an ISO string. Both are declared `number`, and a type-level pin holds them there. The ruling's prohibitions are satisfied: nothing declares a `Date`, and no revival layer exists.
55+
56+
## Two places better-auth's own types were the wrong answer
57+
58+
Read off the wire against a real server, not off the vendor's `.d.ts`:
59+
60+
- `getPublic` is declared `OAuthClient` — the full row — but its handler hand-picks seven columns. `OAuthApplicationPublic` is that projection, derived with `Pick` so it cannot drift from its parent. Its `redirect_uris` is always `[]` on this route and carries no information.
61+
- `user_id` and `application_type` are declared nullable by the vendor, but the serialiser folds a null column to `undefined`, so `null` is unreachable and is not declared.
62+
63+
## `oauth.applications.delete` is deliberately NOT bound
64+
65+
The fifth method of the family keeps its `Promise< any >` and its ledger entry. Its route answers HTTP 200 with a zero-byte body, so its `res.json()` rejects with a `SyntaxError` on every successful delete. No annotation can be honest while that call stands, and binding it needs a behaviour change — a decision beyond this card's type-narrowing scope. That the shrink-only ledger still carries exactly this one entry is the mechanism working.

.changeset/console-a472b07167a3.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
"@objectstack/console": minor
3+
---
4+
5+
Console (objectui) refreshed to `a472b07167a3`. Frontend changes in this range:
6+
7+
Derived from the changesets objectui declared over the range — 15 releasing of 18 changesets added across 29 non-merge commits; omitted: 3 release-nothing changesets, 11 commits carrying no changeset (they ship no package code).
8+
9+
- **minor****BREAKING** — Converge the lookup/user widget metadata on the spec's camelCase — one concept, one spelling (objectui#7155, maintainer ruling A′ of 2026-09-03, director decision batch #19). (objectui `351eb3181`)
10+
- **minor****BREAKING** — One authority for `KanbanSchema` / `KanbanColumn` / `KanbanCard`: the bare names now belong to `@object-ui/plugin-kanban` (objectui#6172, closing the cross-package half of objectu… (objectui `2c71482ea`)
11+
- **minor** — Retire `ComponentInput.inputType` — the fifth and last key objectui#5905 named (ADR-0049 enforce-or-remove, maintainer ruling 2026-08-31, option B). (objectui `1ec291c0d`)
12+
- **minor**`@object-ui/core` publishes `resolveRecordSourceObjectName`, the ONE reader for "which object is this block bound to" (objectui#7627). (objectui `b041b9c0c`)
13+
- **minor****Published TS surface narrowed:** `DashboardComponentSchema` no longer declares the dashboard-root `title` member (objectui#7623). (objectui `5d0876c5c`)
14+
- **minor****BREAKING** — BREAKING (`@object-ui/components`): the chart primitives — `ChartContainer`, `ChartTooltip`, `ChartTooltipContent`, `ChartLegend`, `ChartLegendContent`, `ChartStyle` and the `Char… (objectui `7bf244bea`)
15+
- **minor** — ListView: fold `data={{ provider: 'object', object }}` onto `objectName`, and read the author's view kind from `specType` / `type` (objectui#7477 — step 6 of #2890, released by th… (objectui `00d2fa682`)
16+
- **minor** — Retire the dashboard-**root** `title` read across all five surfaces (objectui#7509, maintainer ruling 2026-09-04, decision batch #29, option C, under ADR-0049). (objectui `1cca678ba`)
17+
- **minor****BREAKING** — Re-home the breakpoint layout vocabulary and delete the two dead responsive implementations (objectui#7580, maintainer ruling 2026-09-04, option A). (objectui `e62c44e7e`)
18+
- **minor**`@object-ui/types/zod`: the zod const `StylePropsSchema` is renamed to `ClassNameStylePropsSchema` (objectui#5928). **The old name is gone** — there is no deprecated alias and no… (objectui `24e027e93`)
19+
- **patch** — Fix `extractToc` eating the underscores out of a `SCREAMING_SNAKE` heading, so its `#id` links resolve to the heading they name again (objectui#7667). (objectui `a472b0716`)
20+
- **patch** — Remove `src/ui/toast.tsx`, an unreferenced primitive, and the dependency only it imported (objectui `2f61238b9`)
21+
- **patch** — Fix `extractToc` deleting tag-shaped text that lives INSIDE an inline code span, so its `#id` links resolve to the heading they name again (objectui#7658). (objectui `90c6d090d`)
22+
- **patch** — A record-page URL now names the object the clicked rows actually came from, in `ObjectTree` and `ObjectCalendar` (objectui#7638). (objectui `2ce2612df`)
23+
- **patch** — fix(app-shell): the object-field options editor no longer drops `default` and `visibleWhen` on save (objectui `97c3e1972`)
24+
25+
⚠️ 4 of these carry a breaking change: 4 by the author's own breaking annotation in the changeset body — objectui declares no `major` inside a launch window (`scripts/check-changeset-no-major.mjs`). Each is marked **BREAKING** in the list above — read them before compiling the release record.
26+
27+
**In this console build, declared nowhere** — objectui merged 11 commits in this range with no `.changeset/*.md`. The code is inside the pin above and ships here, but nothing upstream declared them, so they appear in no objectui CHANGELOG and in no entry above. Listed by subject rather than counted, because a count cannot tell a dependency bump from a form-behaviour change (objectstack#6174); the upstream gate that would prevent this is objectui#3387.
28+
29+
- _(no changeset)_ fix(scripts): check-doc-links resolves the #fragment, not just the file (objectui#7644) (#7657) (objectui `f7cf7e8a9`)
30+
- _(no changeset)_ docs(plugin-chatbot): document chatbot-floating's seven declared inputs keys (objectui#7594) (#7656) (objectui `8e501cb97`)
31+
- _(no changeset)_ docs(agents): record the never-approve seat rule beside the governed never-list (#7630) (objectui `2e99852ca`)
32+
- _(no changeset)_ refactor(examples): drop the inert root `title` from six catalog dashboards (#7634) (objectui `46cde8264`)
33+
- _(no changeset)_ docs(check-skill-examples): drop the stale zero-jsonc-fences claim (#7631) (objectui `0b24d7f85`)
34+
- _(no changeset)_ docs(governed-guard): replace the retired sha pin with the ruled approval-record predicate (#7616) (objectui `11edab88f`)
35+
- _(no changeset)_ docs(skills): split multi-document JSON fences, drop the `...` elisions, mark every parsing fence (#7608) (objectui `89d6adf37`)
36+
- _(no changeset)_ fix(scripts): judge spec citations at member granularity, and stop the header teaching a retired filter (objectui#7513) (#7617) (objectui `d28d87bf4`)
37+
- _(no changeset)_ fix(governed-guard): an authorised approval record satisfies the queue leg on any commit (#7606) (objectui `0d8fd7ce3`)
38+
- _(no changeset)_ chore(deps): Bump fumadocs-core from 16.14.4 to 16.15.4 (#7059) (objectui `1bae75bb8`)
39+
- _(no changeset)_ docs(claude-md): collapse the two AGENTS.md excerpts to rule + hook + pointer (#7600) (objectui `c70ebaaeb`)
40+
41+
<!-- adr-0087: not-required (no-migration-prescription) All FOUR declared-breaking entries in the range `00d3f09c500c...a472b07167a3` are judged ONE AT A TIME against `packages/spec`'s authorable surface at this HEAD, not as a batch, and every count below was re-measured here rather than quoted from upstream prose. (1) objectui `351eb3181` (objectui#7155) converges objectui's WIDGET metadata bags `LookupFieldMetadata` / `UserFieldMetadata` onto the spec's camelCase, removing the snake members. It moves TOWARD this repo's contract, not away from it: `packages/spec/src/data/field.zod.ts` already declares `displayField` (`:835`, `:1342`), `descriptionField` (`:1343`) and `lookupFilters` (`:1355`), and the snake spellings have ZERO occurrences under `packages/spec/src` — `display_field` 0, `description_field` 0, `lookup_filters` 0, `id_field` 0 (the single apparent `id_field` hit is the substring inside `invalid_field` in an unrelated `api/protocol.test.ts` fixture). The snake dialect was never an ObjectStack-authorable key, so no accepted key moves, no stored `sys_metadata` row can carry a retired spelling, and there is nothing here for `objectstack migrate meta` to act on. (2) objectui `2c71482ea` (objectui#6172) is a TypeScript export rename inside `@object-ui/types` giving the bare Kanban trio to `@object-ui/plugin-kanban`; `KanbanSchema`, `KanbanColumn` and `KanbanCard` have ZERO occurrences under `packages/spec/src`, and upstream states no member, no optionality and no accept/reject behaviour moves with it. (3) objectui `7bf244bea` (objectui#7397) removes the duplicated React chart primitives from `@object-ui/components`. This repo's own `ChartConfigSchema` / `ChartConfig` (`packages/spec/src/ui/chart.zod.ts:539`) is an independently declared ObjectStack metadata schema that shares a NAME with the removed objectui type and nothing else: `packages/spec/src` imports from `@object-ui/*` zero times (re-measured), so none of the removed React exports sits on any ObjectStack surface. (4) objectui `e62c44e7e` (objectui#7580) re-homes `BreakpointName` and `BreakpointColumnMap` into objectui packages and deletes the two dead responsive implementations. This repo retired that whole vocabulary itself in objectstack#11027 and its ADR-0087 ledger entries ALREADY EXIST on this side — `RETIRED_DEFS_BY_MAJOR[18]` carries `ui/BreakpointName`, `ui/BreakpointColumnMap` and `ui/BreakpointOrderMap` — so this entry is objectui catching up to a retirement already registered here, and it prescribes nothing new. None of the four is reachable through `@objectstack/console` in any case, re-measured against `packages/console/package.json` at this HEAD: it publishes a frozen prebuilt SPA whose `files` list is ["dist", "README.md", "CHANGELOG.md"] and whose sole `exports` entry is `./package.json`, so it forwards no `@object-ui/*` module entry point and re-exports none of these types; and no `package.json` in this workspace declares an `@object-ui/*` dependency at all (0 files, re-measured). This diff is `.objectui-sha`, this changeset and the regenerated console provenance records the pin gates require, and nothing else — no `packages/spec` schema, no authorable metadata key and no protocol surface change is in it. This bump adds no ledger entry and claims none. -->
42+
43+
objectui range: `00d3f09c500c...a472b07167a3`
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
"@objectstack/service-automation": minor
3+
---
4+
5+
A contained per-iteration failure is now visible at run level, attributed to its iteration, and bound to its row.
6+
7+
`loop { body: [ try_catch { try, catch } ] }` is the containment spelling for a per-iteration failure that must not end the sweep (there is deliberately no `loop.config.onIterationError` key). Containment already worked — the failure was caught, the loop went on and the run completed — but nothing said what it had contained: a sweep that lost two rows out of five reported `status=completed selected=5 acted=9 skipped=0` and was indistinguishable from one that lost none. The failure was in the step log and in `nodes[].failures`; no run-level number carried it, the failing step named no row, and `$error` bound no row identity.
8+
9+
Four changes populate the contract `@objectstack/spec` already declares:
10+
11+
- **`FlowRunSummary.failed`**`summarizeRun` now folds `failed = Σ nodes[].failures` over the per-node array it publishes, so the run-level count can never disagree with the breakdown it summarizes. It counts every node execution that failed, contained or fatal; on a run that completed, all of them were contained.
12+
- **`failed=N` on the run summary line**`formatRunSummaryLine` prints the token whenever the count is present, `failed=0` included. That is the opposite of the `unmeasured` rule beside it and deliberate: `unmeasured` qualifies `acted`, while `failed` answers a question a completed run's line otherwise cannot be asked at all. Read `failed=0` precisely: **no node execution of this run failed**. It is the node fold and only that, so a `subflow` child's own contained failures stay on the child's summary rather than rolling up the way `acted` does — see #15617, where the declaration's two paragraphs are being reconciled.
13+
- **Iteration through `try_catch`** — a step that ran in a `try` or `catch` region inside a loop body now carries the enclosing loop's `iteration`, with `regionKind` still `try` / `catch`. The step says which region ran it *and* which row it ran for. `parallel` branch tagging is unchanged.
14+
- **`$error` binds the row** — the value bound to `errorVariable` (default `$error`) is the declared `TryCatchErrorValue`: `nodeId` and `message` as before, plus `iteration` and the loop's current `item` when the failure happened inside a loop body. A `subflow` / `map` child run has its own variable scope and therefore binds neither, so a parent's row identity never leaks into a child's `$error`.
15+
16+
**`failed` absent means "not tracked", never `0`.** Runs recorded before this change keep it absent — no migration and no default, the same convention `unmeasured` carries. Defaulting it to zero would tell an operator "nothing failed" about a run nobody measured. Absent, the summary line prints no `failed=` token at all; present-and-zero prints `failed=0`. The count rides in the persisted `summary_json`, including on a summary compacted past the size cap, where the per-node `failures` it folds are exactly what gets dropped.

0 commit comments

Comments
 (0)