Repository navigation
docs(spec): re-anchor the dead tracker citations in kernel/ and contracts/ to the commits and ADRs that decided them (stage 1) - #20326
Conversation
Comment-only. Each rewritten line cites the commit that decided it. Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 24 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 5 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e265b0d4f3cf3b7cf89bc06f12cdb97329e765a3 && git checkout e265b0d4f3cf3b7cf89bc06f12cdb97329e765a3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin de091b50e67aec12764eccc18a87b1b4259573e3 ebbea0b6e9a22b35a49b7fee578bae2d4b6d9986 && git checkout -B drift-repro de091b50e67aec12764eccc18a87b1b4259573e3 && git merge --no-ff ebbea0b6e9a22b35a49b7fee578bae2d4b6d9986
node scripts/docs-audit/affected-docs.mjs --json de091b50e67aec12764eccc18a87b1b4259573e3
|
Contract reviewServed-tier: Read: card #20234 (body, 5856637615, 5858331362, 5859418643, 5860236501), ruling 5749154545 on #19123, AGENTS.md lines 11–18 and 1071–1080, precedent 66e266c, PR #20226 (body, instrument), PR #20326 (object, body, 46-file list, 6 commits, full diff against merge base 6a6a17b, 35 check-runs on the head), the 38 cited commits (subject, message, diff where the line claims more than the subject), ADR-0090 D10, the gate headers of check-issue-citations / check-changeset-no-major / check-empty-changeset and pr-automation.yml's WHICH LEVEL. Ran: sha ancestry and disambiguation, a TypeScript-parser leaf-token comparison over 45 files with three controls, a REST census of 445 numbers at base and head with lit and dead controls at six checkpoints, the citation judging pass in a detached worktree at the head under os-verify-lock, merge-tree against origin/main 10ea9eb, and the CI poll to convergence. NOT MEASURED: the derived gate families other than the citation pass (not re-run by rule), the dist build (ships-bytes taken from files[] and the precedent, not rebuilt), and the objectstack-ai/framework board. ① Derived judgments(a) Deciding commits — PASS. 38 distinct 9-hex shas appear on added lines; every one resolves to exactly one commit ( (b) The four dropped numbers — PASS. All four answer 404 (probed here). No ADR, (c) No code token moved — PASS. Own instrument (tokcmp.mjs, TypeScript 5.9.3 parser, leaf nodes, JSDoc nodes excluded, comments never nodes) over the 45 touched (d) The census — PASS. Own extraction with the gate's grammar (bare, (e) Form C compliance — PASS. No tracker number stands as provenance on any added line; every number on an added line already stood on the removed line of the same file (added-minus-removed per file: empty). PR #6900 and #7211 appear only beside b5404f4 and 1507ba3. Judging pass, run as CI runs it, in a detached worktree at the head under os-verify-lock with ② Semver level
③ Boundary flagsBlocking: none CI at this head: 35 check-runs, 32 success, 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke opt-in), 0 failure, converged 22:22:12Z; the seven required contexts (TypeScript Type Check, Test Core, Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL), Lint & Repo Gates, Governed Surface Queue Guard) all success. PR is a draft; Implemented-by: VERDICT: PASS |
… and pruned to everyone else (objectstack-ai#20337) Fixes objectstack-ai#20290 Clause-②: no This executes triage's grade on the card (comment 5859504238). Triage decided the carrier is the server, under maintainer ruling 5856774816 on objectstack-ai#20156 (letter B). Triage's words, verbatim: > **Carrier, decided here: the server.** Ruling B's own words decide it: 「Read-to-display is pruned per user; read-to-edit is whole for the editor」, and 「whoever can save it must see it whole, or a save drops entries silently」. A draft is a stored version, not a rendered one. So the plain read's `?state=draft` branch takes the same author exemption PR objectstack-ai#20284 gave the stored-version doors: whole for whoever may save the app, pruned for everyone else. ## What changed **The transport** (`packages/rest/src/rest-server.ts`) - The plain read `GET /meta/:type/:name` now chooses its gate policy by what it serves. Its `?state=draft` branch serves the pending draft row, which is a stored version, so it runs `RestServer.STORED_VERSION_DOOR_POLICY` (`{ arms: 'per-caller', app: 'author-exempt' }`). Every other read on that route keeps `{ arms: 'all', app: 'gate' }`, including the `?preview=draft` render. - There is no second predicate and no route test in the gate. `metaItemReadGate` already attaches `MetaReadGateCaller.mayWriteItem` whenever the policy is `author-exempt`, from `RestServer.metaSaveVerdict`: the admission of `PUT /meta/:type/:name`, spelled once by PR objectstack-ai#20284. The draft read inherits that. - **For an app:** - a caller the app's save door admits reads the stored draft whole; - every other caller who may open the app reads it pruned per caller, exactly as before; - an app the plain read refuses whole (an app-level `requiredPermissions` the caller lacks, or an unpublished app to a non-builder) is still refused, to an author too. - **Per-deployment gates:** the ADR-0057 D10 `requiresService` arms (app, nav entry, dashboard widget) and the nav servability gate no longer run on the draft read, for any caller. See Acceptance notes item 4 for the measurement and the reasons. - Unchanged: `NO_DRAFT` (404) when nothing is pending, the docs audience on `doc` and `book`, and the object mask. **The shared gate** (`packages/rest/src/meta-item-read-gate.ts`): docblock only. Three sentences listed the doors each policy member serves and named "the plain read" as a rendered door without an exception. They now name the draft branch. No code changed. **Tests** - The census `meta-alternate-door-read-gates.test.ts` gains the draft read as a door, `?state=draft`, of kind `stored`. Its cells sit beside `/layers`, `?layers=true` and `/diff` for every subject and caller (36 new cells). - `AUTHOR_EXEMPTION` names four doors now, with `draftCarrier: '5859504238'`. - The scope pins hold the exemption to exactly the author's partial `crm` cells: 4 changed cells and 8 whole refusals kept. - Each authenticated draft cell asserts that the protocol was asked for `state: 'draft'`. - New: `meta-draft-read-author-exemption.test.ts` runs the real stack: better-sqlite3 `:memory:`, the real `sys_metadata*` objects, a real `ObjectStackProtocolImplementation` and the real routes. The only stubs are the auth boundary and the `tenancy` service probe. - An author holding `manage_metadata` but not `finance.access` reads the draft whole: the withheld entries, a draft-only entry and one whose service is off. - A member reads it pruned per caller (the control). - **A draft save by that author keeps `nav_finance_ledger`.** The test runs the editors' round trip: `/layers` effective, merged with the stripped draft, saved back through `PUT ?mode=draft`. It then reads the persisted `sys_metadata` draft row. - It widens nothing: the author's draft answer equals what `/diff` already serves them for the same history version. - The plain read and `?preview=draft` still prune for the author. - A whole refusal (`payroll`) stays `403` on the draft read. **Docs and release notes** - `content/docs/ui/apps.mdx` names `?state=draft` among the doors that answer by who is asking, and states that those doors apply no per-deployment gate. Its gate-table row now says "the rendered `/meta` body". - The two pending release notes are corrected in place (see the section below). This PR's own note is `.changeset/20290-draft-read-author-exemption.md`, `@objectstack/rest` `patch`. ## Verification **Tests**, at head `bd1361ee6`. `git diff bd1361e 8055937 -- packages/` is empty: the only change since is the one `apps.mdx` table row. - Census plus the new real-stack file: 303/303. - `@objectstack/rest`, `vitest run --project local`: 203 files, 3704 passed, 1 skipped, 0 failed. - `test:repo`: 8/8. - `@objectstack/rest` `typecheck` (`tsc --noEmit` plus the test layer under `tsconfig.test.json`): exit 0. `tsc -p tsconfig.test.json --listFiles` includes both test files (204 test files in the program). - `@objectstack/runtime` is not touched and no rest export changed, so no runtime test is owed. The dispatcher does not serve `?state=draft`; see Acceptance notes item 5. **Ablations**, committed fix first, at head `bd1361ee6`. - Each mutation ran through `scripts/ablation-replace.mjs` in wrap mode, inside a script with its own EXIT, INT and TERM trap that restores `packages/rest/src/rest-server.ts` from `HEAD` by absolute path. - Each restore was proven twice: the blob equals `HEAD` (`d5ccd775bb3b`) and `git diff HEAD` is empty. - The subject is imported by relative path (`./rest-server.js`), so the mutations act on source and no `dist` is involved. - Each prediction was written down before its run. | mutation | landed (anchor, blob) | predicted | result | |:--|:--|:--|:--| | A: the exemption off on the draft read (`{ arms: 'per-caller', app: 'gate' }`) | 1 → 0, `d5ccd775bb3b` → `4b8f055b9a0e` | 4 red | **4 red**: the census `?state=draft app/crm × author` cell; real stack: author reads whole, the draft-save round trip, "widens nothing" | | B: the exemption for everyone (`mayWriteItem: true`) | 1 → 0, `d5ccd775bb3b` → `f45c0e2167e9` | 7 red | **7 red**: `app/crm × non-reader` on all four stored doors (`?state=draft` included), the fault-path `/layers` edge, the org-presentation edge, the real-stack member control | | C: per-deployment arms back on the draft read (`{ arms: 'all', app: 'author-exempt' }`) | 1 → 0, `d5ccd775bb3b` → `ad2e5f485f20` | 4 red | **4 red**: `?state=draft dashboard/ops` × reader, non-reader and author; the real-stack member control (`nav_org_directory`) | **Gates**, at head `8055937f5`. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 91 families from merge base `10ea9eb2e`. Every command ran with its exit code captured before any pipe. - `--ran` reconciled the run: 91 derived, 91 run, 0 NOT-MEASURED, 0 UNRUN. - 90 exit 0. `node scripts/check-empty-changeset.mjs --base origin/main` exits 1 **by design** (next section). - `check:skill-examples`, `check:type-check-debt` and `check:dual-build-cjs-loads` first refused with exit 3, because the merge moved `packages/spec/src` and the client SDK was unbuilt. All three exit 0 once their named prerequisites were built: - `check:skill-examples`: 259 examples; - `check:type-check-debt`: 4 entries re-measured, none above its record; - `check:dual-build-cjs-loads`: 104 entry points across 66 packages. - Added by this lane: - `pnpm lint` (`eslint . --no-inline-config`, the whole repo): exit 0. It is a full run, not a narrowed one. - `pnpm --filter @objectstack/spec run check:liveness`: exit 0. - The board check `node scripts/check-issue-citations.mjs`, after merging `origin/main` at `10ea9eb2e`: exit 0 at the merge head, with 6 citations judged and all resolving. At the final head, `--base 10ea9eb`: exit 0, 5 of 5 resolve. `origin/main` then moved to `a78f731ad`, and `--base origin/main` against that unmerged tip exits 2. It counts 99 citations that objectstack-ai#20326 removed on `main` as if this change had added them. They sit in 21 files, none of them in this diff: a moving-ref reading, not a finding. ## A pending release note is corrected in place, so `Check Changeset` stays red `check-empty-changeset` names both notes: "present on the merge base and CHANGED by this PR". This is the **DELIBERATE CORRECTION** class. Its remedy text reads 「do NOT restore it -- say so on the PR and get it confirmed」 and 「this gate stays red either way」. Both notes are pending, not yet consumed by a Version Packages PR. Each said the plain read prunes for every caller, authors included, which this PR makes false for `?state=draft`: - `.changeset/20156-alternate-door-read-gates.md`, in the `/layers` / `?layers=true` / `/diff` bullet. - Before: "The plain read and `/published` prune for every caller, authors included." - After: "The plain read and `/published` prune for every caller, authors included, except the plain read's `?state=draft`: it serves the pending draft, a stored version, and answers as these three doors do." - `.changeset/20156-app-author-exemption.md`, in the "Unchanged" bullet. - Before: "Unchanged: the plain read and `/published` still prune for every caller, authors included." - After: "Unchanged: the plain read (its `?preview=draft` included) and `/published` still prune for every caller, authors included. The plain read's `?state=draft` is the exception: it serves the pending draft, a stored version, and answers as these three doors do." This PR's own note is `.changeset/20290-draft-read-author-exemption.md`. `skip-changeset` is not applied, because this PR publishes. ## Acceptance notes All readings below were taken on the real stack described above. The pre-fix readings are a one-shot probe at `de091b50e`, since removed. Its caller "author" holds `manage_metadata` only; "member" holds nothing; "finance author" holds `manage_metadata` and `finance.access`. `tenancy` is off. The app is published with `nav_leads`, `nav_finance_ledger` (`finance.access`) and `nav_org_directory` (`requiresService: 'tenancy'`). The finance author saved a draft that adds `nav_finance_forecast` (`finance.access`). **Item 1: the site, and the red re-measured through REST.** - The site is the uncached arm of `GET /meta/:type/:name`: `stateParam` sets `state: 'draft'` on `getMetaItem`, then the gate call ran `{ arms: 'all', app: 'gate' }`. - Before the fix, the author's `?state=draft` answered 200 with the draft's label and navigation `[nav_leads]`. `/layers` answered `[nav_leads, nav_finance_ledger, nav_org_directory]` on all three layers. **Item 2: what the draft read is.** - At `.objectui-sha` `f8a9d0fb` (a read-only clone), `MetadataClient.getDraft` sends `GET /meta/:type/:name?state=draft`, adding `&package=` when scoped, and maps 404 to `null`. - Both editors use it for their baseline, never `?preview=draft`: - `StudioDesignSurface.tsx`: about :1759-:1767 for the app (`{ ...eff, ...appDraftBody }`), and about :1885-:1893 for a nav leaf, whose type can be `dashboard`, `page`, `object`, `report` or `action`; - `ResourceEditPage.tsx`: about :1015-:1051 on load, :1509-:1518 after a draft save and :1686-:1699 after a publish. - With no draft pending, `?state=draft` answers `404` `{ error: "No pending draft exists for app/NAME.", code: "NO_DRAFT" }` (measured). It does not fall back to the active version: the protocol stops before the registry for a draft read. **Item 3: the premise, which holds on the stop condition as written.** - `/layers` does **not** serve the draft. `getMetaItemLayered` looks its overlay up with `state: 'active'` only, and the draft-only `nav_finance_forecast` was absent from every layer for every caller. - `/diff` **does**: - a draft save goes through `SysMetadataRepository.put` with `state: 'draft'`, which appends a full-body `sys_metadata_history` row (measured: version 1 is the active app, version 2 the draft with 4 entries); - before this PR, `/diff?from=0&to=2` served the author `[nav_leads, nav_finance_ledger, nav_org_directory, nav_finance_forecast]`, the co-author's draft whole, under ruling B's exemption on `/diff`. - So the exemption on the draft read discloses to an author nothing a ruled stored-version door does not already serve them whole. The test "it widens nothing" pins that permanently. - For a non-author the permission axis is unchanged: `nav_finance_*` is withheld before and after. Their only change is item 4's, from `[nav_leads]` to `[nav_leads, nav_org_directory]`, which equals what `/layers` and `/diff` already served the member before this PR. **Item 4: the arms.** - Before the fix, the draft read dropped `nav_org_directory` for **every** caller, the finance author who holds every entry's permission included (`[nav_leads, nav_finance_ledger, nav_finance_forecast]`). That is the same data-loss class: a save of the merged baseline deletes the entry. - The census shows the dashboard twin: `dashboard/ops` has its widget `w_org_kpi` bound to `tenancy`. The design surface loads dashboards through the same door. - Hence `STORED_VERSION_DOOR_POLICY`. The per-deployment arms need not stay for non-authors: - they withhold nothing from the caller (the `MetaReadGatePolicy` docblock); - the draft read is not a render door, since `?preview=draft` is, and it keeps `arms: 'all'`; - non-authors already read the per-caller-only answer on `/layers` and `/diff`. - Ablation C pins the choice. **Item 5: the dispatcher.** `packages/runtime/src/domains/meta.ts`'s item read passes `packageId`, `organizationId` and `previewDrafts` to `getMetaItem`, and never reads `state`. So on a host that serves only the dispatcher, `?state=draft` answers the active item under the rendered policy: never the draft, and never `NO_DRAFT`. It does not follow this rule because it does not serve this door. Left alone, as ordered, and reported for objectstack-ai#20320's family. This is a source reading at `bd1361ee6`, not measured through `dispatch()`. **Item 6:** see the section above. `content/docs/ui/apps.mdx` is corrected the same way. **Triage note 3: another read-to-display baseline saved back in objectui**, for the objectui seat. This is a source reading at `f8a9d0fb`, not measured at runtime. - `useMetadata().apps` is the list read, pruned per caller. - Two console paths publish an app built from that list, without `mode: 'draft'`: - `app-shell/src/hooks/useNavigationSync.ts` `saveApp`, via `NavigationSyncEffect` when a page or dashboard is created or deleted: `client.meta.saveItem('app', appName, { ...app, navigation: updated })`; - `apps/console/src/pages/system/AppManagementPage.tsx` `handleToggleActive` and `handleSetDefault`: `meta.saveItem('app', app.name, { ...app, ... })`. - A saving author who is withheld an entry, or an entry whose service is off here, would publish the app without it. - A server change here cannot reach these paths: the list read is read-to-display by ruling B, so the client must read what it saves from a stored-version door. **Deviation from the claim's file surface.** The claim admits `meta-item-read-gate.ts` "only if the policy type needs a member for the draft read". This PR changes no member there. It edits three docblock sentences that this change made false, and no code. The change is declared here for confirmation. **Observed, not in scope.** The draft reads carry no builder gate: a member who may open an app reads its pending draft (pruned per caller) through `?state=draft` and `?preview=draft`. ADR-0037's risk table plans 「confirm/add a builder/admin role gate on the dispatcher reads」. This PR does not change who may read a draft: the non-author answer is unchanged on the permission axis. It is reported to the seat. ## Not addressed here - objectstack-ai#20139 remains open: the bare-number query reads in `rest-server.ts`. - objectstack-ai#20320 remains open: the dispatcher's divergences. Item 5 above is a candidate row for it. - The objectui paths above remain for the objectui seat. --- _Generated by [Claude Code](https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Part of #20234
Clause-②: no
What changed
This is stage 1 of the staged sweep, covering
packages/spec/src/kernel/**andpackages/spec/src/contracts/**and nothing else. Later stages cover the other areas, so this PR carriesPart of.Every comment or docblock site in these two areas that cited a tracker number answering 404 has been rewritten in ruling C+D's form C (comment 5749154545 on #19123): 160 sites on 151 lines in 45 files, covering 47 numbers (152 lines rewritten). Each rewritten line now cites the object this repository controls that decided the matter:
origin/mainhistory that decided it.Each line also says in its own words what that object decided. Where nothing answers, the sentence keeps its reason in words and the number is gone: that happened for four numbers.
Only comments changed. Every file keeps its line count (152 lines out, 152 in), so no line citation into these files moves. No code token moves (see the guard below). String literals carrying a dead number are tokens: 30 such sites are left as they were and listed below.
No citation number is added. Every tracker number on an added line was already on the line it replaces. That includes the two PR numbers now standing beside their shas as convenience links: PR #6900 beside
b5404f496, and PR #7211 beside1507ba356.Census: this stage's two areas, before and after
Instrument. This is PR #20226's instrument: REST
GET /repos/objectstack-ai/objectstack/issues/Nwithout following redirects, over every distinct in-repo number cited in the two areas. The population is:#N,objectstack#N,framework#N, and thepre-#N/post-#Nspellings, with N of 100 or more;PD, decisionbatch) andsummon.Controls. The lit controls were
#16862,#16847and#17698. The dead controls were#16714,#16715and#16697. They were probed at the start, after every 100 numbers and at the end: 6 checkpoints per run. They read 18 of 18 lit (200) and 18 of 18 dead (404) in both runs.6a6a17b62, probed 2026-09-27T20:14Z to 20:16Zeda5c6b27, 2026-09-27T21:24Z to 21:26Z; source identical at the final head)Before, by class.
After. Only the 30 string sites remain. There are 0 comment sites. The head probe found no number newly dead since the base probe.
PR #20226's area table read kernel 105 and contracts 81 at an earlier base. This census reads 106 and 84 because it also counts the
pre-#N/post-#Nspelling: 3 dead sites.Per-number table
The site counts give comments rewritten and strings left. The kind column says what each line now cites:
#597097e7e3caa:ActionSchema.visiblegains the boolean arm#608353068c130: find and findOne pinned to the parsed state#6206d7e0b4212: maintainer ruling 2026-08-07, enforcement takes the full envelope with no per-site subset. One site cites8e13ca876, the route half that restored the five dropped fields. Two name the ruling in words where the same block already cites the sha#6216f586f1a89: one ExecutionContext assembler, closed field-set pin#630074155c735: find and findOne accept the author state#636190bbf2510: notification-listcursorretired on both halves#6362b5404f496(PR #6900 beside it):connectorkeeps the ADR-0010 envelope#636317d095413:unreadCountcounts the whole inbox, not the window#6483ee58392e1: nine unratifiedallowOrgOverride: truerolled back#6511(a PR)d7e0b4212, its squash commit#6523aa4b90d9a: sharing and approval enforcement take the full ExecutionContext#66402ab1257c9:preserveAuditis UPDATE-only, with a loud INSERT warn#6723(a PR)8ad609c69, its squash commit: getObject's declared answer#67251507ba356(PR #7211 beside it): facade object writes reach the map its reads use#67457a5ef0008: the getObject-equals-get conformance pin#87152c86fe3ea: the retirement pin form overexport-origins/#8794,#88361850ebbb0: measured the filter-reuse invariant and pinned it#101942306a765c: theme and analytics_cube bound at the /meta door#10238559041d39leaves it open)#10338d2619fd0c:ApiEndpoint.targetoptional, the publish gate holds the requirement#1048535ad101bc:themescarrier and ThemeSchema retired#10627be21955ba, whose message records that controlled census#10724be21955ba: nine deadcontributesmembers tombstoned#10726bc56e1881:contributes.routesretired, ruled Option B#10812be21955barecords)#1107150fb191dc:os generatefile names derived from the registry, with the parity pin#11330a9ee98992: trust-tier text states publish-gate-only enforcement#11331#11332dce5cd4f0: three dead manifest containers retired#11333aaacf1d5c: the commit that corrected the permissions half#11350ece4dad31, which records the 2026-08-23 entry-nameability ruling#11504f90e82024:FLOW_INPUT_SCHEMA_INVALIDregistered#11741b706af987:SendEmailInput.organizationId#118460c2334f6c: preview mode retired#12010ConnectionEngineLikeinventory is described in words#12165b307bfd2a: the glob-discovery disposition recorded besidefilePatterns#122488425c17cc: the five ruled engine members adopted, getObject typed#131359e0ba21a1: paper customization protocol retired. ADR-0126 section 6 wall 4 stays cited where the line had it#13608fc9ba76a5: eligibility held at redemption#14143f19475c0a: the handler-facectx.recordLoadDeniedsignal#14192#1472223c72be3c: pinned the measurement that refuted that card's premise#16559c7aca0dce: ResumeFailureReport declared once#167866059b29c0:updateByIddeclares its answer#17147aaacf1d5c: the granted permission set is registered and refuses nothing#18335Every cited sha resolves to exactly one commit, and every one is an ancestor of
origin/main(38 shas, eachmerge-base --is-ancestorexit 0).The 30 string sites left as tokens
data-engine.test.ts(4),objectql-engine.test.ts(2),email-service.test.ts,resume-failure-report.pin.test.ts,scoped-context.test.tsandsharing-service.test.ts(1 each).manifest-unknown-keys.test.ts(4),manifest.test.ts(4),preview-mode-retirement.test.ts(4, one of them an assertion message),plugin-runtime-tier-truthful-text.test.ts(3), and 1 each inmetadata-customization-retirement.test.ts,metadata-type-api-registration.test.tsandmetadata-type-schemas.test.ts.why:strings on rows of the exportedMETADATA_ROUNDTRIP_CASEStable incontracts/metadata-service-roundtrip-conformance.ts(lines 194 and 202). They ship in the package as data. No runtime path prints them to an author: both test drivers title each case by itsid. So they are not author-shown text in the form D sense, and they are not rewritten here.Mechanical guard: no code token moves
The check is a comments-stripped token comparison, base
6a6a17b62against the head. It uses the TypeScript parser's leaf tokens, so template literals are scanned in context, and it excludes JSDoc nodes. It ran over all 45 touched.tsfiles.Changeset
This change ships bytes, so a
patchchangeset for@objectstack/specis included; it says only that provenance comments were re-anchored.Measured on the built package: rewritten docblocks reach
dist/**/*.d.ts. For example,8425c17cc,17d095413,aa4b90d9aandfc9ba76a5each appear in 1 declaration file, and the positive control, a pre-existingnotification-servicedocblock sentence, appears indist/contracts/index.d.ts. Rewritten comments also reach the bundled.js:be21955baappears in 20 files. Thesrc/**/*.zod.tssources ship verbatim throughfiles[].Gates (head
ebbea0b6e)pnpm check:issue-citations && node scripts/check-issue-citations.mjsexits 0. It judged 23 citations: 21 resolve and 2 resolve as pull requests (the two convenience links).pnpm check:doc-authoringexits 0.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 86 families, and all 86 exit 0.--ranreports 86 run, 0 NOT MEASURED, 0 unrun, and exits 0. Five of them (check:doc-formula-expressions,check:dual-build-cjs-loads,check:i18n,check:lean-entry-closure,check:type-check-debt) first exited 3, PREREQUISITE NOT MET. They exited 0 after a fullturbo run buildof./packages/*(71 tasks, exit 0, under the shared verify lock).pnpm --filter @objectstack/spec buildexits 0.vitest run src/kernel src/contractsinpackages/spec: 99 files and 1,608 tests pass. That covers all 24 touched test files and every test here that reads contract source text.pnpm --filter @objectstack/spec typecheckexits 0, includingcheck:test-typecheck.Acceptance notes
origin/main(4e0f72e8d). None of those commits toucheskernel/,contracts/or any file here, so there was no merge.pre-#Nandpost-#Nas a cross-repository qualifier (pre-), so it never judges them. In these two areas that is 18 sites at base, 3 of them dead. This census counted them by hand.framework#Nis NOT MEASURED as a repository.objectstack-ai/frameworkanswers 403 to this session's REST gate. The five numbers cited that way resolve 200 in this repository. None of them is in the dead set.#13003notes inpackages/spec/liveness/permission.jsonare outside this stage, as the claim records.Generated by Claude Code