Skip to content

Commit b22a9ee

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-15204-s8-catalog-objects
2 parents 68121eb + 4f5679c commit b22a9ee

35 files changed

Lines changed: 3477 additions & 430 deletions
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@objectstack/verify': minor
3+
---
4+
5+
fix(verify)!: `runDashboardWindowProofs` takes no options, so the dashboard date-window run can no longer be pinned to an instant the server does not resolve on, and a run that crosses UTC midnight after it starts reports `not-run` instead of a false red
6+
7+
`runDashboardWindowProofs(stack, token, config)` loses its fourth parameter, and `DashboardWindowProofOptions` (its only member was `now`) is retired. The server resolves a dashboard's date preset per request on its own clock, so any `now` other than the current instant made every window read `contradicted`: the option could only produce false reds, and nothing passed it.
8+
9+
Clause-②: no (narrowing)
10+
11+
<!-- adr-0087: not-required (runtime-export-retired @objectstack/verify#DashboardWindowProofOptions) No metadata moves: no spec key, authorable spelling, object definition or stored shape is added, removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite. What retires is one type export of `@objectstack/verify`'s published entry, `DashboardWindowProofOptions`, together with the optional fourth parameter of `runDashboardWindowProofs` that it typed. The affected party is a TypeScript caller, and the compiler at that call site delivers the break. -->
12+
13+
**BREAKING** (an accept-set narrowing), shipped as `minor` under the launch-window convention for breaking changes.
14+
15+
- FROM `DashboardWindowProofOptions` TO nothing (no replacement): drop the fourth argument, so `runDashboardWindowProofs(stack, token, config, { now })` becomes `runDashboardWindowProofs(stack, token, config)`.
16+
17+
Fix: the presets resolve when the run starts, and each count measure places its fixture rows on the day it is probed. A run that crossed UTC midnight between the two judged that measure against the previous day's edges and could read it `contradicted`. That measure is now `not-run`, and its detail names both days; the widget reads `inconclusive`. The guard that catches a day turning while a measure is being probed is unchanged.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/skills": patch
3+
---
4+
5+
docs(skills): both READMEs the package ships install the catalog from `@objectstack/skills` at the installed `@objectstack/spec`'s version, and name the GitHub path only as the `next` channel (#22668)
6+
7+
Clause-②: no
8+
9+
`README.md` (the npm page) and `dist/skills/README.md` (the catalog's front page, copied from the repository's `skills/README.md`) are the two READMEs this package ships. Both now give the same two-step install the docs give: `npm install --save-dev "@objectstack/skills@$(node -p "require('@objectstack/spec/package.json').version")"`, then `npx skills experimental_sync --agent claude-code -y` — the catalog's version is then the installed spec's.
10+
11+
Before: the npm page taught a bare `npm install --save-dev @objectstack/skills`, which on a project depending on `@objectstack/spec` 17.x installs `18.0.0-next.0`, the next major's catalog (the registry's `latest`); its example named `@objectstack/skills@17.7.0`, a version that was never published; and it did not say that the sync skips every skill a `skills add` installed, which is every project `create-objectstack` scaffolded through `18.0.0-next.0`. The catalog's front page still taught `npx skills add objectstack-ai/objectstack/skills …` as the install command for existing projects.
12+
13+
Both pages now state which versions exist (published from `18.0.0-next.0` on; no 17.x, so step 1 answers `ETARGET` there), the update story (bump `@objectstack/skills` with the other `@objectstack/*` packages, then re-run the sync), and the GitHub path once, as the `next` channel: the unreleased `main`, for trying the next version's skills, not for a released project. Nothing under `dist/skills/*/` changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/plugin-auth': patch
3+
---
4+
5+
fix(plugin-auth): a fresh `os dev` database opens on the console shell, not on the "Set the workspace timezone" dialog — the dev seed gives the workspace it lands its admin in the host's time zone
6+
7+
Clause-②: no
8+
9+
**FROM.** The dev admin seed (`NODE_ENV=development`, on unless `OS_SEED_ADMIN=0`) created its admin and left the admin's workspace with `localization.timezone` unset. The console asks an administrator for a zone while that key still resolves from the manifest default, so every fresh `os dev` database (each `--fresh` run, each new database file) opened on the dialog. The console's own workspace-creation paths already send the creator's browser zone; the seed did not go through them.
10+
11+
**TO.** On the boot that seeds the admin, the seed writes the host's resolved zone (`Intl.DateTimeFormat().resolvedOptions().timeZone`, so `TZ` chooses it) to `localization.timezone` for each organization the admin is a member of. Under the default `single` posture that is the Default Organization. The write goes through the settings service, the same door the dialog's confirm uses. It is one `tenant` row per organization, with the key's IANA zone check applied there.
12+
13+
**Unchanged.**
14+
- A zone already set on any rung (the organization's, the global one, an `OS_LOCALIZATION_TIMEZONE` override) is never overwritten.
15+
- A host that reports no zone, or reports one the settings door refuses, gets nothing written. The workspace keeps the default and the dialog still asks.
16+
- Boots after the seeding one write nothing, so a database that already exists is not touched.
17+
- Production is not affected: the seed stays gated to `NODE_ENV=development`.
18+
- `sys_organization.timezone` is a separate key, which the dialog does not read. It is not written.
19+
20+
**Note for in-process test boots.** `@objectstack/verify`'s harness forces `NODE_ENV=development` to get the seeded admin, so its boots now give that admin's workspace the host's zone too. On a host in `UTC` the resolved value is the same as before. On a host in another zone, a suite that relies on the default `UTC` can set `TZ=UTC`, or set the zone through `PUT /api/settings/localization` as it would for any workspace.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
'@objectstack/runtime': minor
3+
'@objectstack/rest': minor
4+
'@objectstack/cloud-connection': minor
5+
---
6+
7+
fix(runtime,rest,cloud-connection)!: the declared-endpoint fallback, REST's direct-mounted publish and federation routes, and cloud-connection's session doors refuse a session the ADR-0069 authentication policy holds
8+
9+
Clause-②: no (narrowing) — a session ADR-0069 holds out of protected resources is refused by doors that answered it; core's existing exports only, no published schema or export moves.
10+
11+
<!-- adr-0087: not-required (no-migration-prescription) A runtime authentication narrowing at three groups of doors, not a metadata change. No spec key, export, option, config field, response field or stored shape is removed, renamed or re-shaped, and a session the policy does not hold receives the same answers as before, so there is no tombstone and nothing for `objectstack migrate meta` to rewrite. What narrows is which sessions these doors serve: a session whose user carries the ADR-0069 posture (an expired password, or enforced MFA not yet enrolled) is now refused with the gate's 403 before the door's own logic runs. The other categories are closed on facts: the three packages publish (not unpublished); no ADR-0087 id covers these doors and this diff adds none (not registered / already-registered); and no published interface or type changes, the new fields living on package-internal types only (not runtime-interface-only / type-surface-only). -->
12+
13+
**BREAKING** (an accept-set narrowing), shipped as `minor` under the launch-window convention for breaking changes.
14+
15+
ADR-0069 holds a signed-in user out of every protected resource while their password has expired or while enforced MFA is not yet enrolled, until they remediate. REST's `enforceAuth` and the runtime dispatcher already refuse such a session. Three groups of doors that resolve a session on their own never asked, so they served it as an ordinary signed-in caller:
16+
17+
- **`@objectstack/runtime`**: the declared-endpoint fallback (app-declared `apis:` endpoints, served by the dispatcher plugin's fallback seam). Its policy chain now asks the shared decision (`evaluateAuthGate`, `@objectstack/core`) before `authRequired` and before the endpoint's target runs, on every declared endpoint, an `authRequired: false` one included, because the target runs as the caller. While a gate feature is active the chain reads the session for this, and when an active gate cannot read the session the request is answered `503` (`SERVICE_UNAVAILABLE`), as REST answers it. No declared path is handed to the allow-list, so no endpoint can exempt itself through the prefix it sits under.
18+
- **`@objectstack/rest`**: the direct-mounted package publish door (`registerPackageRoutes`) and the external-datasource federation family (`registerExternalDatasourceRoutes`). Each refuses on the `authGate` the REST resolver already puts on the execution context it hands them.
19+
- **`@objectstack/cloud-connection`**: `CloudConnectionPlugin`'s seven session doors (bind, poll, unbind, install, and the three installed-state reads) and all five `MarketplaceInstallLocalPlugin` doors (install, list, uninstall, reseed, purge). Each plugin asks the gate once, where it resolves the session, and every door that resolves one refuses on it.
20+
21+
- **Refused now:** a held session gets `403` with the gate's own `code` (`PASSWORD_EXPIRED` or `MFA_REQUIRED`) and `message`, in each door's declared error envelope, before the door does anything else. This is the answer REST gives the same session.
22+
- **Unchanged:** a session the policy does not hold is served exactly as before, an API-key caller is unaffected because it has no session to hold, and an anonymous caller gets the same `401`. `CloudConnectionPlugin`'s status read and `MarketplaceProxyPlugin`'s catalog proxy resolve no session and answer every caller alike, so they are unchanged.
23+
24+
What changes for you. A user the policy holds must remediate (change the password, or enroll an authenticator) before these doors answer them, as on every other protected route. Nothing needs configuring: the posture comes from the kernel's `auth` service, as it does for REST and the dispatcher.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@objectstack/metadata-protocol": patch
3+
---
4+
5+
Republishing a view container without one of its views now stops serving that view, without a restart
6+
7+
Clause-②: no
8+
9+
- A view container (a `defineView` document, such as a package's `showcase_task` views) expands to one view per entry, registered in the process registry under `<object>.<viewKey>`. A publish of the container registered the views it expanded to and removed none it no longer expanded to. So after `POST /api/v1/meta/view/NAME/publish` of a container whose `listViews` lost an entry, `GET /api/v1/meta/view`, `GET /api/v1/meta/view?object=OBJECT` and the by-name read of that view kept serving it until the process restarted.
10+
- Every write that changes a view container's stored row now leaves the registry holding the views that row expands to: a publish, a save that publishes, a rollback, a revert, a replica's convergence, a reset and a delete. So does the list read's and the boot's hydration of a stored row. The write answers after this, so a read that follows it serves the published set.
11+
- A view the container no longer expands to is healed the way a reset heals it: where a package ships a view of that name, the package's view is served again, and a name nothing else serves is removed. As for a reset, a name whose MetadataService read fails stays registered until a restart.
12+
- When one container name has two stored rows (one bound to no package, one bound to a package), each row is compared with what that row registered before. A republish of one row removes only the views that row dropped, and the list read leaves both rows' views registered however often it runs. A view both rows expand to, which one row drops, is served from the other row's stored row and registered again by the next list read. A reset or delete of the name heals every row's views, as before.
13+
- Unchanged: an organization-scoped write touches no registry entry, a baseline is re-registered on a control-plane kernel only, and a view name another package ships is never registered or healed for the container. Every other type registers and resets as before.
14+
- No public export, signature, schema or accept-set change. In the built entry declarations, `ObjectStackProtocolImplementation` gains one untyped `private` member name and loses two `private static` ones.

0 commit comments

Comments
 (0)