Repository navigation
Commit 98cce87
docs(releases): amend the released "absent security admits analytics reads" sentences to the measured deny (#22296)
Part of #22279
Clause-②: no
This is the docs-only half of #22279. It amends release-owned text and
nothing else. The four `service-analytics` source comments are in a
separate PR, on branch `claude/issue-22279-analytics-source-comments`.
The card stays open until both PRs have merged.
## Route: amend each entry in place and add a dated erratum inside it
AGENTS.md, *Documentation Guardrails*, the `packages/*/CHANGELOG.md`
row: "Factual error in a released entry → **amend that entry in a
dedicated docs-only PR**, ⛔ never an erratum in a later entry and never
a rider on code changes". The `content/docs/releases/` row: "Factual
error on a releases page → dedicated docs-only PR or an issue, never a
rider on code changes."
Triage asked this PR to say which route it took: "⛔ No silent rewrite of
a published CHANGELOG line, if that process forbids one; the PR states
which route it took."
The route: each false passage is corrected inside the entry that
published it. Each amended entry also gets one dated line at its own
end, in the form `*Erratum, 2026-10-08 — this entry said "…". …
(Corrected after publication, #22279.)*`. That line quotes the wording
that shipped. Earlier in-place amendments in these files use the same
shape, for example 5b481e2 and 576afc1 in
`packages/spec/CHANGELOG.md`, and the bulk-callers bullet on the 17.0
release page. So nothing is rewritten silently. The shipped wording is
quoted in the entry, kept in the published tarballs and kept in git
history. No later entry is written, and no changeset is added (see
below).
## Why: maintainer ruling B on #22235
Ruling `6056824332` (「同意」, 2026-10-08), verbatim: "**B — deny, as
measured, becomes the declaration.** On a deployment with no security
service the analytics read bridges deny, fail-closed, as they do today;
the bridge comments and the header of
`admission-bridge-resolution.test.ts` say so; the "absent admits"
sentence in the released text is corrected by a docs card, since that
text is release-owned."
The sentences were false when they were published, not only now.
Measured on the published tarballs (`npm pack`, unpacked into a scratch
directory):
- `@objectstack/core` 17.5.0 and 17.6.0: the context `getService` of
both `ObjectKernel` and `LiteKernel` throws `[Kernel] Service 'NAME' not
found` for a name that was never registered.
- `@objectstack/service-analytics` 17.5.0 and 17.6.0: the object-level
bridge catches that throw as `unusable` and denies. Its `if
(resolved.kind === "absent") return true;` line is reached only when the
lookup returns nothing. The row-scope bridge does the same and throws
`readScopeUnresolvedError`. In 17.6.0 the field-level bridge throws as
well. In both releases `assertReadAdmitted` runs before
`resolveReadScopes`.
The new text states what was ruled: on a deployment with no security
service the bridges deny, fail-closed. ⛔ It does not say that the ABSENT
branch denies. ABSENT is described as a state reached only by a context
that answers the lookup with nothing, and no in-repo kernel does that.
This matches the bridge comments that PR #22276 landed on `main`
(`58707166f`).
## What changed
Line positions are at base `58707166f`. These files have not changed
since `3513ac77`, where the card read its positions.
| File | Entry | Passage | Listed on the card? |
|---|---|---|---|
| `service-analytics/CHANGELOG.md` | 17.6.0 `1571aed` | `:583-584`
"applies no field-level check, as on the data API" | yes |
| same | 17.6.0 `5f6b63a` | `:645-647` "applies no object-level check,
as on the data API" | yes |
| same | 17.6.0 `ce4e205` | `:821` "the field-level read gate, which
stands down with no security service" | **added** |
| same | 17.6.0 `ae1e950` | `:1211-1213` "A deployment with no security
service, and an object …, apply no field-level check" | yes |
| same, and the three lockstep copies | 17.5.0 `041d9fd` | `:1917-1919`
BREAKING banner, "Nothing that was already admitted becomes refused
**except** the requests GET /data/OBJECT refuses" | **added** |
| same, and the three lockstep copies | 17.5.0 `041d9fd` | `:1926`
"keeps its previous analytics behaviour by design" | yes |
| same, and the three lockstep copies | 17.5.0 `041d9fd` | `:1930` "an
ABSENT `security` service admits (… keeps a deployment shipping no
`plugin-security` working as before)" | yes |
| same | 17.5.0 `5d12b16` | `:1936` "ABSENT admits, THROWING and
METHOD-LESS deny" | yes |
| same | 17.5.0 `5d12b16` | `:1952` ABSENT row, "a legitimate
configuration … ⛔ Deliberately not tightened" | yes |
| same | 17.5.0 `5d12b16` | `:1955` "and no deployment with none,
changes behaviour by so much as a byte" | **added** |
| same | 17.5.0 `54b3d1d` | `:2773` "a deployment with NO security
service still runs unscoped exactly as before" | yes |
| `content/docs/releases/v17/17-5.mdx` | object read grant bullet |
`:482-486` "keeps its old behaviour and warns at init" | yes
(`:482-484`) |
The lockstep copies are `plugin-security/CHANGELOG.md` (`:1666-1668`,
`:1675`, `:1679`), `spec/CHANGELOG.md` (`:13365-13367`, `:13374`,
`:13378`) and `verify/CHANGELOG.md` (`:562-564`, `:571`, `:575`). After
the edit the `041d9fd` entry is still byte-identical in all four files:
27 lines each, sha256 prefix `a7ff1b99f2de9992`. The four copies were
also identical before the edit.
Each amended entry gets one erratum line: seven in
`service-analytics/CHANGELOG.md`, one in each lockstep copy and one in
the release-page bullet. On the release page, the migration line also
gains the remedy for a deployment with no security service: register
one, or supply `admitObjectRead`.
### The three added passages (bounded in-place fix, declared here)
The card did not list these. Each makes the same claim and sits inside
an entry this PR amends, or in the same file:
- `:1917-1919` (all four copies): on a kernel with no security service,
analytics reads that 17.4 served became refused, while `/data` still
serves them. Left alone, the banner would contradict the amended `:1926`
three paragraphs below it in the same entry. One clause is added.
- `:1955`: the same entry as `:1936` and `:1952`, with the same claim.
- `:821`: the claim `:1211` makes, in another 17.6.0 entry of the same
file.
All three meet the four conditions: the same defect class as the card, a
mechanical rewording to a shape the ruling already fixed, a file this
card already holds, and the same gates. Reviewer: if you want any of
them out, say which and it comes back in a patch round.
## Not changed, on purpose
- The ADR-0087 disposition marker of the `041d9fd` entry (`:1912`) is an
HTML-comment line that does not render. Its prose also says the
narrowing is "the same verdict GET /data/OBJECT already returns". It is
the machine-read disposition record, its category (`not-required`) does
not change, and it is left as published.
- `:1930` still says the plugin "warns loudly at init when no security
service is registered". That stays because 17.5.0 and 17.6.0 did print
that warning at init (measured in both tarballs). Only what the bridge
then does is corrected.
- `:1244` says the 17.6.0 member gate refuses "in every tier — including
a deployment with no security service". That is true, so it stays.
`:1948` describes the value the pre-fix code produced for an absent
service. That is history, so it stays too.
- Not here, per the card: the runtime UNUSABLE log text in `plugin.ts`
and `read-admission.ts`, and any change in behaviour.
## Changeset: none, labelled `skip-changeset`
This follows 5b481e2 and 576afc1. `CHANGELOG.md` is in each
package's `files[]`, so the next tarball ships the amended text. A
changeset is still the wrong tool here. It would compile the correction
into a new entry under a later version. That is the "erratum in a later
entry" the guardrail rules out, and this PR changes no package code.
`changeset version` prepends to these files and keeps the amended
entries. All four packages are in the single `fixed` group of
`.changeset/config.json`, and 101 changesets are pending on `main`, so
the next release carries the corrected entries.
## Verification (head `2bd53e98a`)
- Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives **85** commands for this diff. Each
was run with its exit code captured before any pipe. **79 exit 0.** **6
are NOT MEASURED**: each exited 3, `PREREQUISITE NOT MET`, because it
reads build output this docs-only worktree does not hold.
- `pnpm --filter @objectstack/spec run check:skill-examples`: its
client-SDK half needs a 36-package build of the `@objectstack/client`
and `@objectstack/client-react` closure.
- `pnpm check:i18n`: needs the CLI closure, 61 packages.
- `pnpm check:dts-closure`, `pnpm check:dual-build-cjs-loads`, `pnpm
check:lean-entry-closure` and `pnpm check:sourcemap-no-sources-content`:
need a full workspace build.
- This narrowing is declared. The diff changes no source byte. A build
compiles `src/` and never reads `CHANGELOG.md` or `.mdx`. CI's `Lint &
Repo Gates` runs these gates after its own closure build.
- `node scripts/pm/dispatch-gates.mjs --ran` gives: "85 derived, 79 run,
6 NOT-MEASURED, 0 UNRUN."
- The `@objectstack/lint` closure (lint, formula, spec, sdui-parser) was
built under the verify lock first, so these gates were measured rather
than refused: `check:docs` ("225 generated files in sync"),
`check:doc-formula-expressions`, `check:doc-security-posture` and
`check:docs-transcript-drift`, all exit 0. The build left the working
tree clean.
- Named results: `check:nul-bytes` scanned 10245 tracked files and found
no raw control bytes. `check:release-notes`,
`check:release-page-status`, `check:doc-authoring` and
`check:issue-citations` all exit 0. A separate control-byte grep over
the five files matches nothing.
- Lint: `eslint --no-inline-config --format json` over the 5 files
reports 5 files, each "File ignored because no matching configuration
was supplied". No config object matches `.md` or `.mdx`, so `pnpm lint`
has nothing to judge here.
## Acceptance notes
- Two test titles say "no security service" where they mean a test
double that answers the lookup with nothing.
`admission-absence-report.test.ts:199` names its describe "no security
service ever registered (the ABSENT resolution)".
`caller-member-column-reference-gate.test.ts:109` labels a tier "no
security service (no field reader wired)". Test names are outside a
docs-only PR and outside a comments-only PR. Noted, not filed. Carrier:
none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_0115N1oNnQS5WqofZ2DzaT3q)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 799eb00 commit 98cce87
5 files changed
Lines changed: 68 additions & 33 deletions
File tree
- content/docs/releases/v17
- packages
- plugins/plugin-security
- services/service-analytics
- spec
- verify
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
480 | 480 | | |
481 | 481 | | |
482 | 482 | | |
483 | | - | |
484 | | - | |
485 | | - | |
486 | | - | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
487 | 493 | | |
488 | 494 | | |
489 | 495 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1665 | 1665 | | |
1666 | 1666 | | |
1667 | 1667 | | |
1668 | | - | |
1669 | | - | |
| 1668 | + | |
| 1669 | + | |
| 1670 | + | |
1670 | 1671 | | |
1671 | 1672 | | |
1672 | 1673 | | |
1673 | 1674 | | |
1674 | 1675 | | |
1675 | | - | |
| 1676 | + | |
1676 | 1677 | | |
1677 | 1678 | | |
1678 | 1679 | | |
1679 | | - | |
| 1680 | + | |
1680 | 1681 | | |
1681 | 1682 | | |
1682 | 1683 | | |
| 1684 | + | |
| 1685 | + | |
1683 | 1686 | | |
1684 | 1687 | | |
1685 | 1688 | | |
| |||
0 commit comments