Skip to content

docs(service-analytics): the source comments state the ruled deny for a deployment with no security service - #22299

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-22279-analytics-source-comments
Oct 8, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-22279-analytics-source-comments

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #22279

Clause-②: no

This is the source-comment half of #22279: comments only, plus the patch changeset their published text needs. The release-owned text is in the docs-only PR #22296. The card stays open until both PRs have merged.

Why

Maintainer ruling B on #22235 (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."

PR #22276 (58707166f) rewrote the bridge comments in plugin.ts and the test header to that ruling. The comments here are the ones its acceptance notes listed outside its fence. Each one equated "no provider wired" with "a deployment with no security service" and said such a deployment keeps its analytics behaviour. Through AnalyticsServicePlugin a provider is always wired, either the host's own or the bridge. On ObjectKernel and LiteKernel the lookup of a security service that was never registered throws, so the bridges take UNUSABLE and refuse the query, fail-closed.

The new text follows the plugin.ts wording on main. ⛔ It does not say the ABSENT branch denies. ABSENT is described as reached only by a context that answers the lookup with nothing (the package's test doubles do, and no in-repo kernel does). Whether ABSENT itself should deny is not ruled.

What changed (comments only)

Line positions are at base 58707166f.

File Site Listed on the card?
read-admission.ts module header, Fail direction, :51-65. The ABSENT bullet is replaced by three bullets: the declared deny on a deployment with no security service, the ABSENT context, and a host that constructs AnalyticsService with no provider. The lead-in "but closed is a claim about a WIRED provider" goes. yes (:59-65)
analytics-service.ts AnalyticsServiceConfig.admitObjectRead doc, :842-845 yes
analytics-service.ts AnalyticsServiceConfig.getReadableFields doc, :862-866 yes
analytics-service.ts assertReadAdmitted doc, :1899-1901 (the card's :1897-1899) yes
field-read-admission.ts assertCallerMembersJudgeable header, :338-341 yes (:339-341)
analytics-service.ts the [#20917] field-level read gate doc, :1922 "A no-op when no provider is wired (no security service)". It documents assertFieldsReadable but sits detached, directly above the member-shape gate's doc. added
analytics-service.ts assertCallerMembersResolvable doc, :1935 "that gate is a no-op with no security service" added
analytics-service.ts assertDatasetFieldsJudgeable doc, :2061 "which stands down with no security service" added
read-scope-refusal.ts readScopeUnresolvedError doc, :96-99: "a deployment with no security service … is reported loudly at init, and it must keep running unscoped exactly as before" added

The four added sites (bounded in-place fix, declared here)

The card listed four sites, taken from PR #22276's acceptance notes. A census of the package's src/ for the same claim, git grep -n -i 'no .?security.? service' outside __tests__, found four more. Three are in analytics-service.ts, a file this card already holds. The fourth is the row-scope sibling of the read-admission header. All four meet the four conditions: the same defect class as the card, a mechanical rewording to a shape the ruling already fixed, the same gates, and no other claim on the file (read-scope-refusal.ts is in none of the 12 open PRs' file lists, which were read during this run before the edit). Leaving them would keep the claim alive twenty lines below the doc this PR corrects. Reviewer: if you want any of them out, say which and it comes back in a patch round.

Proof that only comments moved

For each of the four files, ts.transpileModule with removeComments: true gives byte-identical output for the base file and for this head:

read-admission.ts        base=8a4829c31e94d58c/1351   head=8a4829c31e94d58c/1351
analytics-service.ts     base=8dd74af6788b7660/65291  head=8dd74af6788b7660/65291
field-read-admission.ts  base=9be45d2722f380cd/5145   head=9be45d2722f380cd/5145
read-scope-refusal.ts    base=badef6b1c177459d/233    head=badef6b1c177459d/233

(sha256 prefix / bytes.) Positive control: the same comparison over read-scope-refusal.ts with err.status = 500 changed in memory to 501 reports the stripped outputs as different.

Changeset: patch for @objectstack/service-analytics, not skip-changeset

AGENTS.md: published means what files[] ships, and this package ships ["dist","README.md","CHANGELOG.md"]. After a rebuild of the package (under the verify lock), the edited JSDoc is in the published output:

  • "That is not a deployment with no security service" (the two AnalyticsServiceConfig docs) is in dist/index.d.ts and dist/index.d.cts.
  • "without admitObjectRead. AnalyticsServicePlugin always wires one" and "no-op with no field reader wired" (class-member docs) are in all four of dist/index.{js,cjs,d.ts,d.cts}.
  • "a deployment that registers NO security service denies" (the module header) is in dist/index.d.ts and dist/index.d.cts.
  • Control for that reading: the read-scope-refusal.ts phrase "their lookup throws on the never-registered name" is in 0 files, because a non-exported function's doc is not emitted. A runtime string from plugin.ts is in 2 files.

The published @objectstack/service-analytics@17.6.0 tarball carries the old sentences in the same files. "the deployment has no security service, which" and "keeps its pre-existing analytics behaviour" are in its index.d.ts and index.d.cts. "A no-op when no provider is wired: that is a deployment with no security" is in all four. So this diff changes published bytes and takes a patch: .changeset/22279-analytics-absent-security-comments.md.

This differs from PR #22276, which carried skip-changeset. Its plugin.ts comments sit inside a function body, measured at 0 files under dist/. Here the comments are on an exported interface and on class members, which the build keeps.

Verification (head 7fb9cee98)

  • @objectstack/service-analytics was built under the verify lock: its dependency closure, then the package itself. check-dts-emitted found "2/2 declared declaration file(s) present".
  • pnpm --filter @objectstack/service-analytics typecheck exits 0.
  • pnpm --filter @objectstack/service-analytics exec vitest run --maxWorkers=2: "Test Files 180 passed (180)", "Tests 4443 passed | 262 skipped (4705)". These are the same counts PR fix(service-analytics): declare the measured deny on a kernel with no security service, pin it on both in-repo kernels, give the reconcile runner an explicit security double #22276 recorded.
  • Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 58 commands. Each was run with its exit code captured before any pipe. 57 exit 0. 1 is NOT MEASURED: pnpm check:dual-build-cjs-loads exited 3, PREREQUISITE NOT MET, because 65 workspace packages have no dist/ in this worktree. A targeted substitute reading: require('./dist/index.cjs') of this package loads, with 17 exports and AnalyticsServicePlugin a function. dispatch-gates --ran gives: "58 derived, 57 run, 1 NOT-MEASURED, 0 UNRUN."
  • Named results: check:dts-closure reports 75/75 declaration files across 15 built packages. check:sourcemap-no-sources-content reports 105 maps across 15 packages, none embedding source. check:published-files, check:nul-bytes (10246 tracked files, no raw control bytes), check:doc-authoring, check-empty-changeset ("1 declaring changeset(s) added") and check:lean-entry-closure all exit 0. Locally, check-changeset-no-major reads its clause-② level axis as not applicable, because there is no pull_request payload. CI reads this body's Clause-②: no.
  • Lint, narrowed: eslint --no-inline-config --format json over the 4 touched source files reports 4 files, 0 errors and 0 warnings. The config's only global ignores are node_modules, dist, build, .next and .turbo, so all 4 files are in scope. The config never enables type-aware linting (no parserOptions.project in eslint.config.mjs), so this diff cannot change the verdict on a file it does not touch. The repo-wide pnpm lint is left to CI.

Acceptance notes

  • Not here, per the card: the runtime UNUSABLE log text ("A security service is wired on this deployment") in plugin.ts and read-admission.ts, and any change in behaviour.
  • Two test titles still say "no security service" for a double that answers the lookup with nothing. One is the describe at admission-absence-report.test.ts:199, the other the tier label at caller-member-column-reference-gate.test.ts:109. Test names are outside this comments-only fence. Noted, not filed. Carrier: none.

Generated by Claude Code

claude added 2 commits October 8, 2026 12:42
… a deployment with no security service

Comments only. The read-admission module header, the admitObjectRead and
getReadableFields docs on AnalyticsServiceConfig, the assertReadAdmitted,
assertFieldsReadable and member-gate docs, the field-read-admission member
gate header and the row-scope refusal doc each equated "no provider wired"
with "a deployment with no security service" and said such a deployment
keeps its analytics behaviour. AnalyticsServicePlugin always wires the
providers, and on ObjectKernel and LiteKernel a never-registered `security`
lookup throws, so the bridges take UNUSABLE and refuse, fail-closed.

A comment-stripped transpile of each file is byte-identical to the base.

Claude-Session: https://claude.ai/code/session_0115N1oNnQS5WqofZ2DzaT3q
Co-authored-by: Claude <noreply@anthropic.com>
…ted API doc comments

The edited JSDoc ships: after a rebuild the new phrases occur in
dist/index.d.ts and dist/index.d.cts (and the class-member ones in
dist/index.js and dist/index.cjs), and the published 17.6.0 tarball carries
the old sentences in the same files.

Claude-Session: https://claude.ai/code/session_0115N1oNnQS5WqofZ2DzaT3q
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added the size/s label Oct 8, 2026
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/service-analytics, touching 2 documentable anchor(s). ⚠️ 3 changed file(s) yielded no anchor (packages/services/service-analytics/src/field-read-admission.ts, packages/services/service-analytics/src/read-admission.ts, packages/services/service-analytics/src/read-scope-refusal.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

⛔ 3 release-owned page(s) name something this change touched. These are read-only:

  • content/docs/releases/v17/17-5.mdx (via AnalyticsService (symbol, a top-level class))
  • content/docs/releases/v17/17-6.mdx (via AnalyticsService (symbol, a top-level class))
  • content/docs/releases/v17/17-7.mdx (via AnalyticsService (symbol, a top-level class))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/services/service-analytics/src/field-read-admission.ts, packages/services/service-analytics/src/read-admission.ts, packages/services/service-analytics/src/read-scope-refusal.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 238222d8cd412ca77c816fa1f849c991ed84f251 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8627ba999a1b8dafecc316ad1ae0bc053159c565 — the merge of head 7fb9cee9875bccc483711810842f9030d55313f1 into base 238222d8cd412ca77c816fa1f849c991ed84f251, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8627ba999a1b8dafecc316ad1ae0bc053159c565 && git checkout 8627ba999a1b8dafecc316ad1ae0bc053159c565
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 238222d8cd412ca77c816fa1f849c991ed84f251 7fb9cee9875bccc483711810842f9030d55313f1 && git checkout -B drift-repro 238222d8cd412ca77c816fa1f849c991ed84f251 && git merge --no-ff 7fb9cee9875bccc483711810842f9030d55313f1

node scripts/docs-audit/affected-docs.mjs --json 238222d8cd412ca77c816fa1f849c991ed84f251

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 238222d8cd412ca77c816fa1f849c991ed84f251 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

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

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants