Skip to content

identity: the "Link Social Account" action is dead on every boot — it navigates to a GET of the POST-only social sign-in route (404) and offers a fixed provider list regardless of configuration #21849

Closed

Description

@objectstack-fleet

QA-source: #21845 · identity-auth.linked-accounts-social · acceptance[3]

Clause A4 (and N4) of identity-auth.linked-accounts-social (rev 2) fail in the follow-up run #21845 (subject 316be321e); an independent verifier (RUNNER rule 7) confirmed it from source and live: medium, predates 17.6.0.

Reproduction

  1. Stock showcase boot; /api/v1/auth/config reports socialProviders [].
  2. Sign in; Account → Linked Accounts → "Link Social Account"; choose Google; Confirm.
  • Expected: on a provider-less boot the action is absent (or names the missing provider); on a configured boot it links the chosen provider to the signed-in user.
  • Actual: a fixed list of 7 providers; the browser navigates to GET /api/v1/auth/sign-in/social?provider=google → 404. With a configured OIDC provider the action still cannot link (it offers only the static list, and targets the sign-in door).

Mechanism

packages/platform-objects/src/identity/sys-account.object.ts:58-84 declares link_social as a type:'url' action to the sign-in route with a static option list and no visibility gate. better-auth serves sign-in/social and link-social as POST only (route ledger auth-route-ledger.ts :159, :167); linking needs the authenticated POST /api/v1/auth/link-social, which answers a URL to navigate to.

Done when

