Skip to content

Commit 90849be

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-24186-mcp-verifier-jwks-seam
2 parents 6902fdd + b9ac35c commit 90849be

34 files changed

Lines changed: 1561 additions & 1373 deletions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
'@objectstack/spec': patch
4+
---
5+
6+
`sys_organization` now declares an `invite_user` action at `record_header`, so an organization record page can offer "Invite User" as its primary header button. It calls `/api/v1/auth/organization/invite-member` with the record's id as `organizationId`, asks for `email` and `role` (the role picker offers only the roles the caller may grant), and is gated like the other three invite mirrors: the `organization` capability and the owner / admin / delegated_admin grades. Its `order: -1` puts it first in the header.
7+
8+
`leave_organization` keeps `variant: 'danger'` and now declares `order: 1`, so it sorts last among the header actions and folds into the `⋯` overflow menu instead of taking the third inline slot. Its confirmation now names what is lost: the organization's environments and members (en, zh-CN, ja-JP and es-ES).
9+
10+
`@objectstack/spec` books the new action in `PUBLIC_AUTH_FEATURES.organization.gatedInputs`, beside the other three invite mirrors.
11+
12+
Clause-②: no
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/objectql': patch
3+
'@objectstack/cloud-connection': patch
4+
---
5+
6+
Clause-②: no
7+
8+
fix(objectql): withdrawing a package that extends another package's object puts the owner's definition back at `GET /api/v1/meta/object/NAME` at once, not at the next restart
9+
10+
- **What was wrong.** When a package whose content is an `objectExtensions` field on another package's object is registered on a started kernel, the ObjectQL bridge rewrites the OWNER's copy of that object in the `metadata` service with the merged body, extension included. `DELETE /api/v1/marketplace/install-local/:manifestId` of the extender withdrew its contribution from the registry, so the object listing and the data plane dropped the field, but nothing rewrote the owner's copy. The by-name read asks that copy first, so `GET /api/v1/meta/object/NAME` kept serving the withdrawn field until the runtime restarted.
11+
- **What changes.** The ObjectQL bridge remembers which owners' copies each package's extensions rewrote, and the `manifest` service gains `restoreExtendedObjectCopies(packageId)`: once the registry no longer holds the package, it re-registers each such copy with the registry's current definition. The install-local DELETE calls it right after the registry withdrawal. The by-name read then serves the owner's body without the extension's fields, as the listing and the data plane already did.
12+
- **Not touched.** Only a copy stamped with the registry owner's id is rewritten, the same rule the bridge overwrites by, so an authored copy stays. The DELETE answer is unchanged. A copy that cannot be restored is logged once at `error`, naming the objects and the remedy: restart the runtime.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/spec": minor
3+
"@objectstack/core": patch
4+
"@objectstack/service-print": patch
5+
---
6+
7+
feat(spec): `AuthSessionApi.getSession`'s result declares the fields its in-process readers read
8+
9+
Clause-②: yes (widening)
10+
11+
- **`@objectstack/spec/contracts` — `AuthSessionApi.getSession`'s result gains five optional members**, each declared for a named reader and typed as that reader takes it: `user.email` and `session.id` / `session.token` (read by `resolveAuthzContext`'s session arm in `@objectstack/core`), `user.authGate` as `unknown` (the ADR-0069 posture, which `normalizeAuthGate` validates against the closed posture vocabulary), and `session.impersonatedBy` as `string | null` (read by the print door's `impersonatorOf` in `@objectstack/service-print`). Before this, those reads went through `any` or a cast, so a field better-auth dropped or renamed compiled and read `undefined`. For `impersonatedBy`, that would have silently turned off the impersonation refusal. Every member is optional, so every implementer and caller typechecks unchanged.
12+
- **`@objectstack/core`**: `resolveAuthzContext`'s session arm reads the session through the declared type instead of `any`. `ResolveAuthzInput.getSession`'s own type is unchanged. Runtime behaviour is unchanged.
13+
- **`@objectstack/service-print`**: `impersonatorOf` reads `session.impersonatedBy` through the declared type instead of a cast. Runtime behaviour is unchanged.

‎.github/workflows/board-snapshot.yml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ on:
152152
# platform-checklist watchdog at :51 — 44 minutes after this run starts —
153153
# plus CodeQL on Mondays. `4,10,16,22` was the obvious alternative and is
154154
# worse on the same measurement: it drops an 800-request run into the busiest
155-
# scheduled hour on this board (04:00 rerun-safety, 04:19 release-coverage
156-
# patrol, 04:23 required-set patrol, 04:37 branch reaper on Mondays, 04:41
157-
# create-smoke) and shares hour 16 with the required-set patrol.
155+
# scheduled hour on this board (04:19 release-coverage patrol, 04:23
156+
# required-set patrol, 04:37 branch reaper on Mondays, 04:41 create-smoke)
157+
# and shares hour 16 with the required-set patrol.
158158
#
159159
# The minute is off the top of the hour on purpose, as in every patrol here:
160160
# scheduled workflows queue behind everyone else's :00 cron.

‎.github/workflows/ci.yml‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,24 @@ jobs:
828828
pnpm turbo run build "--filter=$PKG" --concurrency=4 --log-order=stream
829829
done < "$RUNNER_TEMP/shard-packages.txt"
830830
831+
# ── Test leftovers, step 1 of 2: the snapshot (#23880, ruling 乙) ──────
832+
#
833+
# REPORT ONLY, never a gate; the rationale, the listing and the closed
834+
# exclusion list are in the `scripts/ci/report-test-leftovers.mjs` header.
835+
# Taken HERE, after both dependency-closure builds above and before the
836+
# tests, so the report after the tests can tell what the test run added
837+
# from what the builds wrote. A package's OWN build (a test task that
838+
# turbo.json makes depend on `build` without `^`) still runs inside the
839+
# test step; the report excludes its declared outputs, read from
840+
# turbo.json on every run. The snapshot goes to $RUNNER_TEMP, outside the
841+
# tree, or the report would count it.
842+
#
843+
# ⛔ No `if:` and no `continue-on-error`: the script exits 0 on every
844+
# path, by construction (a failure prints one NOT MEASURED warning), so
845+
# this step cannot fail the shard or withhold its attestation.
846+
- name: Snapshot the working tree before this shard's tests
847+
run: node scripts/ci/report-test-leftovers.mjs snapshot --out "$RUNNER_TEMP/test-leftovers/before.json"
848+
831849
# --concurrency=4: turbo's default (10) oversubscribes the 4-vCPU
832850
# hosted runner; matching the core count bounds peak memory and the
833851
# job is CPU-bound anyway.
@@ -1056,6 +1074,27 @@ jobs:
10561074
done
10571075
exit $STATUS
10581076
1077+
# ── Test leftovers, step 2 of 2: the report (#23880, ruling 乙) ────────
1078+
#
1079+
# Every path this shard's test run ADDED to the working tree since the
1080+
# snapshot, ignored paths included -- `.objectstack/` is gitignored, so
1081+
# `git status` cannot see that class -- grouped by package directory: a
1082+
# table in the job summary and one `::warning::` annotation per package.
1083+
# Placed directly after the test step so no later step's writes are
1084+
# charged to the tests, and `if: always()` so a red shard still reports.
1085+
#
1086+
# ⛔ REPORT ONLY by ruling, never a gate: the script exits 0 on findings,
1087+
# on a missing snapshot and on a crash, so the step carries no
1088+
# `continue-on-error` and cannot fail the shard. Making it block is the
1089+
# maintainer's word, not an edit here. It stays ABOVE the attestation
1090+
# pair at the bottom of the job (#6082), like every step after the tests.
1091+
- name: Report what this shard's tests left in the working tree
1092+
if: always()
1093+
run: |
1094+
node scripts/ci/report-test-leftovers.mjs report \
1095+
--before "$RUNNER_TEMP/test-leftovers/before.json" \
1096+
--label "Test Core (${{ matrix.shard }}/6)"
1097+
10591098
# --summarize above costs nothing at runtime and writes
10601099
# `.turbo/runs/<id>.json`: one per-task record with the execution window
10611100
# turbo actually observed. That file IS the balancing input for the next
@@ -2106,6 +2145,13 @@ jobs:
21062145
--report-dir "$RUNNER_TEMP/stall-reports" -- \
21072146
pnpm turbo run build --filter=@objectstack/dogfood --concurrency=4 --log-order=stream
21082147
2148+
# Test leftovers, step 1 of 2 (#23880, ruling 乙): the snapshot, after the
2149+
# closure build and before the tests. Report only; the same pair as Test
2150+
# Core's, whose comments carry the rationale. `dogfood#test` depends on
2151+
# `^build` alone, so the step above builds everything the tests need.
2152+
- name: Snapshot the working tree before the dogfood tests
2153+
run: node scripts/ci/report-test-leftovers.mjs snapshot --out "$RUNNER_TEMP/test-leftovers/before.json"
2154+
21092155
# Boots real example apps in-process (in-memory SQLite) and exercises them
21102156
# through the real HTTP + service stack — catches runtime regressions that
21112157
# build / unit tests / spec-liveness pass over (e.g. the #2018 tz-bucketing
@@ -2147,6 +2193,16 @@ jobs:
21472193
--report-dir "$RUNNER_TEMP/stall-reports" -- \
21482194
pnpm turbo run test --filter=@objectstack/dogfood --log-order=stream
21492195
2196+
# Test leftovers, step 2 of 2 (#23880, ruling 乙): what the dogfood test
2197+
# run added to the working tree. Report only -- exits 0 on every path, no
2198+
# `continue-on-error` -- and `if: always()`; see Test Core's pair.
2199+
- name: Report what the dogfood tests left in the working tree
2200+
if: always()
2201+
run: |
2202+
node scripts/ci/report-test-leftovers.mjs report \
2203+
--before "$RUNNER_TEMP/test-leftovers/before.json" \
2204+
--label "Dogfood Regression Gate (${{ matrix.shard }}/3)"
2205+
21502206
# Dogfood boots real apps in-process, so a native/OOM abort is likelier
21512207
# here than in the unit suites — and a shard that dies silently looks like
21522208
# a shard that had less work.

‎.github/workflows/docs-deploy.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ on:
5252
# The HOURS keep out of this repository's crowded scheduled windows, read
5353
# from `grep -rn 'cron:' .github/workflows/` on the day this landed: 01–05
5454
# UTC carry most of the nightlies (stale, CodeQL, validate-deps,
55-
# rerun-safety, coverage, the release-coverage and required-set patrols,
56-
# the smokes and nightly tiers), 07 carries showcase-smoke, and the board
55+
# coverage, the release-coverage and required-set patrols, the smokes and
56+
# nightly tiers), 07 carries showcase-smoke, and the board
5757
# snapshot owns :07 of 02, 08, 14 and 20. Of the six six-hour sets, only
5858
# 0/6/12/18 and 1/7/13/19 have hours with nothing scheduled after :00; the
5959
# first is taken because its :00 neighbours are short (release.yml's

‎.github/workflows/lint.yml‎

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3728,6 +3728,23 @@ jobs:
37283728
continue-on-error: true
37293729
run: node scripts/report-test-timings.mjs --self-test
37303730

3731+
# The test-leftover report's own instrument (#23880, ruling 乙). ci.yml's
3732+
# test jobs run `scripts/ci/report-test-leftovers.mjs snapshot` / `report`,
3733+
# which exit 0 on every path BY RULING -- report only, never a gate -- so
3734+
# nothing there can go red when the report stops seeing what it exists to
3735+
# see: an ignored path a test added. This self-test is where that breaks
3736+
# loudly: fixture snapshots for the diff, the closed exclusion list and the
3737+
# turbo.json own-build derivation, plus a real throwaway git tree that
3738+
# proves the listing includes IGNORED paths and that every in-job failure
3739+
# is a warning with exit 0. It also loads the script on every pull
3740+
# request, the one breakage its in-job modes cannot catch about
3741+
# themselves. Invoked as `node` per the GATE INVOCATION IDIOM note at the
3742+
# top of this file. Offline; about a second.
3743+
- name: Test-leftover report self-test
3744+
id: test-leftover-report-self-test
3745+
continue-on-error: true
3746+
run: node scripts/ci/report-test-leftovers.mjs --self-test
3747+
37313748
# The per-package suite-duration ratchet's own instrument (#16468). The
37323749
# gate runs in ci.yml's `Test Core` aggregator, where a clean tree with
37333750
# every suite under its ceiling reads OK whether or not the over-ceiling,
@@ -5184,28 +5201,6 @@ jobs:
51845201
continue-on-error: true
51855202
run: pnpm check:stall-guard-budget
51865203

5187-
# The `Rerun Safety` verdict table (#18590) — self-test half only, and the
5188-
# asymmetry is the same one the step below explains: the measurement half
5189-
# takes two log paths and two exit codes that exist only inside that
5190-
# nightly job, so there is nothing here for a bare invocation to read.
5191-
#
5192-
# ⭐ It is wired HERE rather than left in the nightly deliberately.
5193-
# `rerun-safety-nightly.yml` declares `schedule` and `workflow_dispatch`
5194-
# and no PR-time event, so a gate family reachable only from it would be
5195-
# this tree's first SCHEDULED-ONLY family — which `check:pm-dispatch-gates`
5196-
# refuses by name, on the ground that a board sweep must not be routed into
5197-
# a per-PR gate list.
5198-
#
5199-
# WHAT REDDENS IT: its own script's parsing rules and verdict table. Those
5200-
# are matching rules, so their production verdict is identical before and
5201-
# after they break (see `check-self-test-wired.mjs`) — this step is the
5202-
# only instrument watching them. Reads nothing but its own fixtures; no
5203-
# build, no network, no token, sub-second.
5204-
- name: Rerun-safety verdict table self-test
5205-
id: rerun-safety-verdict-table-self-test
5206-
continue-on-error: true
5207-
run: pnpm check:rerun-safety-verdict
5208-
52095204
# Rationale: `scripts/measure-stall-guard-headroom.mjs` header (#13246, #13121).
52105205
# ⛔ `--self-test` only: never append a bare run (it needs a token).
52115206
- name: Stall-guard headroom self-test (self-test half only, never the measurement)

‎.github/workflows/prerelease-pin-watch.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ name: Prerelease Pin Watch
5757

5858
on:
5959
schedule:
60-
# 06:00 UTC nightly — after Rerun Safety (04:00) and Spec Coverage (05:00),
61-
# before Showcase Smoke (07:00). Nightly, not weekly: see the note above.
60+
# 06:00 UTC nightly — after Spec Coverage (05:00), before Showcase Smoke
61+
# (07:00). Nightly, not weekly: see the note above.
6262
- cron: '0 6 * * *'
6363
workflow_dispatch:
6464
pull_request:

0 commit comments

Comments
 (0)