Skip to content

Commit 6c1589e

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-24844-google-env-credentials-save
2 parents e66a252 + 81120ca commit 6c1589e

16 files changed

Lines changed: 1226 additions & 138 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@objectstack/plugin-approvals': patch
3+
---
4+
5+
fix(plugin-approvals): a reminder's `notified` counts each approver address once, not once per slate slot
6+
7+
Clause-②: no
8+
9+
`POST /api/v1/approvals/requests/:id/remind` (`ApprovalService.remind()`) answers `notified` as the number of reminders it handed to messaging: one per distinct approver address on the pending slate. A `per_group` slate lists a person once per group they resolved into, and `pending_approvers` keeps every one of those slots until the first vote, so a person placed in two groups was counted twice while messaging delivered them one reminder. They are now reminded once and counted once, the rule the opening `approval.requested` notice already applies.
10+
11+
A user id and the same account's email are still two addresses: the person holds two slots and receives two reminders, exactly as at the opening. Unchanged: who is reminded, each reminder's topic, payload, deep link and dedup key, the throttle, the submitter check, the `remind` audit row, and `position:*`-style literals, which still notify no one and add nothing to the count.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/plugin-auth': patch
3+
---
4+
5+
fix(plugin-auth): a refused OAuth application registration answers the status the refusal declared, not 500 (#24773)
6+
7+
Clause-②: no
8+
9+
`POST /api/v1/auth/sys-oauth-application/register` answered most refusals from better-auth as `500 OAUTH_REGISTER_FAILED`. better-auth raises each refusal as an `APIError` whose HTTP status is the number `statusCode` (`400`) and the name `status` (`'BAD_REQUEST'`). The route read only a numeric `status`, so a named refusal fell through to 500. Two examples are a redirect URI the provider refuses, such as `http://localhost:4001/callback` on a `web` client (`invalid_redirect_uri`), and a request with no session (`UNAUTHORIZED`).
10+
11+
- **Now.** The route answers the refusal's own status: `400` for the redirect-URI refusal and `401` for the missing session. The code stays `OAUTH_REGISTER_FAILED`, and `error.details.upstreamError` still carries the provider's discriminator (`invalid_redirect_uri`).
12+
- **Unchanged.** A throw that declares no status, such as a storage fault while the client is persisted, still answers `500`. The body-schema refusal keeps answering `400`. Which redirect URIs a client may register is unchanged: a `web` client still needs an `https` URI on a non-loopback host.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@objectstack/plugin-audit': patch
3+
---
4+
5+
fix(plugin-audit): an @mention notification reaches only mentioned users who can read the comment's record
6+
7+
Clause-②: no (narrows who a notification reaches; no key, route or payload shape is added)
8+
9+
- **Recipients are judged by read access to the record.** The `sys_comment` mention writer now resolves each `mentions` entry to a user and asks, in that user's own envelope, whether they can read the record named by the comment's `thread_id`. The envelope comes from the resolver every request uses (`resolveUserAuthzGrants`). The user's organization claim is vetted under the tenancy posture in force (`vetOrganizationClaim`). The read goes through the evaluator every parent-derived read gate uses (`resolveReadableParentIds`). So the tenant wall, sharing, RLS and object permissions decide, as they do when that user opens the deep link. A user who cannot read the record gets no notification, and a `warn` line records their id and the reason (never the comment text).
10+
- **Email entries resolve to a user first.** An email-shaped mention is looked up to its user and then checked like an id. An email that matches no user notifies nobody. Entries that expand an audience (`role:`, `team:`, `owner_of:`) name no single person and are no longer mentions.
11+
- **Fail closed.** A comment whose thread names no record, a record that cannot be found, and a grant resolution that fails all withhold the notification. `installAuditWriters` takes the gate as `admitMentionRecipients`, and `AuditPlugin` wires it. A host that calls `installAuditWriters` without one emits no mention notifications and is told so once at `warn`.

‎docs/qa/platform-checklist/areas/platform-core.json‎

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@
416416
"title": "Metadata authoring round-trip: draft → publish on a WRITABLE package; read-only packages and locked types are server-side refused",
417417
"since": "v16",
418418
"status": "active",
419-
"revision": 4,
419+
"revision": 5,
420420
"priority": "P1",
421421
"surface": "mixed",
422422
"personas": ["seeded admin (admin@objectos.ai / admin123)"],
@@ -452,7 +452,7 @@
452452
{
453453
"clause": "Studio's designer authors through the same pipeline: creating a record page issues PUT /api/v1/meta/page/<name> bound to its object and seeded from the default layout",
454454
"oracle": "network",
455-
"verify": "capture the PUT during Studio create. ⚠ Drive it by hand: the pin (objectui e2e/live/studio-record-page.spec.ts, which waits on exactly that request) is STALE against the current surface — it fills the Object control as an input when it is now a role=combobox button — see automated.stale",
455+
"verify": "capture the PUT during Studio create (pinned by objectui e2e/live/studio-record-page.spec.ts, which waits on exactly that request and asserts its body — see automated.ref)",
456456
"evidence": "the captured PUT"
457457
},
458458
{
@@ -482,16 +482,7 @@
482482
"traps": ["dispatcher-vs-hono-route", "stale-console-bundle"],
483483
"automated": {
484484
"kind": "api",
485-
"ref": "packages/qa/dogfood/test/package-first-authoring.dogfood.test.ts; objectui: e2e/live/studio-record-page.spec.ts, e2e/live/studio-object-designer.spec.ts",
486-
"stale": {
487-
"since": "2026-08-11",
488-
"observedIn": "#24598",
489-
"ref": "#7753 item 6",
490-
"partial": "objectui: e2e/live/studio-record-page.spec.ts (whole), and e2e/live/studio-object-designer.spec.ts cases F1 and F4 (no clause here rests on them)",
491-
"why": "STALE, NOT RED — studio-record-page.spec.ts fills the Object control as an input when it is now a `role=combobox` button, so it fails against the CURRENT surface rather than against a product defect. Re-measured at the 18.0 sweep: Tier 1 run #24598 ran it at the sweep's console pin 4016370af3c9, 0 passed / 1 failed; at the shipped pin 12dc7b47c340 the spec is byte-identical (the same blob at both pins), so it is still stale there. First observed by #7695 on 2026-08-11. The dogfood pin (package-first-authoring) is unaffected. studio-object-designer.spec.ts is NOT unaffected, as this marker used to say: #24598 ran it with F2 and F3 passing and F1 and F4 failing as stale cases (F1 opens an app no stock boot loads; F4 expects no banner for a picklist with no option source), and it is byte-identical at 12dc7b47c340 too. No clause here cites it. object-designer-roundtrip's 4th ref, from the same class, was already repaired (package-create moved to /_console/studio).",
492-
"runnerRule": "The Studio-designer clause here (clause 3, 'creating a record page issues PUT /api/v1/meta/page/<name>') must be driven by hand — capture the PUT in the browser — until the spec is re-pointed; do not cite its output and do not score its failure as this item's FAIL. Every other clause keeps its own oracle.",
493-
"ownedBy": "objectui — re-pointing the two specs is objectstack-ai/objectui#13104 (the family card for the eleven live specs that are stale or red at the console pin, both of these among them), the cross-repo half of #7753; reported, not edited from this repo"
494-
}
485+
"ref": "packages/qa/dogfood/test/package-first-authoring.dogfood.test.ts; objectui: e2e/live/studio-record-page.spec.ts (acceptance[2] ONLY: it creates a record page bound to showcase_invoice and asserts the captured PUT /meta/page body's type 'record', its object, and regions seeded with a record:highlights block), e2e/live/studio-object-designer.spec.ts (scores NO clause of this item: its cases drive the object designer and the Studio package switcher, and no clause here scores either)"
495486
},
496487
"source": [
497488
"packages/runtime/src/route-ledger.ts (PUT /meta/:type/:name, GET /meta/_drafts, GET /meta/:type/:name/published, POST /packages/:id/publish-drafts)",
@@ -503,7 +494,8 @@
503494
{ "revision": 1, "date": "2026-08-07", "change": "initial — grounds the Studio authoring pipeline end-to-end with both deny gates as first-class clauses", "ref": "claude/platform-test-checklist-ocwugl" },
504495
{ "revision": 2, "date": "2026-08-11", "change": "annotated the objectui e2e/live/studio-record-page.spec.ts half of this item's automated.ref as STALE (run #7695): it fills the Object control as an input when it is now a role=combobox button, so it fails against the current surface, not against a defect. The Studio-designer clause now says drive it by hand until the spec is re-pointed; the dogfood pin and studio-object-designer.spec.ts are unaffected. Re-pointing lives in objectui (cross-repo half of #7753 item 6)", "ref": "#7753" },
505496
{ "revision": 3, "date": "2026-10-16", "change": "steps[1], [3] and [7] and acceptance[0].verify and [5].verify re-pointed (checklist-accuracy findings of QA run #23939, wave #23878). A plain PUT /meta/view/NAME saves state=active, so the draft never appeared in /meta/_drafts — ?mode=draft is required — and a view's name must be qualified OBJECT.view (#23939 used showcase_task.os_qa_view_RUNID). The Studio half now names the create form (/_console/apps/showcase_app/metadata/page/new) and its 'list' default, which has to be set to 'record' for a record page. Not loosened: every clause still scores the same server reads", "ref": "#24036" },
506-
{ "revision": 4, "date": "2026-10-20", "change": "automated.stale.observedIn, partial, why and ownedBy refreshed — the carried note from round 6 of wave anchor #24579 (its report, comment 6280484387), the refresh round 6 made on studio-authoring.record-page-roundtrip in PR #24697. Tier 1 run #24598 re-measured studio-record-page.spec.ts red at the sweep's console pin 4016370af3c9 (0 passed / 1 failed), and the spec is byte-identical at the shipped pin 12dc7b47c340, so the marker first written from #7695 still holds; ownedBy names the family card objectstack-ai/objectui#13104. The why also said studio-object-designer.spec.ts was unaffected; #24598 ran its F1 and F4 red (F2 and F3 passed), and partial now says so. No clause changed", "ref": "#24717" }
497+
{ "revision": 4, "date": "2026-10-20", "change": "automated.stale.observedIn, partial, why and ownedBy refreshed — the carried note from round 6 of wave anchor #24579 (its report, comment 6280484387), the refresh round 6 made on studio-authoring.record-page-roundtrip in PR #24697. Tier 1 run #24598 re-measured studio-record-page.spec.ts red at the sweep's console pin 4016370af3c9 (0 passed / 1 failed), and the spec is byte-identical at the shipped pin 12dc7b47c340, so the marker first written from #7695 still holds; ownedBy names the family card objectstack-ai/objectui#13104. The why also said studio-object-designer.spec.ts was unaffected; #24598 ran its F1 and F4 red (F2 and F3 passed), and partial now says so. No clause changed", "ref": "#24717" },
498+
{ "revision": 5, "date": "2026-10-20", "change": "automated.stale removed, automated.ref scoped per objectui spec, and acceptance[2].verify's stale note rewritten — round 14 of wave anchor #24579 (18.0 sweep), on the objectui pointer 6284006658. objectui#13132 (objectui 0b36ffa) repaired both specs the stale record named, and the console pin moved to 616df6598b42 (PR #24829), which contains 0b36ffa. studio-record-page.spec.ts: blob 181b2562c18d at the old pin 12dc7b47c340, 3844a60ccd79 at both 0b36ffa and 616df6598b42; it now sets Page type to record and picks the object from the Object combobox. studio-object-designer.spec.ts: blob 5967807df335, then 58a7f1cbf024 at both; F1 and F4 repaired. objectui measured its whole live suite at 0b36ffa as 61 passed (11.0m) on the shipped showcase; no live run exists at 616df6598b42, so the verdict there is NOT MEASURED. Re-read at the new pin, the ref keeps only what this record claimed: studio-record-page.spec.ts asserts acceptance[2], the clause the stale record sent to hand-driving, and studio-object-designer.spec.ts, on which no clause here rests, now says so. The dogfood pin is unchanged. No clause changed", "ref": "#24857" }
507499
]
508500
},
509501
{

0 commit comments

Comments
 (0)