Skip to content

Commit cc14657

Browse files
docs(qa): the share-link landing page asserts the 'Sign in required' state for a signed_in link (#23169) (#23327)
Part of #23169 Clause-②: no (QA data) This PR lands one row of #23169: `access-security.share-link-landing-page` C3, from QA run #23163 (`surface:browser`). The row waited for PR #23222, which also edited `access-security.json`; it merged as `66949b7729`. #23169 remains open for its other row, `platform-core.lifecycle-retention-sweep` steps[4], which still waits on a maintainer ruling and is not part of this PR. ## What changed One item changes: `access-security.share-link-landing-page`, at `.items[27]` of `docs/qa/platform-checklist/areas/access-security.json`. Its `revision` goes from 1 to 2, and one `history` entry is appended. Indices are zero-based. | field | before | after | |---|---|---| | `fixtures.knownGaps[2]` | the page folds every 401 into the password prompt, so a `signed_in` link opened anonymously renders "Password required". It asked to be revised once the console told the two codes apart | a regression row, expected PASS. The page reads a 401 by its `error.code`, and a `signed_in` link opened anonymously renders the "Sign in required" state. It names the objectui pins | | `acceptance[3].clause` (the item's clause 4) | no leak, plus "a designed state", recording whichever state renders | asserts the sign-in state: the "Sign in required" heading, "The owner shared this link with signed-in users only.", and a Sign in link to the console's `/login` route that redirects back. Never the password prompt or a password input | | `acceptance[3].verify` | "the rendered state noted" | the record-free `401 SIGN_IN_REQUIRED` body, then a screenshot and a DOM read of the sign-in state | | `variants[5]` | "refused, designed state" | "refused: the 'Sign in required' state, no password prompt" | No other item changes, and no other field of this item. This is the same edit discipline as PR #23278. ## How the row was checked The row was re-checked from source. No browser was driven and no app was booted, as in PR #23278. QA run #23163 saw the state live, at objectstack `36b2889c` with objectui `1fb1ced36243`: "`signed_in` audience renders a dedicated 'Sign in required' state (401 SIGN_IN_REQUIRED), member 200". - **Console, objectui at `1fb1ced36243`,** still `main`'s `.objectui-sha`: - `apps/console/src/pages/SharedRecordPage.tsx`: `fetchResolve` reads a 401's body through `resolveGateOf`. A `sign-in-required` answer sets the `sign-in` gate. That gate renders "Sign in required", "The owner shared this link with signed-in users only." and a Sign in link to `/login` whose `redirect` is the router path. - `apps/console/src/pages/shared-record-shape.ts`: `RESOLVE_GATE_BY_CODE` maps `NEEDS_PASSWORD` and `WRONG_PASSWORD` to the password gate and `SIGN_IN_REQUIRED` to the sign-in gate. Any other code names no gate, and the page shows the server's message. - Pins at the same revision: `SharedRecordPage-11649.test.tsx` ("shows the sign-in path back to this link, and no password prompt") and `shared-record-shape.test.ts` ("reads each 401 code as its gate"). - **Framework, at base `87e902dcbb`:** both resolve mounts answer `401 SIGN_IN_REQUIRED` when a live `signed_in` link without a password is opened anonymously. One is the probe in the resolve route of `packages/plugins/plugin-sharing/src/share-link-routes.ts`; the other is its dispatcher twin in `packages/runtime/src/domains/share-links.ts`. The two sides agree. So, as the item itself asked, the knownGap becomes a regression row and clause 4 becomes an assertion. **Edit discipline.** One scripted edit: - Each replacement asserted that its anchor occurs exactly once inside the item and exactly once in the file. - After the save, the script parsed the file and checked it against the base blob: - the 27 other items are identical; - this item changed only in `revision`, `fixtures`, `acceptance`, `variants` and `history`; - inside those fields, only knownGaps[2], acceptance[3].clause, acceptance[3].verify and variants[5] differ; - `revision` went up by one, and `history` is the base list plus one entry. - The new text cites code by function and string names, never by line number. The ledger's anchor rule (`scripts/symbol-anchors.mjs`) says a line number is not an anchor form. ## Gates All gates ran at head `88a65fb624`. Each ran in its own process with its own log, and its exit code was read before any pipe. `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 13 commands for the one path. The `--ran` reconciliation printed `✓ dispatch-gates --ran: 13 derived famil(ies) accounted for — 13 run, 0 NOT-MEASURED (a DERIVED zero — all 13 recorded an exit code and none of them is 3).` | command | exit | verdict line | |---|---|---| | `node scripts/check-ci-filter-parity.mjs` | 0 | `OK: all 21 build input(s) turbo.json declares outside the packages …` | | `node scripts/check-closing-keyword-parity.mjs` | 0 | `check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords …)` | | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | `✓ … 40 assertions, 5 mutations of the shipped parsers each driven to red.` | | `node scripts/check-comment-mask-corpus.mjs` | 0 | `✓ comment-mask corpus sweep …: 8983 files, 0 disagree, 0 unparseable` | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 | `✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 474 files …`. It ran after `pnpm --filter '@objectstack/lint...' build` under `os-verify-lock`: `VERDICT command-exit 0`, 151 s held | | `pnpm check:cross-package-test-inputs` | 0 | `OK: 30 package(s) read outside themselves, all declared …` | | `pnpm check:doc-authoring` | 0 | `✓ doc authoring guard: 18522 customer-facing string(s) … clean` | | `pnpm check:driver-memory-census` | 0 | `check-driver-memory-census: OK …` | | `pnpm check:gitlink-declared` | 0 | `check-gitlink-declared: OK (11279 index entries …)` | | `pnpm check:nul-bytes` | 0 | `check-nul-bytes: OK (scanned 11270 text file(s) … no raw ASCII control bytes).` | | `pnpm check:platform-checklist` | 1 | `check-platform-checklist: 8 problem(s)`: the same 8 lines as at base `87e902dcbb`. The sorted problem lines diff empty, and none of them is in this item | | `pnpm check:refd-timer-probe` | 0 | `OK check-refd-timer-probe: 8977 source file(s) swept …` | | `pnpm check:watch-hint-literal` | 0 | `✓ check-watch-hint-literal: 73 declaration(s) across 4 rostered name(s) …` | - **The 8 `check:platform-checklist` problems predate this PR.** Seven are absent symbols, in `access-security.public-form-withdrawal-layers`, `attachments-storage.attach-requires-parent-edit` and `search.rls-both-personas`. The eighth is the attachments-storage anchor floor. The daily watchdog owns them. - **Anchor census:** `--anchor-census` at base and at head reads `724/741` resolved, plus 10 on the named residual. Every per-file count is identical, `areas/access-security.json` 63 at both. - **`skip-changeset`:** `docs/qa/**` ships in no package. `git grep 'docs/qa' -- '*package.json'` exits 1, with no hit. The positive control is `packages/spec/package.json`, which carries a `files` field (`dist`, `json-schema`, …). - **The selector still reads the item:** `node scripts/checklist-select.mjs access-security.share-link-landing-page` prints `1 runnable item(s)`. ## Acceptance notes Two things are noted here and not filed by this PR. 1. **A related product defect, out of scope and reproduced (handed to the seat to file).** A link minted with both a password and `audience: 'signed_in'`, opened anonymously with the correct password, answers `401 WRONG_PASSWORD`. - Measured with a throwaway probe, not committed. It drove plugin-sharing's real resolve route on a real `SqlDriver` (`:memory:`): - no password: `401 NEEDS_PASSWORD`; - wrong password: `401 WRONG_PASSWORD`; - correct password: `401 WRONG_PASSWORD`; - signed in, correct password: `200`. - Why: `resolveToken` refuses on the audience before it checks the password. The route's probe then answers from the row in password-first order, and it reads only whether a password was sent, not whether it was right. The dispatcher twin has the same order (source read). - Who can produce it: objectui's `ShareDialog.tsx` at the pin sends an audience and a password in one create. The landing page then says "Wrong password." for the right one, and never offers sign-in. - This item mints its password token and its `signed_in` token separately, so it does not reach that case. 2. **Stale line ranges in this item's untouched fields.** `acceptance[1].verify` (`SharedRecordPage.tsx,143-176`), `acceptance[2].verify` (`,178-186`), `knownGaps[1]` and `source[1]` (`,190-234`) no longer point at those code paths at the pin. - They are not fixed here. The anchor rule judges `file:line`, but not this comma spelling, which appears 44 times across `areas/*.json`. - Re-pointing them by name is a re-authoring of the item, not this row. --- _Generated by [Claude Code](https://claude.ai/code/session_012zwsLMxQBwHUYJgPyrpEvx)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 345d1be commit cc14657

1 file changed

Lines changed: 11 additions & 5 deletions

File tree

‎docs/qa/platform-checklist/areas/access-security.json‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,7 +3018,7 @@
30183018
"title": "The /s/:token share-link landing page renders the resolved record minus redacted fields, gates on password, and refuses dead links with designed states — never a blank page or a raw error",
30193019
"since": "v16",
30203020
"status": "active",
3021-
"revision": 1,
3021+
"revision": 2,
30223022
"priority": "P2",
30233023
"surface": "browser",
30243024
"personas": [
@@ -3035,7 +3035,7 @@
30353035
"knownGaps": [
30363036
"automated.ref lives ENTIRELY in the objectui repo — from this checkout it is neither runnable nor pin-evidenced (the RUNNER standing fact): drive the item by hand in the browser, or run the pin in an objectui checkout and name the revision",
30373037
"the ai_conversations transcript branch (SharedRecordPage.tsx,190-234 — messages fetch + ChatbotEnhanced readOnly) is ai_conversations-only (Cloud/EE service-ai) — the same knownGap split the API item records for /:token/messages; not runnable on open-framework showcase",
3038-
"the page folds EVERY 401 into the password prompt (SharedRecordPage.tsx branches on status alone, never on the body's NEEDS_PASSWORD vs SIGN_IN_REQUIRED code): a signed_in-audience link opened anonymously renders 'Password required' today, not a sign-in prompt. Clause 4's bar is therefore non-leak + a designed state; record the rendered state as measured, and revise this item if the console later distinguishes the two codes"
3038+
"FIXED, regression row, expected PASS (objectui#11649): the page no longer folds every 401 into the password prompt. At objectui 1fb1ced36243, still this repo's .objectui-sha, SharedRecordPage.tsx reads a 401 by the body's error.code through shared-record-shape.ts resolveGateOf — NEEDS_PASSWORD and WRONG_PASSWORD open the password prompt, SIGN_IN_REQUIRED opens the sign-in gate, and any other code shows the server's message, not a prompt — so a signed_in-audience link opened anonymously renders the dedicated 'Sign in required' state, never 'Password required'. acceptance[3] now asserts that state (QA run #23163 saw it live at objectstack 36b2889c). The objectui pins are apps/console/src/pages/SharedRecordPage-11649.test.tsx ('shows the sign-in path back to this link, and no password prompt') and shared-record-shape.test.ts ('reads each 401 code as its gate'), objectui-repo-only like knownGaps[0]"
30393039
]
30403040
},
30413041
"steps": [
@@ -3066,9 +3066,9 @@
30663066
"evidence": "screenshots + the 404/410 bodies"
30673067
},
30683068
{
3069-
"clause": "audience 'signed_in', both sides: the anonymous open never renders the record (the 401 body is record-free; the page shows a designed state — per knownGaps, today that state is the password prompt, record which renders), and the form-signed-in member's open renders it",
3069+
"clause": "audience 'signed_in', both sides: the anonymous open never renders the record — the resolve answers 401 SIGN_IN_REQUIRED with a record-free body, and the page renders its dedicated sign-in state ('Sign in required', 'The owner shared this link with signed-in users only.', and a 'Sign in' link to the console's /login route whose redirect parameter returns to this link), never the 'Password required' prompt or a password input — a password prompt here is the regression knownGaps[2] records as fixed; and the form-signed-in member's open renders the record",
30703070
"oracle": "network",
3071-
"verify": "anonymous resolve 401 record-free + the rendered state noted; signed-in resolve 200 and the record renders (the resolve fetch rides the same-origin session cookie)",
3071+
"verify": "anonymous resolve 401 SIGN_IN_REQUIRED record-free, then a screenshot and a DOM read of the sign-in state: the 'Sign in required' heading, a 'Sign in' link whose href is the console's /login with redirect= the URL-encoded /s/ path of this token, and no input[type=password] (SharedRecordPage.tsx renders it when shared-record-shape.ts resolveGateOf reads SIGN_IN_REQUIRED off the 401 body); signed-in resolve 200 and the record renders (the resolve fetch rides the same-origin session cookie)",
30723072
"evidence": "both traces + both screenshots"
30733073
},
30743074
{
@@ -3088,7 +3088,7 @@
30883088
"revoked (410 message)",
30893089
"expired (410 message)",
30903090
"unknown token (404 message)",
3091-
"audience signed_in — anonymous (refused, designed state)",
3091+
"audience signed_in — anonymous (refused: the 'Sign in required' state, no password prompt)",
30923092
"audience signed_in — signed-in (renders)",
30933093
"redacted-fields notice"
30943094
],
@@ -3115,6 +3115,12 @@
31153115
"date": "2026-08-30",
31163116
"change": "new — the UI half of the share-link surface: access-security.share-link-capability-tokens (surface:api) asserts the resolve contract but nothing asserted what /s/:token actually renders — the redaction notice (whose #3983 regression was precisely a render-only loss), the password prompt loop, the designed dead-link states, and the outside-the-shell mount. Cross-referenced both ways; the 401-fold boundary (password prompt rendered for a signed_in-audience 401) is recorded as a measured knownGap, not an expectation",
31173117
"ref": "#sweep-2026-08-30"
3118+
},
3119+
{
3120+
"revision": 2,
3121+
"date": "2026-10-13",
3122+
"change": "knownGaps[2], acceptance[3].clause, acceptance[3].verify and variants[5] (knownGap stale, #23163 C3; parked on #23121, carried by #23169). The page no longer folds every 401 into the password prompt: at objectui 1fb1ced36243, still this repo's .objectui-sha, SharedRecordPage.tsx reads a 401 by its error.code (shared-record-shape.ts resolveGateOf, objectui#11649) and renders a dedicated 'Sign in required' state, with a 'Sign in' link back to this link, for SIGN_IN_REQUIRED. The server half is unchanged at 87e902dcbb: both resolve mounts, packages/plugins/plugin-sharing/src/share-link-routes.ts and its dispatcher twin packages/runtime/src/domains/share-links.ts, answer an anonymous open of a live signed_in link with no password with 401 SIGN_IN_REQUIRED. As the knownGap itself asked, it becomes a regression row, and acceptance[3] (the item's clause 4) asserts the sign-in state instead of recording whichever state renders. Read from source at both pins; no browser was driven and no app was booted. QA run #23163 saw the state live",
3123+
"ref": "#23169"
31183124
}
31193125
]
31203126
}

0 commit comments

Comments
 (0)