diff --git a/README.md b/README.md
index 6d6dd16e4b..dd39ebb761 100644
--- a/README.md
+++ b/README.md
@@ -177,7 +177,7 @@ os doctor # Check environment health
os explain # Explain protocol concepts on the command line
```
-Cloud, package registry, and environment management subcommands (`os publish`, `os rollback`, `os package`, `os login`, `os whoami`, `os cloud …`) are available when targeting an ObjectStack Cloud control plane.
+Cloud, package registry, and environment management subcommands (`os package publish`, `os package install`, `os login`, `os whoami`, `os environments`, `os cloud …`) are available when targeting an ObjectStack Cloud control plane.
## Use the generated API
diff --git a/content/docs/concepts/cloud-artifact-api.mdx b/content/docs/concepts/cloud-artifact-api.mdx
index 9632a50830..86372d67c3 100644
--- a/content/docs/concepts/cloud-artifact-api.mdx
+++ b/content/docs/concepts/cloud-artifact-api.mdx
@@ -37,14 +37,15 @@ caches.
}
```
-The CLI command is:
+This control-plane endpoint is driven by the Cloud / Marketplace install flow.
+The framework CLI publishes through the package catalog:
```bash
-OS_CLOUD_URL=https://cloud.example.com \
-OS_ENVIRONMENT_ID=env_prod \
-os publish
+os package publish ./dist/objectstack.json --env env_prod --install
```
+(The legacy direct-to-environment `os publish` CLI was removed — #2237.)
+
---
## Activate revision endpoint
@@ -57,11 +58,9 @@ Activating a revision changes the environment's current artifact pointer.
Runtime nodes can then reload or refresh their environment kernel based on the
new commit/checksum.
-```bash
-OS_CLOUD_URL=https://cloud.example.com \
-OS_ENVIRONMENT_ID=env_prod \
-os rollback --commit 9ce1bd48dd7022b8
-```
+Revision activation is a Cloud control-plane operation. The framework `os rollback`
+CLI was removed (#2237); to change an environment's active artifact, install the
+desired package version into it.
---
diff --git a/content/docs/concepts/metadata-lifecycle.mdx b/content/docs/concepts/metadata-lifecycle.mdx
index 6177037ec8..ed95d0ba6e 100644
--- a/content/docs/concepts/metadata-lifecycle.mdx
+++ b/content/docs/concepts/metadata-lifecycle.mdx
@@ -76,6 +76,20 @@ The `seq` is the single source of truth for ordering. The Studio status badge (`
---
+## Package-first authoring (ADR-0070)
+
+Every runtime-authored item lives inside a **writable package** — there are no
+orphans. Code-defined and installed packages are **read-only** at runtime, so the
+first step of any Studio/API authoring action is to target a *writable* package (a
+"base"): a create/update aimed at a read-only package is rejected, and the author
+is asked to pick or create a writable base first. New objects, fields, views, and
+flows are namespaced into that package — which is exactly what `os package publish`
+later ships. See [ADR-0070](https://github.com/objectstack-ai/framework/blob/main/docs/adr/0070-package-first-authoring.md).
+
+> Note: "package" here is the runtime **authoring base** (a `package_id`-bearing
+> container of metadata), distinct from the npm `@objectstack/*` packages listed in
+> the repo README.
+
## Overlay whitelist (shared-DB tenancy invariant)
In shared-database multi-tenancy, **most metadata types must not be per-org customizable** — overriding them would break the physical schema. The whitelist lives in **one** place: `MetadataTypeRegistryEntry.allowOrgOverride` in `packages/spec/src/kernel/metadata-plugin.zod.ts`.
diff --git a/content/docs/getting-started/core-concepts.mdx b/content/docs/getting-started/core-concepts.mdx
index 486135f776..5ec9a28fcb 100644
--- a/content/docs/getting-started/core-concepts.mdx
+++ b/content/docs/getting-started/core-concepts.mdx
@@ -137,7 +137,7 @@ This ensures ObjectStack apps can run on Node.js + PostgreSQL today, Python + SQ
| **Engine** | Enforces the logic | Compiles the `using` condition into a SQL `WHERE` clause |
-CRUD permissions (`allowRead`, `allowEdit`, …) are simple booleans — they grant or deny an operation. Record-level *conditional* access is a separate mechanism: [Row-Level Security](/docs/getting-started/architecture) policies, whose `using` clause is a SQL-like (PostgreSQL-compatible) predicate over context variables such as `current_user.role` and `current_user.id`.
+CRUD permissions (`allowRead`, `allowEdit`, …) are simple booleans — they grant or deny an operation. Record-level *conditional* access is a separate mechanism: [Row-Level Security](/docs/getting-started/architecture) policies, whose `using` clause is a SQL-like (PostgreSQL-compatible) predicate over context variables such as `current_user.roles` and `current_user.id`.
### Single Source of Truth
diff --git a/content/docs/guides/analytics-datasets.mdx b/content/docs/guides/analytics-datasets.mdx
index a0c3c0dbcf..e7208df35c 100644
--- a/content/docs/guides/analytics-datasets.mdx
+++ b/content/docs/guides/analytics-datasets.mdx
@@ -135,6 +135,11 @@ capability the inline single-object query could never reach:
// → revenue by account.region, joined + RLS-enforced per object.
```
+Joins follow **dotted relationship paths** and may traverse **multiple to-one hops**
+(ADR-0071) — e.g. `account.owner.region` walks the chain order → account → owner →
+region. The path is capped at **3 join hops (4 objects)** and is **to-one only**;
+to-many traversal is rejected (aggregate the many-side as its own measure instead).
+
## How it runs
A dataset compiles to the **Cube analytics runtime** (`IAnalyticsService`). The
diff --git a/content/docs/guides/auth-sso.mdx b/content/docs/guides/auth-sso.mdx
index ea0f2fe716..30ed253587 100644
--- a/content/docs/guides/auth-sso.mdx
+++ b/content/docs/guides/auth-sso.mdx
@@ -113,6 +113,12 @@ Enterprise packages can pass `oidcProviders` into `@objectstack/plugin-auth`
or contribute them through `auth:configure`. The open-source package does not
ship a generic OIDC settings UI.
+> **Per-environment external IdP (ADR-0069).** Recent releases add a
+> per-environment external-IdP path built on `@better-auth/sso` (a generic OIDC
+> relying party) and surface an `sso` flag in the public `/auth/config`
+> (`features.sso`) so a client can show an enterprise-login button when SSO is
+> configured. The `oidcProviders` extension below remains the in-process path.
+
### Quick start — Okta
```ts
diff --git a/content/docs/guides/cloud-deployment.mdx b/content/docs/guides/cloud-deployment.mdx
index c1cd211c0f..8025edf8b9 100644
--- a/content/docs/guides/cloud-deployment.mdx
+++ b/content/docs/guides/cloud-deployment.mdx
@@ -84,18 +84,11 @@ request — no restart, and no environment id to remember.
> install in one call: `os package publish --env --install`. This is for
> automation only — interactive installs happen in the environment Marketplace.
-> **Legacy env-revision path.** `os publish` posts compiled metadata straight to
-> an environment as a revision, rather than as a versioned package:
->
-> ```bash
-> OS_CLOUD_URL=https://cloud.example.com OS_ENVIRONMENT_ID=env_prod os publish
-> # POST /api/v1/cloud/environments/:environment/metadata
-> # rollback: POST /api/v1/cloud/environments/:environment/revisions/:commit/activate
-> ```
->
-> It still works, but the package flow above is the direction of travel
-> (ADR-0006 v4): `sys_environment_revision` is retired once all publishes go
-> through the package endpoints.
+> **Removed: the legacy env-revision path.** The direct-to-environment `os publish`
+> / `os rollback` commands (which wrote `sys_environment_revision`) were **removed**
+> (#2237, ADR-0006 v4). All publishing now goes through the package flow above
+> (`os package publish`); to change what an environment runs, install a package
+> version into it.
Cloud control-plane hosts, database provisioning, billing, and public SaaS
deployment are outside this framework repository. The framework runtime exposes
diff --git a/content/docs/guides/data-modeling.mdx b/content/docs/guides/data-modeling.mdx
index d403351099..6855e7f211 100644
--- a/content/docs/guides/data-modeling.mdx
+++ b/content/docs/guides/data-modeling.mdx
@@ -97,6 +97,28 @@ enable: {
---
+### Global search — `searchable` + `searchableFields`
+
+`searchable: true` includes an object's records in global search and the record
+picker. By default the search matches the name/title field plus short-text fields.
+To control exactly which fields are matched, set `searchableFields` on the object
+(ADR-0061):
+
+```typescript
+{
+ name: 'account',
+ searchable: true,
+ searchableFields: ['name', 'website', 'billing_city'],
+}
+```
+
+Queries then use the `$search` filter operator to match across `searchableFields`
+(e.g. `{ filters: { $search: 'acme' } }`); a view may narrow the set with
+`$searchFields`. When `searchableFields` is unset, search falls back to the
+name/title field plus short-text fields.
+
+---
+
## Field Types & Configuration
### Text Fields
diff --git a/content/docs/guides/metadata/object.mdx b/content/docs/guides/metadata/object.mdx
index 17150d9d74..2fdbc45947 100644
--- a/content/docs/guides/metadata/object.mdx
+++ b/content/docs/guides/metadata/object.mdx
@@ -203,7 +203,7 @@ indexes: [
| `active` | `boolean` | Is object active (default: `true`) |
| `isSystem` | `boolean` | System object, protected from deletion (default: `false`) |
| `abstract` | `boolean` | Abstract base, cannot be instantiated (default: `false`) |
-| `sharingModel` | `enum` | `'private'`, `'read'`, `'read_write'`, `'full'` |
+| `sharingModel` | `enum` | Org-Wide Default record visibility (ADR-0055/0056). Canonical: `'private'`, `'public_read'`, `'public_read_write'`, `'controlled_by_parent'` (detail visibility derived from its master). Legacy aliases: `'read'`=public_read, `'read_write'`/`'full'`=public_read_write |
| `keyPrefix` | `string` | Short prefix for record IDs (e.g. `'001'`) |
| `recordTypes` | `string[]` | Record type names for this object |
| `validations` | `ValidationRule[]` | Object-level validation rules (see [Validation](./validation)) |
diff --git a/content/docs/guides/metadata/page.mdx b/content/docs/guides/metadata/page.mdx
index ff451db43e..9569551a47 100644
--- a/content/docs/guides/metadata/page.mdx
+++ b/content/docs/guides/metadata/page.mdx
@@ -136,6 +136,7 @@ Components are the building blocks placed inside regions.
| `events` | `Record` | optional | Event handlers (action expressions) |
| `style` | `object` | optional | CSS styles |
| `className` | `string` | optional | CSS class names |
+| `responsiveStyles` | `object` | optional | **Preferred** SDUI styling channel (ADR-0065): per-breakpoint scoped CSS-property maps keyed by `xs`/`sm`/`md`/`lg`/`xl`/`2xl`, compiled to id-scoped CSS at render. Prefer design tokens, e.g. `{ base: { padding: 'var(--space-6)' }, md: { padding: 'var(--space-8)' } }`. Use over ad-hoc `style`/`className` for metadata-authored pages. |
| `visibility` | `string` | optional | Visibility predicate (CEL expression) |
The `type` field is a union of the standard `PageComponentType` enum and any custom string. The standard (namespaced) component types include:
diff --git a/content/docs/guides/metadata/permission.mdx b/content/docs/guides/metadata/permission.mdx
index 6b6460e810..c602b86e22 100644
--- a/content/docs/guides/metadata/permission.mdx
+++ b/content/docs/guides/metadata/permission.mdx
@@ -195,8 +195,13 @@ contextVariables: {
```
The built-in context variables available in RLS `using`/`check` clauses include
-`current_user.id`, `current_user.organization_id`, `current_user.department`,
-`current_user.role`, and `current_user.region`.
+`current_user.id`, `current_user.organization_id`, and `current_user.roles`
+(ADR-0068). `roles` is a **string array** — the only canonical role field — so test
+membership with CEL: `'org_admin' in current_user.roles` or
+`current_user.roles.exists(r, r == 'sales_manager')`. The framework-seeded built-in
+role names are `platform_admin`, `org_owner`, `org_admin`, and `org_member`.
+(`current_user.isPlatformAdmin` is a derived, deprecated alias of
+`'platform_admin' in current_user.roles`.)
## Profile vs. Permission Set
diff --git a/content/docs/guides/publish-and-preview.mdx b/content/docs/guides/publish-and-preview.mdx
index c240dede90..2a8198e9dd 100644
--- a/content/docs/guides/publish-and-preview.mdx
+++ b/content/docs/guides/publish-and-preview.mdx
@@ -1,20 +1,28 @@
---
title: Publish, Versioning & Preview
-description: Compile metadata, publish it to a Cloud environment, and activate or roll back revisions.
+description: Compile metadata into an artifact, publish it as a versioned package to your Cloud catalog, optionally install it into an environment, and preview locally.
---
# Publish, Versioning & Preview
-ObjectStack treats compiled metadata as an immutable environment artifact. The
-local loop is:
+ObjectStack treats compiled metadata as an immutable artifact. The local loop is:
```text
-objectstack.config.ts -> os compile -> dist/objectstack.json -> os publish -> Cloud environment revision
+objectstack.config.ts -> os compile -> dist/objectstack.json -> os package publish -> Cloud package version (optionally installed into an environment)
```
-The framework CLI owns compile/publish/rollback commands. The Cloud control
-plane that stores revisions and serves them to runtime nodes lives outside this
-framework repo.
+The framework CLI owns `compile` and `package publish`. The Cloud control plane
+that stores package versions, installs them into environments, and serves them to
+runtime nodes lives outside this framework repo.
+
+
+The legacy direct-to-environment `os publish` / `os rollback` commands (which wrote
+`sys_environment_revision`) were **removed** (#2237). Publishing now goes through the
+**package catalog**: `os package publish` uploads a versioned package, and an
+environment is updated by **installing** a version into it. Revision-style rollback
+is no longer a framework CLI command — version and environment management are a
+Cloud control-plane concern.
+
---
@@ -25,75 +33,58 @@ os compile
# -> dist/objectstack.json
```
-The artifact contains metadata, manifest requirements, and packaged function
-code. Deployment config stays outside the artifact: database URLs, secrets,
-runtime credentials, and environment identity are host inputs.
+The artifact contains metadata, manifest requirements, and packaged function code.
+Deployment config stays outside the artifact: database URLs, secrets, runtime
+credentials, and environment identity are host inputs.
---
-## 2. Publish
+## 2. Publish a package version
```bash
-OS_CLOUD_URL=https://cloud.example.com \
-OS_ENVIRONMENT_ID=env_prod \
-os publish
-```
-
-Common inputs:
-
-| Input | Env var | Purpose |
-|:---|:---|:---|
-| `--server`, `-s` | `OS_CLOUD_URL` | Cloud control-plane URL |
-| `--environment`, `-e` | `OS_ENVIRONMENT_ID` | Target environment id |
-| `--token`, `-t` | `OS_CLOUD_API_KEY` | Bearer token when required |
-| `--timeout` | `OS_CLOUD_TIMEOUT_MS` | Request timeout |
+# upload dist/objectstack.json as a new version in your org catalog
+os package publish
-The CLI posts the compiled JSON to:
-
-```text
-POST /api/v1/cloud/environments/:environment/metadata
+# explicit artifact + install into an environment in one step
+os package publish ./dist/objectstack.json --env env_prod --install
```
-The response includes the environment id, commit id, and checksum for the newly
-published revision.
-
----
+The CLI:
-## 3. Activate or roll back
+1. `POST /api/v1/cloud/packages` — ensure a `sys_package` row exists (id derived from `artifact.manifest.id`, or `--manifest-id`).
+2. `POST /api/v1/cloud/packages/:id/versions` — snapshot `dist/objectstack.json` into `sys_package_version.manifest_json` (status `published`).
+3. (optional) install the new version into `--env`.
-To activate a previous commit:
+Common flags:
-```bash
-OS_CLOUD_URL=https://cloud.example.com \
-OS_ENVIRONMENT_ID=env_prod \
-os rollback --commit 9ce1bd48dd7022b8
-```
-
-The CLI calls:
-
-```text
-POST /api/v1/cloud/environments/:environment/revisions/:commit/activate
-```
-
-Runtime hosts can then refresh the environment kernel using the active
-commit/checksum.
+| Flag | Env var | Purpose |
+|:---|:---|:---|
+| `artifact` (positional) | — | Path to the compiled artifact (default `dist/objectstack.json`) |
+| `--server`, `-s` | `OS_CLOUD_URL` | Cloud control-plane URL |
+| `--token`, `-t` | `OS_CLOUD_API_KEY` | Bearer token (service mode) |
+| `--version`, `-v` | — | Semver version (default: `artifact.manifest.version`) |
+| `--visibility` | — | `org` (default) · `private` · `marketplace` |
+| `--org` | `OS_ORG_ID` | Owner org id (service mode) |
+| `--env` | `OS_ENVIRONMENT_ID` | Environment to install the new version into |
+| `--install` | — | Auto-install the new version into `--env` after publishing |
+
+In user mode the package is owned by your active organization; in service mode
+(bearer key) pass `--org`. See [Packages](./packages) for the package model and the
+[Cloud Environment Artifact API](../concepts/cloud-artifact-api) for the
+control-plane endpoints.
---
-## 4. Package publish
-
-Packages are separate from environment revisions:
-
-```bash
-os package publish --env env_prod
-```
+## 3. Install / update an environment
-Package publish targets the Cloud package registry endpoints, while
-`os publish` targets an environment revision.
+An environment is updated by **installing a package version** into it — either at
+publish time with `--env --install`, or separately via the Cloud control plane /
+Marketplace. To "roll back," install the prior version; there is no
+revision-activate CLI command anymore.
---
-## 5. Preview patterns
+## 4. Preview patterns
Use one of these shapes:
@@ -101,12 +92,13 @@ Use one of these shapes:
|:---|:---|
| Local artifact preview | `os dev --artifact ./dist/objectstack.json --ui` |
| Production artifact host | `OS_ARTIFACT_PATH=./dist/objectstack.json os start` |
-| Cloud environment preview | Publish to a preview environment id, then route clients to that environment via `/api/v1/environments/:environmentId/...` or `X-Environment-Id`. |
+| Cloud environment preview | Install to a preview environment, then route clients to it via `/api/v1/environments/:environmentId/...` or `X-Environment-Id`. |
---
## Related
+- [Packages](./packages)
- [Deployment Modes](./cloud-deployment)
- [Environment-Scoped Routing](./project-scoping)
- [Cloud Environment Artifact API](../concepts/cloud-artifact-api)
diff --git a/content/docs/guides/security.mdx b/content/docs/guides/security.mdx
index 2392282ccb..6765d5de50 100644
--- a/content/docs/guides/security.mdx
+++ b/content/docs/guides/security.mdx
@@ -148,6 +148,27 @@ RLS (no compiler change; ADR-0055). Sharing rules still widen on top.
> resolver); without it they **fail closed to `own`** (never fail-open), and
> `defineStack` errors if a grant uses one without `requires: ['hierarchy-security']`.
+### Capabilities & secure-by-default object access (ADR-0066)
+
+Beyond CRUD grants and scope depth, two newer gates compose with the model above:
+
+- **Capabilities** are first-class records in the `sys_capability` registry (ADR-0066 D1) — maintainable named privileges such as `manage_metadata`, `manage_users`, `manage_org_users`, `manage_platform_settings`, `setup.access`, and `studio.access`. Grant them through permission sets like any other privilege.
+- **Object access posture** — an object may declare `access: { default: 'public' | 'private' }` (ADR-0066 D2). `public` (the default) preserves allow-by-default exposure; `private` makes the object **secure-by-default** (no access unless explicitly granted).
+- **Object-level `requiredPermissions`** (ADR-0066 D3) — a string array of capabilities that gate the object as an **AND** alongside CRUD grants (mirrors `App.requiredPermissions`): a user must hold every listed capability *and* the relevant CRUD grant.
+
+### Built-in identity roles (ADR-0068)
+
+`current_user.roles` is a **string array** — the only canonical role field (there is no singular `current_user.role`). Four role names are framework-seeded into `sys_role`:
+
+| Role | Meaning |
+|:---|:---|
+| `platform_admin` | Platform operator (SaaS admin) — not a tenant role |
+| `org_owner` | Organization owner (`sys_member.role = owner`) |
+| `org_admin` | Organization administrator (`sys_member.role = admin`) |
+| `org_member` | Organization member (`sys_member.role = member`) |
+
+Test membership in RLS/CEL with `'org_admin' in current_user.roles` or `current_user.roles.exists(r, r == 'sales_manager')`. `current_user.isPlatformAdmin` is a derived, deprecated alias of `'platform_admin' in current_user.roles`.
+
### Standard Profiles
#### Sales Representative
diff --git a/content/docs/protocol/objectos/index.mdx b/content/docs/protocol/objectos/index.mdx
index 73c1d4efdf..a1fda7e072 100644
--- a/content/docs/protocol/objectos/index.mdx
+++ b/content/docs/protocol/objectos/index.mdx
@@ -126,8 +126,8 @@ Traditional enterprise platforms tightly couple infrastructure concerns with bus
**ObjectOS Approach:**
```bash
-# Publish a compiled artifact to ObjectStack Cloud
-os publish dist/objectstack.json --environment
+# Publish a compiled artifact as a versioned package to ObjectStack Cloud
+os package publish dist/objectstack.json --env --install
# ✓ Validated dependencies
# ✓ Applied schema changes
# ✓ Updated configuration
@@ -368,7 +368,7 @@ permissions:
```
### Idempotent Operations
-Run `os publish` 100 times → Same result.
+Run `os package publish` 100 times → Same result.
- Installing a plugin twice does nothing (it's already installed)
- Applying same configuration twice doesn't duplicate settings
- Schema migrations are versioned (run once, skip if already applied)
@@ -481,7 +481,7 @@ const message = context.i18n.t('slack.button.send');
| **i18n** | Built-in engine | Manual (libraries) | Manual | Manual |
| **Dependency Resolution** | Semantic versioning | Manual (YAML) | Manual | Manual |
| **Zero-Downtime Upgrades** | Declarative | Rolling updates | Blue-green | Git push |
-| **Developer UX** | `os publish` | `kubectl apply` | `cf push` | `git push heroku` |
+| **Developer UX** | `os package publish` | `kubectl apply` | `cf push` | `git push heroku` |
**Key Differentiator:** ObjectOS is **application-aware**. Kubernetes knows about containers, not plugins. ObjectOS knows about ObjectQL objects, ObjectUI views, and business logic dependencies.
diff --git a/content/docs/protocol/objectos/lifecycle.mdx b/content/docs/protocol/objectos/lifecycle.mdx
index d275f33e6b..04cc1a985d 100644
--- a/content/docs/protocol/objectos/lifecycle.mdx
+++ b/content/docs/protocol/objectos/lifecycle.mdx
@@ -543,17 +543,14 @@ If upgrade fails, ObjectOS **automatically rolls back** to previous version.
#### Manual Rollback
-`os rollback` activates a previously published artifact revision —
-the cloud equivalent of "switch back to yesterday's build". It does not run
-DDL or undo schema migrations.
-
-```bash
-# Activate a specific revision (commit) for an environment
-os rollback --environment --commit
-
-# Environment can also be supplied via OS_ENVIRONMENT_ID
-OS_ENVIRONMENT_ID= os rollback --commit
-```
+To switch an environment back to a previous build, **install the prior package
+version** into it (via the Cloud control plane / Marketplace, or
+`os package publish --env --install`). This is the cloud
+equivalent of "switch back to yesterday's build"; it does not run DDL or undo
+schema migrations.
+
+> The legacy revision-activate `os rollback` CLI was removed (#2237); environment
+> version management now goes through package install.
For schema rollback, run the `down()` of your generated migration through
whatever Knex / driver tooling your team uses to apply the `up()`.
diff --git a/content/docs/protocol/objectql/index.mdx b/content/docs/protocol/objectql/index.mdx
index 996f1bc969..89004b19ce 100644
--- a/content/docs/protocol/objectql/index.mdx
+++ b/content/docs/protocol/objectql/index.mdx
@@ -254,7 +254,7 @@ fields:
```bash
# Publish the updated metadata
-os publish
+os package publish
```
**What happens:**
diff --git a/content/docs/protocol/objectql/schema.mdx b/content/docs/protocol/objectql/schema.mdx
index a55b9388cd..a3ddb0752d 100644
--- a/content/docs/protocol/objectql/schema.mdx
+++ b/content/docs/protocol/objectql/schema.mdx
@@ -676,11 +676,11 @@ os build
# 3. Compare two configs to detect breaking changes
os diff ./before.json ./after.json
-# 4. Publish the compiled artifact to ObjectStack Cloud
-os publish
+# 4. Publish the compiled artifact as a versioned package to ObjectStack Cloud
+os package publish
-# 5. Roll back / forward to a previously published revision
-os rollback --commit
+# 5. Roll back / forward by installing a prior package version
+os package publish ./before.json --env --install
```
## Best Practices
diff --git a/docs/adr/0061-record-search-architecture.md b/docs/adr/0061-record-search-architecture.md
index 08bfe1e3ac..a22f44b56a 100644
--- a/docs/adr/0061-record-search-architecture.md
+++ b/docs/adr/0061-record-search-architecture.md
@@ -1,6 +1,6 @@
# ADR-0061: Record Search Architecture — metadata-driven `$search` resolution
-**Status**: Proposed — recommended for acceptance; nothing implemented yet (2026-06-21)
+**Status**: Proposed — recommended for acceptance (2026-06-21). **Tier 1 (`$search` + `object.searchableFields`) has since been implemented & is live; Tier 2 (FTS/relevance) deferred — header pending formal update.**
**Deciders**: ObjectStack Protocol Architects
**Builds on**: ADR-0045 (additive materialization & visibility gate — search must be visibility-aware), ADR-0049 (enforce-or-remove / no unenforced declaration), ADR-0054 (runtime proof per enforced surface), ADR-0060 (conformance ledger as a platform pattern)
**Consumers**: spec, objectql, driver-sql, driver-memory, driver-mongodb, rest, objectui (`fields`, `plugin-list`, `app-shell`), verify, dogfood
diff --git a/docs/adr/0071-dataset-semantic-layer-depth.md b/docs/adr/0071-dataset-semantic-layer-depth.md
index d19771941f..aa57456b7d 100644
--- a/docs/adr/0071-dataset-semantic-layer-depth.md
+++ b/docs/adr/0071-dataset-semantic-layer-depth.md
@@ -4,7 +4,7 @@
Proposed. (Refocused — see **Correction** below. The first merged draft also
proposed matrix/across pivoting; a code check found that already implemented, so
-this ADR now covers only the remaining gap: multi-hop joins.)
+this ADR now covers only the remaining gap: multi-hop joins.) **Multi-hop to-one joins (≤3 hops / 4 objects) have since been implemented & are live — header pending formal update.**
## Correction (2026-06-24)
diff --git a/skills/objectstack-platform/SKILL.md b/skills/objectstack-platform/SKILL.md
index 440cc7601a..258a86e2ae 100644
--- a/skills/objectstack-platform/SKILL.md
+++ b/skills/objectstack-platform/SKILL.md
@@ -1158,7 +1158,7 @@ Port resolution is the same for `os dev` and `os start` (both spawn `os serve`):
| `os data export` / `import` | Bulk import / export records as JSONL |
| `os diff` | Show schema diff between local and target environment |
| `os meta apply` | Apply metadata + data migrations to the target |
-| `os rollback` | Roll back the most recent migration batch |
+| `os migrate plan` / `os migrate apply` | Dry-run / apply physical-DB drift reconciliation from metadata (forward-only — no batch rollback; `os rollback` was removed) |
## Environments & deploy
@@ -1166,7 +1166,6 @@ Port resolution is the same for `os dev` and `os start` (both spawn `os serve`):
|:--------|:-------------|
| `os login` / `logout` / `whoami` | Auth against the ObjectStack cloud control plane |
| `os environments list` / `create` / `switch` | Manage cloud environments (prod/staging/dev) |
-| `os publish` | Push the compiled stack to a cloud environment |
| `os register` | Register the local stack as a deployable target |
| `os cloud …` | Cloud-specific subcommands (logs, metrics, status) |
| `os package publish [dist/objectstack.json] [--env … --install --visibility org]` | Upload the compiled artifact as a versioned package to the cloud catalog (ADR-0008 P3) |