From 2afc48a66639289574e4a7b4252cef7737b376c3 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 17:04:55 +0000 Subject: [PATCH 1/4] docs(app-shell): record the objectui#7612 ruling where AUTHOR_SHAPE_ONLY_TYPES states its ingress condition The header above AUTHOR_SHAPE_ONLY_TYPES ended on a plan: switch the sharing_rule edit gate on once the _diagnostics ingress is closed. That condition was met (objectui#7603, hoisted by objectui#8181 into extractDraftBody, which strips through the spec's stripReadDecorations), the switch was put to the maintainer on objectui#7612, and the ruling was option A: the edit door stays with the server. The ending now records that, verbatim, where the reader meets the condition. The measurement above it is kept unchanged; the one sentence that quoted the pre-strip assembly is marked as the path objectui#6982 measured, with the live answer pointed at its test. No code line moves. --- .../views/metadata-admin/clientValidation.ts | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/app-shell/src/views/metadata-admin/clientValidation.ts b/packages/app-shell/src/views/metadata-admin/clientValidation.ts index d7ba23ed78..01af8ea3b1 100644 --- a/packages/app-shell/src/views/metadata-admin/clientValidation.ts +++ b/packages/app-shell/src/views/metadata-admin/clientValidation.ts @@ -562,11 +562,33 @@ function expandViewIssues( * where a permissive match-all sharing condition gets written — and deliberately * not on `edit`. This is NOT a tolerant fallback: nothing is coerced and no * draft is waved through; one door has a client gate and the other keeps the - * server's. Turning this gate on is gated on the `_diagnostics` ingress being - * closed first (the strip belongs where the draft is assembled, not here — + * server's. + * + * ── The ingress condition was MET, and the answer was still no (objectui#7612) ── + * + * This block used to end on a plan: switch the edit gate on once the + * `_diagnostics` ingress is closed where the draft is assembled (not here — * reconstructing the decoration list in this file would be a second de-facto - * contract). Until then a gate here would refuse legitimate author input, which - * is worse than the defense-in-depth gap it closes. + * contract), and not before, since until then a gate here would refuse + * legitimate author input. That condition was met. objectui#7603 stripped the + * read decorations off the pending draft, and objectui#8181 hoisted the strip + * into `extractDraftBody`, which removes the spec's own list through the spec's + * `stripReadDecorations` before the pending draft is merged. So the + * `getDraft().item` assembly quoted above is the edit path as objectui#6982 + * measured it, not as it stands; for the live answer read + * `ResourceEditPage.readDecorationStrip.test.tsx`, not this paragraph. + * + * The switch was then put to the maintainer on objectui#7612, with the met + * condition measured on that card and a finished implementation beside it + * (PR objectui#10054). The maintainer ruled option A on 2026-09-20, verbatim + * 「7612 只需要服务端校验」 ("7612 needs server-side validation only"): the edit + * door stays ungated, because the server is authoritative on it and that is + * enough. The PR closed unmerged. The create door was not in question and keeps + * its client gate. + * + * ⇒ A closed ingress is NOT a reason to take `sharing_rule` out of this set: + * that question was asked with the condition already met, and answered. Only a + * new maintainer ruling re-opens it, never a re-reading of the ingress. */ const AUTHOR_SHAPE_ONLY_TYPES = new Set(['sharing_rule']); From 0a03e7ea95c9117b5b663b1132b33d22b43c51e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 17:05:48 +0000 Subject: [PATCH 2/4] test(app-shell): pin the objectui#7612 ruling to the AUTHOR_SHAPE_ONLY_TYPES header A source scan of the one docblock directly above the set. It requires that docblock to name the ruling's card (objectui#7612) and the function that closed the ingress (extractDraftBody), so the header cannot again read as a plan whose condition is met without the answer beside it. Named subjects only: the ruling's wording is quoted in the header, not pinned as text. The control reads the same docblock for the measurement it must keep (ADR-0010, _diagnostics, objectstack#5316) and proves the read is bounded on both sides, so an empty or misplaced read cannot pass as a scan of nothing. --- ...Validation.authorShapeRuling-10150.test.ts | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 packages/app-shell/src/views/metadata-admin/clientValidation.authorShapeRuling-10150.test.ts diff --git a/packages/app-shell/src/views/metadata-admin/clientValidation.authorShapeRuling-10150.test.ts b/packages/app-shell/src/views/metadata-admin/clientValidation.authorShapeRuling-10150.test.ts new file mode 100644 index 0000000000..b872da54a7 --- /dev/null +++ b/packages/app-shell/src/views/metadata-admin/clientValidation.authorShapeRuling-10150.test.ts @@ -0,0 +1,101 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * objectui#10150 — the `AUTHOR_SHAPE_ONLY_TYPES` header carries the ruling that + * keeps `sharing_rule` in the set, at the place its reader meets the condition. + * + * ## The trap this keeps shut + * + * The header in `clientValidation.ts` used to end on a plan: switch the + * `sharing_rule` edit gate on once the `_diagnostics` ingress is closed. The + * ingress was closed (objectui#7603, hoisted by objectui#8181), the switch was + * put to the maintainer on objectui#7612 with that already measured, and the + * ruling was option A: the edit door stays with the server. A header that still + * reads as the plan sends its next reader, who checks the condition and finds + * it met, straight back to re-filing objectui#7612. + * + * ## What this pins + * + * NAMED SUBJECTS inside ONE docblock, the one directly above the set: the + * ruling's card, and the function that closed the ingress. Inside that docblock + * and not merely somewhere in the file, because a citation moved to another + * comment is one the reader of the condition never meets. + * + * ## What it cannot pin, said here so it is not assumed + * + * - ⛔ Not the ruling's wording. The header quotes it verbatim; nothing parses + * that quotation, so it is not pinned as text. + * - ⛔ Not prose intent. A header that cites objectui#7612 AND re-states the + * old plan passes here. Catching that is review's job. + * - ⛔ Not whether the ingress is still closed. That is behaviour, and + * `ResourceEditPage.readDecorationStrip.test.tsx` is its instrument. + * + * The first case is the lit CONTROL. The same reader finds the measurement the + * header must keep, and finds it only between the docblock's own bounds, so an + * empty or misplaced read cannot let the second case pass as a scan of nothing. + * + * If a later ruling takes `sharing_rule` out of the set, the header changes in + * that pull request, and this file changes with it. + */ + +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const SOURCE = readFileSync(path.join(here, 'clientValidation.ts'), 'utf8'); + +/** The declaration the header documents. */ +const ANCHOR = '\nconst AUTHOR_SHAPE_ONLY_TYPES = '; + +/** + * The docblock that ends directly above `ANCHOR`. A lookup, not a comment mask: + * nothing is removed from the source, the block is only located. Answers '' when + * the declaration is gone or is not directly preceded by a docblock, which every + * case below reads as a failure. + */ +function headerAboveSet(src: string): string { + const at = src.indexOf(ANCHOR); + if (at < 0) return ''; + const before = src.slice(0, at); + const close = before.lastIndexOf('*/'); + if (close < 0 || before.slice(close + 2).trim() !== '') return ''; + const open = before.lastIndexOf('/**', close); + return open < 0 ? '' : before.slice(open, close + 2); +} + +const HEADER = headerAboveSet(SOURCE); + +describe('objectui#10150 — the AUTHOR_SHAPE_ONLY_TYPES header records the objectui#7612 ruling', () => { + it('CONTROL — the reader returns that header, bounded, and it still carries the measurement', () => { + expect(HEADER, 'no docblock directly above `const AUTHOR_SHAPE_ONLY_TYPES`').not.toBe(''); + + // The measurement is why the type was listed, and the card that added the + // ruling kept it on purpose: the envelope family, the read decoration, and + // the inversion both would cause. + for (const subject of ['ADR-0010', '_diagnostics', 'objectstack#5316']) { + expect(HEADER, `the header no longer names ${subject}`).toContain(subject); + } + + // Bounded on both sides: the code just above the docblock and the comment + // just below the set are in the file, and neither is in what was read. + for (const outside of ['function expandViewIssues', 'Map metadata-type name']) { + expect(SOURCE).toContain(outside); + expect(HEADER).not.toContain(outside); + } + }); + + it('cites the ruling and the closed ingress by name, in the header itself', () => { + for (const subject of ['objectui#7612', 'extractDraftBody']) { + expect( + HEADER, + `the header above AUTHOR_SHAPE_ONLY_TYPES must name ${subject}: the ` + + '`_diagnostics` ingress it describes was closed, the edit-door switch ' + + 'was put to the maintainer on objectui#7612, and the ruling kept that ' + + 'door with the server. Without it the header reads as a plan whose ' + + 'condition is met (objectui#10150).', + ).toContain(subject); + } + }); +}); From 4b80f1305152242b6cfbbbdc7b5a5cf90337f83f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 17:10:49 +0000 Subject: [PATCH 3/4] chore(changeset): declare the AUTHOR_SHAPE_ONLY_TYPES header change as releasing nothing The docblock sits on a non-exported const, so it does not reach the emitted clientValidation.d.ts; the comment-stripped emit is identical to the base. --- .changeset/10150-author-shape-header-ruling.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/10150-author-shape-header-ruling.md diff --git a/.changeset/10150-author-shape-header-ruling.md b/.changeset/10150-author-shape-header-ruling.md new file mode 100644 index 0000000000..599e585381 --- /dev/null +++ b/.changeset/10150-author-shape-header-ruling.md @@ -0,0 +1,6 @@ +--- +--- + +Comment-only in `@object-ui/app-shell`: the docblock above `clientValidation`'s `AUTHOR_SHAPE_ONLY_TYPES` ended on a plan, to switch the `sharing_rule` edit gate on once the `_diagnostics` ingress was closed. That condition was met (`extractDraftBody` strips the read decorations through the spec's `stripReadDecorations`), the switch was put to the maintainer on objectui#7612, and the ruling was option A: the edit door stays with the server. The docblock now records that ruling beside the condition, and keeps the measurement above it. A source-scan pin requires the docblock to name the ruling's card and the function that closed the ingress. + +Declared as releasing nothing because the emit was measured rather than assumed: `AUTHOR_SHAPE_ONLY_TYPES` is not exported, so neither it nor its docblock reaches the emitted `clientValidation.d.ts`; the emitted `.js` carries the comment, and its comment-stripped emit is identical to the base. No published behaviour changes (objectui#10150). From a87fe06ee5ad867cfd71643c084b84a62de688c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 17:19:15 +0000 Subject: [PATCH 4/4] docs(app-shell): give the AUTHOR_SHAPE_ONLY_TYPES ruling a second locus The ruling's own card reads 404 from this container today (issue GET, the single-comment GET and the web page; the comment list and the timeline still answer), so the header also names the card that restates it. The quotation stays in the header either way, which is what makes the site self-sufficient. --- .../src/views/metadata-admin/clientValidation.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/app-shell/src/views/metadata-admin/clientValidation.ts b/packages/app-shell/src/views/metadata-admin/clientValidation.ts index 01af8ea3b1..4181dbb619 100644 --- a/packages/app-shell/src/views/metadata-admin/clientValidation.ts +++ b/packages/app-shell/src/views/metadata-admin/clientValidation.ts @@ -580,11 +580,11 @@ function expandViewIssues( * * The switch was then put to the maintainer on objectui#7612, with the met * condition measured on that card and a finished implementation beside it - * (PR objectui#10054). The maintainer ruled option A on 2026-09-20, verbatim - * 「7612 只需要服务端校验」 ("7612 needs server-side validation only"): the edit - * door stays ungated, because the server is authoritative on it and that is - * enough. The PR closed unmerged. The create door was not in question and keeps - * its client gate. + * (PR objectui#10054). The maintainer ruled option A on 2026-09-20 (restated on + * objectui#10150), verbatim 「7612 只需要服务端校验」 ("7612 needs server-side + * validation only"): the edit door stays ungated, because the server is + * authoritative on it and that is enough. The PR closed unmerged. The create + * door was not in question and keeps its client gate. * * ⇒ A closed ingress is NOT a reason to take `sharing_rule` out of this set: * that question was asked with the condition already met, and answered. Only a