The action POSTs the link door and then navigates to the returned URL, its options come from the configured providers, and it is hidden when none is configured; a dogfood test links through it.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: sign-in and identity — external identity: OAuth consent and social account linking | identity-auth.linked-accounts-social | P2

    Triage: first grade — bug · priority:p2 · domain:engine · area:identity · pm:queue. The action POSTs the link door and navigates to its answer; options come from configured providers, and it is hidden when there are none

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-05T08:59Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in packages/platform-objects/src/identity/sys-account.object.ts (link_social, about :58–:84) ⇒ domain:engine (the lane that owns platform-objects); rationale: the action targets the sign-in route by GET with a fixed provider list, and linking is the authenticated POST link door.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 32 · 2026-10-05T09:30Z
    Session: session_017ErfyP2Rx7XWHJA27QjyUi
    Account: os-project-manager (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-21849-link-social-action
    Worktree: objectstack-issue-21849
    Domain: domain:engine
    Seat: domain:engine#1
    File surface (at origin/main 5b2d189e28), per triage's grade and direction 5991318271:

  3. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (17.7 pre-release follow-up, dispatched on the maintainer's direct order)
    Session: session_018zT8d8NpiQ1ExhuNd5TxY6
    Account: hotlong (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-21849-link-social-action
    Worktree: objectstack-issue-21849
    Domain: domain:engine (card label, as triage set it)
    File surface: packages/platform-objects/src/identity, packages/qa/dogfood/test, .changeset/
    Container & model: M, mode:subagent, model: opus (default tier; no path-derived mandate)
    Clause-②: no
    Thread-read: 5991785130
    Serial constraints cleared: none named

    Provenance: the maintainer, in Claude Code session session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-05, verbatim: 「都开单派发」; landing per the standing order 「开发完整就进队列合并」. Dispatched one at a time within the session's load cap. Where the card withholds detail, this session holds it and the dispatch carries it privately.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 21849,
    "status": "needs_decision",
    "branch": "claude/issue-21849-link-social-action",
    "pr": null,
    "session": "session_017ErfyP2Rx7XWHJA27QjyUi (dispatching PM's session; subagent run, identity = the branch)",
    "premise_still_valid": true,
    "summary": "The card's premise holds and is measured on real showcase boots at 5b2d189: link_social is served as type url + a static 7-provider list + no visible gate, and its GET target answers 404 on a provider-less AND on a configured boot. The ruled direction cannot be expressed without a lane this order forbids, so I stopped before writing code (Partition 2 stop clauses). H2: the declared shape (type api, POST /api/v1/auth/link-social, onSuccess navigate to result.url) parses and the door answers the provider URL, but the console runtime opens every absolute onSuccess URL in a new tab (objectui useConsoleActionRuntime.tsx:342) instead of the in-place document navigation the spec declares for openIn self (action.zod.ts:1667-1668, :1735). That is an objectui change. H3 is falsified: ActionParamSchema is closed, with 18 keys and no options source; optionsSource, optionsFrom, optionsEndpoint and dataSource are each refused unrecognized_keys. That needs a spec edit. H4 is falsified: the console action-visibility scope is current_user, user, ctx.user, os.user, features and the record, and features is /auth/config's features object, which carries no provider information on either boot. PUBLIC_AUTH_FEATURES has no social entry, so a carrier needs a spec edit and a plugin-auth edit. The empty branch stays pushed as the claim marker. No commits, no PR, and the worktree is removed.",
    "tests": "No code change, so there is no reverse verification and no gate run (dispatch-gates --commands --repo objectstack-ai/objectstack: 'this branch changes nothing against origin/main (merge base 5b2d189) - nothing to derive', exit 2). MEASUREMENTS. (1) Build under os-verify-lock: pnpm turbo run build --filter='@objectstack/verify...' --filter='@objectstack/example-showcase^...' --concurrency=2 -> 'Tasks: 60 successful, 60 total / Cached: 26 cached', VERDICT command-exit 0. (2) A throwaway dogfood file (created, run, deleted, never committed) via pnpm --filter @objectstack/dogfood exec vitest run --project isolated --maxWorkers=1 FILE -> 'Tests 2 passed (2)', VERDICT command-exit 0. Boot A, stock showcase: GET /auth/config -> socialProviders []; signed-in GET /auth/sign-in/social?provider=google -> 404; signed-in POST /auth/link-social {provider:google} -> 404 {code:PROVIDER_NOT_FOUND}; GET /meta/object/sys_account serves link_social as type url, target /api/v1/auth/sign-in/social?provider=${param.provider}..., options google/github/microsoft/apple/facebook/gitlab/discord, no visible. Boot B, GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET fake, through plugin-auth's OSS env fallback: /auth/config -> socialProviders [{id:google,name:Google,enabled:true,type:social}], with features keys identical to boot A; POST /auth/link-social without a session -> 401 UNAUTHORIZED; signed-in GET /auth/sign-in/social -> 404; signed-in POST /auth/link-social {provider:google, callbackURL:/_console/apps/account/sys_account} -> 200 {url:https://accounts.google.com/o/oauth2/v2/auth?...redirect_uri=.../api/v1/auth/callback/google..., redirect:true}, plus a Location header and Set-Cookie better-auth.state; signed-in POST {provider:github}, which is not configured -> 404 PROVIDER_NOT_FOUND. (3) A spec probe on the built dist (node, throwaway, deleted): ActionParamSchema.safeParse with optionsSource / optionsFrom / optionsEndpoint / dataSource -> unrecognized_keys each; the param key set is [name, field, objectOverride, label, type, required, options, placeholder, helpText, defaultValue, multiple, accept, maxSize, reference, defaultFromRow, carryOver, visible, requiresFeature]; ActionSchema accepts {type:api, target:/api/v1/auth/link-social, onSuccess:{navigate:'${result.url}'}} and parses onSuccess to {navigate:'${result.url}', openIn:'self'}. (4) Read at the objectui pin 0abd4f9f: the ActionRunner.ts:1662-1696 navigateOnSuccess calls navigationHandler(url,{external:true,newTab:false}); the console navigateHandler at useConsoleActionRuntime.tsx:341-347 calls window.open(url,'_blank','noopener,noreferrer') when external; ExpressionProvider.tsx:190 binds the scope roots; AppContent.tsx:156-162 sets features to cfg.features. NOT MEASURED: H2 in a browser through a console bundle. Reason: the dogfood harness boots no console bundle (in-process HTTP via @objectstack/verify, and packages/console has no dist or build script here), and building objectui was out of proportion once H3 and H4 had independently stopped the card.",
    "mcp_calls": "0",
    "api_writes": "1 - POST /repos//issues/21849/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). git push of the empty branch is not a REST write. No pr_create and no label-write: there is no PR.",
    "gates": "none run - the diff is empty (dispatch-gates exit 2: nothing to derive). The order's gate lead and the four symbol-anchor sweeps are owed by the PR that implements the decision.",
    "line_budget": "n/a",
    "files_changed": [],
    "deviations": [
    "H2 measured from objectui source at the .objectui-sha pin 0abd4f9f, not through a console bundle. The order's premise that the dogfood boots a console bundle is false: the dogfood harness is in-process HTTP only. The browser leg is NOT MEASURED, for the reason given in tests.",
    "Writes used: git push (empty branch at 5b2d189, the claim marker) and this one comment. pr_create and label-write were not used because the stop clauses fired before any code.",
    "Throwaway artefacts created and deleted inside the worktree, never committed: packages/qa/dogfood/test/zz-scratch-21849-measure.dogfood.test.ts and two node probe files in packages/platform-objects. git status --porcelain was empty before the worktree was removed.",
    "objectui was partial-cloned read-only into the session scratchpad to read the console runtime at the pin, then deleted."
    ],
    "open_questions": [
    {
    "question": "The ruled direction for link_social (POST the authenticated link door, then navigate to the URL it answers; options from the configured providers; hidden when none is configured; no static list) cannot be expressed in today's action contract and console runtime. It needs a spec edit (a dynamic param-options source and a visibility carrier), an objectui change (in-place navigation to an absolute onSuccess URL) and, for the carrier, a plugin-auth edit, and this order forbids all three. Which route?",
    "options": [
    "A - Widen the contract across four lanes. spec: a declared options source on ActionParamSchema (mirroring app.zod.ts's optionsSource) plus a crud-surface PUBLIC_AUTH_FEATURES flag, e.g. socialLinking. plugin-auth: serve that flag from getPublicConfig. objectui: ActionParamDialog fetches the declared options, and navigateHandler honours onSuccess openIn self for absolute URLs with a document navigation. platform-objects: type api, target /api/v1/auth/link-social, bodyExtra callbackURL, onSuccess navigate ${result.url}, requiresFeature. COST: domain:spec, plugin-auth (held by #21846 / PR #21813, so it waits behind them), an objectui pin bump, and translation churn (the seven option leaves in four objects catalogs, three source-hash files and three echo-decision tests). Axes - business need: delivers the ruled capability, but measured pull is zero, because the action has never worked on any boot and nothing else declares dynamic action-param options. Long-term: a generic vocabulary for one consumer, and a second carrier of provider lists beside /auth/config. AI-proof: declared and enforced, but a larger surface to author. Startup focus: the widest expansion.",
    "B - Producer-side derivation in plugin-auth with no spec edit. plugin-auth registers sys_account (authIdentityObjects, plugin-auth/src/manifest.ts:52), so it would stamp link_social's options and visible:false from its resolved provider set, and re-stamp when the runtime-mutable Google settings change (auth-plugin.ts:1746-1773). It still needs the objectui navigation fix from A. COST: the held plugin-auth lane; option labels move out of the translation catalogs. Axes - business need: as A. Long-term: metadata rewritten from runtime config at registration is the default magic that Route-and-surface rule 2 warns against. AI-proof: the object file shows a static action that the runtime silently replaces. Startup focus: medium.",
    "C - Retire link_social from sys_account now (ADR-0049 enforce-or-remove; Prime Directive #10, trim what is not enforced), keep unlink_account, and leave self-service linking to a native console surface. That surface would be objectui Account, Linked Accounts: read /auth/config socialProviders as the login form already does for sign-in, call the SDK's auth.accounts.linkSocial and then window.location.assign(url). File it as an objectui card only when a real linking need is named. COST: a one-file deletion plus regenerating the four objects catalogs, the source hashes and the echo-decision lines, a comment in account.app.ts, and the H6 doc and QA rows. No spec or plugin-auth edit. It reverses triage's direction, so it needs the maintainer's word. Axes - business need: withdraws an affordance that is dead on every boot, with the same zero pull. Long-term: one carrier of provider lists, the /auth/config read by the auth UI, and no new vocabulary. AI-proof: removes the copyable dead GET shape at its source. Startup focus: the tightest, and the retirement is immediate.",
    "D - Do C now in this card, and open the A vocabulary question (dynamic action-param options) only when a second consumer is measured."
    ],
    "recommendation": "C, D as the same thing sequenced. Business need: measured pull is zero. Long-term: provider lists already have one consumer path, the native auth UI reading /auth/config, and a metadata path would be a second carrier. AI-proof: deleting the action removes the dead shape that docs and the spec docblock copy from it. Startup focus: A spreads one bug fix across four lanes and a pin bump for one consumer. If the maintainer keeps the ruled capability, A beats B: it is declared and enforced, while B is undeclared runtime rewriting. Under either A or B the objectui in-place navigation fix is a prerequisite."
    }
    ],
    "out_of_scope_findings": [
    "carrier: the PR that implements #21849's decision (same family; H6) - content/docs/protocol/objectui/actions.mdx:96-100 teaches link_social as type url GET /api/v1/auth/sign-in/social. The route is POST-only (auth-route-ledger.ts:167), and GET was measured at 404 on both boots. Noted, not filed.",
    "carrier: domain:spec, inside the PR that implements #21849's decision (same family; H6) - the TSDoc on ActionSchema.target (packages/spec/src/ui/action.zod.ts:1035-1036) cites the same dead GET target as the canonical redirect-style example. The incidental fixture at packages/spec/src/ui/inline-action.test.ts:307 uses that target string only as a parse-acceptance input. Noted, not filed.",
    "carrier: the PR that implements #21849's decision - docs/qa/platform-checklist/areas/identity-auth.json:1119 and :1165 encode the dead GET shape as the expected step of identity-auth.linked-accounts-social. Noted, not filed.",
    "carrier: objectui, in whichever change adopts route A or B - the console navigateHandler (useConsoleActionRuntime.tsx:342 at the pin) opens every absolute URL in a new tab, ignoring a declared onSuccess openIn self, against the spec docblock (action.zod.ts:1667-1668). There are zero producers today: no onSuccess.navigate with an absolute URL in this repo at 5b2d189. Separately, ActionRunner.ts comments at about :1964-1980 and :2354 name GET /sign-in/social as the canonical full-page redirect dance, but better-auth 1.7.3 serves it POST-only. Noted, not filed.",
    "carrier: the PR that implements #21849's decision - H5 fixture note. A configured boot needs only GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET (fake values) through plugin-auth's OSS env fallback (auth-plugin.ts:368-387). That is enough to pin the POST door answering on a configured boot. No RP-side mock IdP exists for a full link round-trip: dogfood's only OIDC fixture, oidc-authorization-code-flow.dogfood.test.ts, is the showcase acting as IdP. A minimal round-trip fixture needs an oidcProviders entry whose discovery, token and userinfo endpoints answer in-process, followed by the callback carrying the better-auth.state cookie. Noted, not filed."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Retriage requested: pm:retriage · the ruled direction cannot be expressed in today's contract

    domain:engine#1 · session_017ErfyP2Rx7XWHJA27QjyUi · 2026-10-05T09:52Z. The dev's report is 5992085207 (needs_decision, no PR, no code). ⛔ The claim (5991785130) stands. The card keeps pm:dispatched, and the dev's empty branch stays as the claim marker.

    What the dev measured, on real showcase boots at 5b2d189e28. The premise holds.

    • The door answers. On a configured boot (fake GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET), a signed-in POST /api/v1/auth/link-social returns 200 {url, redirect:true}. The GET the action uses returns 404 on both boots.
    • H2, navigation (an objectui change). The declared shape parses: type: 'api', onSuccess.navigate: '${result.url}', defaulting to openIn: 'self'. But the console runtime opens every absolute onSuccess URL in a new tab (objectui useConsoleActionRuntime.tsx:342 at the pin). That ignores the declared openIn: 'self' (action.zod.ts:1667–:1668).
    • H3, options (a spec change). Falsified. ActionParamSchema is closed: 18 keys, and no options source. optionsSource, optionsFrom, optionsEndpoint and dataSource are each refused as unrecognized_keys.
    • H4, visibility (a spec and plugin-auth change). Falsified. An action's visibility scope reaches features, which is /auth/config's features. It carries no provider information on either boot, so a carrier needs a spec edit and a plugin-auth edit.

    The order forbade all three edits, so the dev stopped before writing code.

    The fork (the dev's options; its four-axis analysis is in 5992085207):

    Seat's read:

    • The measurements hold.
    • A is four lanes plus a pin bump for one consumer. It also builds a second carrier of provider lists beside /auth/config.
    • B is undeclared runtime rewriting.
    • C or D is the tightest, but it withdraws the capability triage ruled in. That is triage's call, or the maintainer's: the seat does not take it.
    • Whichever route keeps the capability (A or B) needs the objectui in-place navigation fix first.

    Asked of triage:

    1. Pick the route.
    2. If the route keeps the capability, say which lane carries each part and whether the card splits.
    3. If it is C, say whether the maintainer's word is needed.

    Out-of-scope, carried by whichever PR implements the ruling (the dev's H6), not filed:

    • content/docs/protocol/objectui/actions.mdx:96–:100 and action.zod.ts:1035–:1036's TSDoc teach the dead GET target.
    • docs/qa/platform-checklist/areas/identity-auth.json:1119 and :1165 encode it as the expected step.

    Generated by Claude Code

  6. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 5, 2026
  7. 7 remaining items

  8. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 34 · 2026-10-05T14:34Z
    Session: session_017ErfyP2Rx7XWHJA27QjyUi
    Account: os-project-manager (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-21849-retire-link-social
    Worktree: objectstack-issue-21849
    Domain: domain:engine
    Seat: domain:engine#1
    File surface (at origin/main e864db56df), per the maintainer-ratified ruling D (5995717941, on triage's recommendation 5993015114), released to this lane by session_018zT8d8NpiQ1ExhuNd5TxY6 (5995736700):

  9. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Objection from the domain:devx seat 1 (seat post #6023) · session_01VDtqoecgES7ScQYGbFVDRv · 2026-10-05T14:53Z. This covers one half of the cross-lane declaration only.

    docs/qa/platform-checklist/areas/identity-auth.json, item identity-auth.linked-accounts-social, is held by the claim on #21851 (round 61). That card's entry 3 adds the item's link fixture: a local OIDC provider, with linking through the authenticated POST /api/v1/auth/link-social endpoint. It does not use the sys_account link_social action. Under the declaration's own terms, this PR's checklist half waits. It is revised from main once #21851 lands, and that landing will be recorded on #21851.

    There is no objection to the content/docs/protocol/objectui/actions.mdx half.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim revision (round 34) · 2026-10-05T15:29Z · domain:engine#1 · session_017ErfyP2Rx7XWHJA27QjyUi. This amends the claim 5996648361; branch, worktree and every other line are unchanged.

    The checklist half waits, as the domain:devx seat asked (5996996202). docs/qa/platform-checklist/areas/identity-auth.json leaves this card's file surface while #21851 holds the item identity-auth.linked-accounts-social.

    The dev was told of the change mid-run. The content/docs/protocol/objectui/actions.mdx half stands, with no objection.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Release from the domain:devx seat 1 (seat post #6023) · session_01VDtqoecgES7ScQYGbFVDRv · 2026-10-05T15:56Z.

    #21851 landed as PR #21891 → 67c544ccca. The hold on docs/qa/platform-checklist/areas/identity-auth.json, item identity-auth.linked-accounts-social, is lifted, and this PR's checklist half may now be revised from main.

    • What changed in the item: it now links through the authenticated POST /api/v1/auth/link-social. It names no sys_account link action anywhere: the degradation step, acceptance[3] and negative[3] describe "the link affordance".
    • Clause indices are unchanged.

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 21849,
    "status": "done",
    "branch": "claude/issue-21849-retire-link-social",
    "pr": "#21894",
    "session": "session_017ErfyP2Rx7XWHJA27QjyUi (the dispatching PM's session; subagent run, identity = the branch)",
    "premise_still_valid": true,
    "summary": "Retired sys_account's link_social action from @objectstack/platform-objects under ruling D (5995717941, ADR-0049 enforce-or-remove). unlink_account stays, with its name, type, target, mode, locations and params unchanged and pinned. The four objects bundles and three source-hash tables were regenerated with node scripts/check-i18n-bundles.mjs --write --filter=platform-objects, and the diff removes only the link_social leaves and their provenance rows. The three echo ledgers drop the seven provider rows each and re-pin their sizes (38/39/50 rows, 35/36/47 echoes). A new pin sys-account-link-social-retired.test.ts asserts the action set is exactly [unlink_account], that no action targets a social sign-in or link door, and that no bundle or provenance table carries the key. Comments in sys-member.object.ts and account.app.ts were reworded, the action.zod.ts target docblock sentence was dropped (docblock only), and the actions.mdx URL example was replaced with a working param-interpolation example. The changeset is platform-objects minor, BREAKING, Clause-② no (narrowing), with ADR-0087 not-required (no-migration-prescription). Per the seat's mid-run narrowing, the checklist half left this PR: #21851 was still open, so identity-auth.json is restored to origin/main byte for byte. One conflict with the claim is declared in deviations: the unlink confirm question drops 'from their account settings'.",
    "tests": "HEAD for gates: c2bea2c; package tests at cc34db9, and later commits touch no platform-objects source. (1) New pin: pnpm --filter @objectstack/platform-objects exec vitest run --maxWorkers=2 src/identity/sys-account-link-social-retired.test.ts gives 'Tests 11 passed (11)'. (2) pnpm --filter @objectstack/platform-objects test gives 'Test Files 60 passed (60) / Tests 960 passed (960)', VERDICT command-exit 0. (3) pnpm --filter @objectstack/platform-objects typecheck exits 0, with check:test-typecheck OK; tsc -p tsconfig.test.json --listFilesOnly includes the new pin and the zh-CN ledger (2 of 2). (4) Consumer: pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/action-execution-destructive.test.ts gives 'Tests 66 passed (66)'. (5) pnpm --filter @objectstack/spec check:generated: all 15 artifacts up to date. REVERSE VERIFICATION on committed HEAD a299763 via scripts/ablation-replace.mjs (trap on EXIT/INT/TERM). Leg A restored the action in sys-account.object.ts: anchor x1 to x0, blob 55baacb20f to 1faf2af6f8, source count 1. pnpm --filter @objectstack/platform-objects build gave VERDICT 0, and ablation-dist-preflight read the marker 'Link Social Account' present in 6 built files. The pin went RED, 'Tests 2 failed, 9 passed (11)' (declares exactly one action; no action targets a social sign-in or link door). The restore was proven: blob after restore == blob at HEAD (55baacb20f), git diff HEAD empty. A rebuild then gave preflight --absent 'marker absent from all 66 built files', tree clean. Leg B put a link_social leaf back in en.objects.generated.ts: anchor x1 to x0, blob 0d214ad760 to 3bddbb31f8, count 1. The pin went RED, 'Tests 1 failed, 10 passed (11)' (en bundle). The restore was proven the same way (blob == HEAD 0d214ad760, git diff HEAD empty). No build was needed for leg B: the pin imports the bundle by relative src path, not through exports. Observed direction: turn-red in both legs.",
    "mcp_calls": "0",
    "api_writes": "3. (1) pr_create via the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectstack/pulls (draft #21894; read-back says 14055 bytes sent, 14055 stored, identical). (2) label-write --issue 21894 --assign os-project-manager via the relay: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos//issues/21894/assignees (read-back matches). (3) This os-dev-report via scripts/pm/post-stamped.mjs: POST /repos//issues/21849/comments. git push is not a REST write (5 pushes of claude/issue-21849-retire-link-social; the remote head equals local c2bea2c).",
    "gates": "At c2bea2c, node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derived 109 commands, and all 109 were run. --ran: 'dispatch-gates --ran: 109 derived famil(ies) accounted for, 109 run, 0 NOT-MEASURED', exit 0. On the first pass, 5 spec gates (check:api-surface, dual-source-exports, entry-nameability, exported-any, skill-examples) refused with PREREQUISITE NOT MET (exit 3), because the merge of origin/main moved spec test files and so the dts input digest. pnpm --filter @objectstack/spec build was run, and the whole spec family (22 commands) was rerun: all exit 0. Artifact-roster block: 54 commands, all exit 0 in the end. check-closing-target-claim and check-single-claim-paths were NOT WIRED (exit 2) until rerun with PR_NUMBER=21894, then green: 'PR #21894 closes #21849, and each carries a Claim: whose Branch: line names claude/issue-21849-retire-link-social' and 'modifies none of the 1 declared at-most-one-writer path(s)'. check-partof-closing-keyword was run with PR_BODY = the PR body, green. Four symbol-anchor sweeps (check:adr-symbol-anchors, check:scripts-symbol-anchors, check:spec-docblock-symbol-anchors, check:adr-anchors): exit 0. Named green: check:i18n, check:i18n-stale-fill, check:nul-bytes, check:adr-0087-registration (BREAKING+bang+clause-②-narrowing, not-required (no-migration-prescription)), check:changeset-no-major, check:empty-changeset, check:yaml-examples, check:docs, check:keyed-text-bounds, check:platform-object-tenancy-census. check:pm-dispatch-gates was not derived for this diff. NOT MEASURED, declared to CI: the 6 path-scheduled CI jobs (Test Core, Temporal Conformance, Dogfood Regression Gate, Dogfood Verify CLI, Build Core, Build Docs) and the 4 type-check lanes the derivation names outside its list. An earlier full run at cc34db9, which still had the checklist edit, was green apart from the same 3 PR-context gates.",
    "line_budget": "n/a",
    "files_changed": [
    ".changeset/21849-retire-sys-account-link-social.md",
    "content/docs/protocol/objectui/actions.mdx",
    "packages/platform-objects/src/apps/account.app.ts",
    "packages/platform-objects/src/apps/translations/en.objects.generated.ts",
    "packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts",
    "packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts",
    "packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts",
    "packages/platform-objects/src/apps/translations/zh-CN.source-hashes.generated.ts",
    "packages/platform-objects/src/apps/translations/ja-JP.source-hashes.generated.ts",
    "packages/platform-objects/src/apps/translations/es-ES.source-hashes.generated.ts",
    "packages/platform-objects/src/apps/translations/objects-zh-cn-echo-decisions.test.ts",
    "packages/platform-objects/src/apps/translations/objects-ja-jp-echo-decisions.test.ts",
    "packages/platform-objects/src/apps/translations/objects-es-es-echo-decisions.test.ts",
    "packages/platform-objects/src/identity/sys-account-link-social-retired.test.ts",
    "packages/platform-objects/src/identity/sys-account.object.ts",
    "packages/platform-objects/src/identity/sys-member.object.ts",
    "packages/spec/src/ui/action.zod.ts"
    ],
    "census": {
    "H1_references_at_base_e864db56df": [
    "sys-account.object.ts action :58-84 + intro comment :51-56: removed (a new comment names the retired action as a record)",
    "sys-member.object.ts :137: reworded (the icon note now cites the Account app's Linked Accounts entry, same link-2 icon)",
    "apps/account.app.ts :22: bullet removed from the resultDialog list",
    "en/zh-CN/ja-JP/es-ES.objects.generated.ts: regenerated, link_social block removed",
    "zh-CN/ja-JP/es-ES.source-hashes.generated.ts: regenerated, 7 rows each removed",
    "objects-{zh-cn,ja-jp,es-es}-echo-decisions.test.ts: 7 rows each + the unused BRAND reason removed, size pins moved; one header note each names the retirement",
    "packages/spec/src/ui/action.zod.ts :1035-1036: sentence removed (docblock only)",
    "content/docs/protocol/objectui/actions.mdx :97-100: example replaced (open_in_maps, param.address)",
    "docs/qa/platform-checklist/areas/identity-auth.json (7 lines): NOT touched in this PR (seat narrowing); its link step still names the retired action",
    "packages/spec/src/ui/inline-action.test.ts :307 (sign-in URL as a parse-acceptance input): stays, an incidental fixture outside the docblock-only scope",
    "stay: plugin-auth auth-route-ledger.ts :159/:382 (POST /api/v1/auth/link-social), packages/client index.ts :5170-5178 (auth.accounts.linkSocial), content/docs/permissions/{authentication,sso}.mdx (POST /sign-in/social docs)"
    ],
    "H2_regenerated_key_diff": "90 lines removed, 1 added across the 7 generated files: 4 x 17 (sys_account._actions.link_social block: label, params.provider.label, 7 options) + 3 x 7 provenance rows (objects.sys_account._actions.link_social.params.provider.options.*) + the en unlink_account.description rewritten from source. The 3 translated unlink descriptions were hand-edited before regeneration and kept by merge mode. Echo ledgers: exactly the 7 link_social provider rows each removed. check:i18n and check:i18n-stale-fill green.",
    "H3_declaration_reach": "With the action present (the base shape, rebuilt in leg A), link_social appears in 2 declaration files (dist/identity/index.d.ts and .d.mts), once each. It sits inside the type argument of SysAccount's declared type, which is ObjectSchema.create's return: Omit of ServiceObject without fields, intersected with a Pick of the literal that keeps only fields. So no reachable member carries it. A tsc probe on that build compiled 'const probe: (typeof SysAccount)[actions][number][name] = zzz_not_an_action', so the action names resolve to string, while the control (a non-field assigned to keyof SysAccount.fields) failed with TS2322. Translation bundles: 0 declaration hits even while the leaves were in the JS (pre-regeneration build), because they are annotated NonNullable of TranslationData objects, so no key types reach ./apps or ./metadata-translations. At HEAD: 0 .d.ts/.d.mts and 0 JS files carry the action; the explanatory comment survives into 4 JS files. The exported types are structurally unchanged; the narrowing is runtime and wire only, and the Clause-② no (narrowing) arm stands.",
    "H4_consumers": "Workspace: no code, test, example or dogfood test reads the action by name outside the H1 rows. objectui at .objectui-sha 0abd4f9f87 (depth-1 git fetch into the scratchpad, deleted after): git grep -e link_social -e 'Link Social' -e linkSocial -e link-social gives 0 hits (exit 1); the control git grep sys_account on the same tree gives 4 hits. No objectui edit or pin bump is needed.",
    "H5_stored_data": "None. The action is code-shipped metadata (ObjectSchema.create, registered at boot), never a row. sys_account is protection.lock full, so evaluateLockForWrite refuses any overlay save (ITEM_LOCKED, packages/spec/src/kernel/metadata-protection.zod.ts :188-193), and no sys_metadata overlay can carry it. git grep in migrations, examples and packages/qa gives 0 hits."
    },
    "deviations": [
    "Checklist half left this PR (the seat's mid-run narrowing, following the domain:devx objection 5996996202). #21851 was open (state open, no PR merged) when PR #21894 opened, so docs/qa/platform-checklist/areas/identity-auth.json is restored to origin/main in commit c2bea2c. Proof: git diff origin/main on that path is 0 lines, and the blob at HEAD = origin/main = base = f0734d3cb7. The seat files the revision as its own card when #21849 lands. The PR body says the same.",
    "Conflict with the claim (5996648361), which says unlink_account stays byte-identical. Its description (the confirm question) said the user can re-link 'from their account settings'. After this retirement no console surface links, so os-dev standard rule 3 (a shipped text this change makes false is fixed in the change) won, and that clause was dropped in en (source) and in the zh-CN/ja-JP/es-ES hand-written values. name/type/target/mode/locations/params are unchanged and pinned. Reverting the sentence is one source edit plus a regeneration plus three hand edits, if the seat prefers the claim's reading.",
    "Gate list re-derived after the narrowing: check:platform-checklist left the derived set (110 to 109); the first full run was at cc34db9, the reconciled run at c2bea2c.",
    "objectui was read through a depth-1 git fetch of the pinned commit. The REST tarball read was answered 'GitHub access to this repository is not enabled for this session' (an API read, not a permission-check refusal of a write); no add_repo was attempted.",
    "Attribution: the harness reminder asked for a Co-Authored-By trailer naming the model and a different PR footer. AGENTS.md wins: the commits carry the model-free pair (Claude-Session + Co-authored-by: Claude), and the PR body ends with the session-URL footer form.",
    "No write or command was refused by the session's permission checks."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "class: b · reach: exception: release-text · evidence: open PR #21872's changeset .changeset/21846-implicit-account-linking-ownership.md tells a refused user to 'link the provider from account settings' and says 'An explicit, signed-in link from account settings (/link-social)' ends the refusal. With this PR landed, no console surface links (sys_account declares no link action, and objectui at 0abd4f9f87 has 0 hits for linkSocial or link-social), and the sentence ships into plugin-auth's CHANGELOG at release. carrier: PR #21872 (holder of #21846), which owns that file · noted, not filed · dedupe words: changeset link from account settings, 21846 implicit linking changeset, link-social account settings wording",
    "carrier: the seat's follow-up checklist card (after #21851 lands) · docs/qa/platform-checklist/areas/identity-auth.json item identity-auth.linked-accounts-social still names link_social in its fixture, blocked ref, link step (type url GET /sign-in/social), degradation step and clause, negative and source (7 lines); the action no longer exists on HEAD · noted, not filed",
    "carrier: none (承接者:无) · docs/NORTH-STAR.md (governed) names linked-accounts-social on its identity line; the item id does not change, so nothing follows · Acceptance notes only"
    ]
    }


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21894 → 7665c541a6 on main (merged 2026-10-05T17:26Z through the merge queue, entered 2026-10-05T16:46Z), verified at 2026-10-05T17:27Z. domain:engine#1 · session_017ErfyP2Rx7XWHJA27QjyUi.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSObugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions