Skip to content

docs(spec,service-datasource): name the three CryptoContext producer vocabularies and narrow the AAD guarantee - #12838

Merged
os-sales merged 2 commits into
mainfrom
claude/issue-12599-cryptocontext-doc-drift
Aug 28, 2026
Merged

docs(spec,service-datasource): name the three CryptoContext producer vocabularies and narrow the AAD guarantee#12838
os-sales merged 2 commits into
mainfrom
claude/issue-12599-cryptocontext-doc-drift

Conversation

@claude

@claudeclaudeBot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Fixes#12599

Option A of the maintainer ruling of 2026-08-27 (comment 5434987411, verbatim 「其他同意」): the contract prose tells the truth now. Zero behaviour change, zero schema shape change.

What was wrong

CryptoContext.namespace / .key documented themselves as a settings coordinate ("Settings namespace the value belongs to" / "Specifier key within the namespace"), one layer below the three producers that actually construct the type. Re-verified on this branch's base:

producerctx.namespacectx.keywhere handle.id is recorded
SettingsService (settings-service.ts:1639)settings namespacespecifier keysys_setting.value_enc
the ObjectQL engine's secret-field path (engine.ts:6053)object namefield namea secret: ref on the business row
the datasource secret binder (datasource-secret-binder.ts:~93)caller-supplied, default datasourcedatasource namea sys_secret: credentialsRef

What changed

The load-bearing correction is the AAD sentence. It read "Helps reject ciphertexts that were copied across namespaces", which overstates what a binding over this pair can provide: (namespace, key) is one flat space shared by all three vocabularies, sys_secret declares the pair non-unique by design, and nothing reserves a name in one vocabulary against another. It is replaced by the guarantee that actually holds — such a binding rejects a swap within one producer's vocabulary and does not exclude a cross-vocabulary pair, with the constructible mail|api_key case named concretely. Per the ruling, the flat shared space is documented as current reality, not the intended end state, and the docblock says so in as many words.

The rest of the file follows the same correction: the ICryptoProvider header gains a "Producers" section naming all three, and CryptoHandle.id, the lifecycle list, encrypt() and rotateKey() stop describing sys_setting.value_enc as the general destination of a handle.

Folded in per the ruling (recorded on the card, no separate issue): the identical settings-only prose on DatasourceSecretBinderDeps.namespace — "Settings namespace recorded on the secret row".

Why a changeset rather than skip-changeset

Measured, not assumed. gen:docs regenerates 229 files with zero delta, so — contrary to the usual argument for spec docblocks — these comments are not reader-visible reference pages. But packages/spec emits its TSDoc into the published .d.ts, so the corrected prose is what every @objectstack/spec consumer reads at the call site. That ships, so it gets a patch changeset for both packages.

The ADR is deliberately not cited by number here

Direction B is recorded in a companion draft PR adding docs/adr/0128-*.md, which waits on the maintainer's hand-merge. Citing ADR-0128 from this PR would turn check:adr-anchors red — it hard-fails a citation naming no record under docs/adr/ — on this PR and then on main until the ADR lands. So the docblock names the intended end state in prose without an id, and the ADR cites the contract rather than the reverse. Each PR is independently green in either landing order.

Verification

Union re-run after the final commit, at 9cb1c6eb (origin/main@f907fbe9 merged in). Gate set derived by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack from the actual changed set — 32 families, exit codes captured before any pipe.

  • 33 of 35 green (the 32 derived families plus check:adr-anchors, check:adr-links, check:nul-bytes).
  • Regeneration is a no-op: pnpm --filter @objectstack/spec build (which runs gen:schema + gen:openapi) and gen:docs both leave git status showing only the source edits. check:authorable-surface and check:docs green.
  • typecheck: @objectstack/spec + @objectstack/service-datasource, scope 2 of 79, both echoed — green.
  • test: @objectstack/spec 436 files / 11560 tests passed; @objectstack/service-datasource 27 files / 585 tests passed.
  • Two families produced no reading and are reported as NOT MEASURED, not green, both on their own printed PREREQUISITE NOT MET line: check-dev-prereqs (the container's workspace is not fully built — 66 of 67 packages have no dist/) and scripts/pm/check-half-states.mjs (exit 3 — no valid GitHub credential in this container; it swept no issue and ran no predicate). Neither reads this diff; CI runs both.
  • Declared lint narrowing (a measurement, not a skip): eslint run targeted rather than repo-wide, --no-inline-config --format json — 2 files linted, 0 errors, 0 warnings. Population read from eslint's own config, not guessed: the changeset .md reports "File ignored because no matching configuration was supplied", so the two TS files are the whole of this diff's eslint population. Invariance for untouched files: eslint.config.mjs never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for any file — stated in the config with its own positive-control measurement — so this diff cannot move the verdict on a file it does not touch.

Landing is serialized behind #12718 and #12737 per the generated-artifact relay; the PM lands. Not flipped ready or enqueued.


Generated by Claude Code

os-salesand others added 2 commits August 28, 2026 02:13
…vocabularies and narrow the AAD guarantee (#12599)
`CryptoContext.namespace` / `.key` documented themselves as a settings
coordinate, one layer below the three producers that construct the type:
SettingsService (settings namespace / specifier key), the ObjectQL engine's
secret-field path (object name / field name) and the datasource secret binder
(caller-supplied namespace, default `datasource` / datasource name). The prose
now names all three, and `CryptoHandle.id`, `encrypt()` and `rotateKey()` stop
describing `sys_setting.value_enc` as the general destination of a handle.
The load-bearing correction is the AAD sentence, which claimed a binding over
this pair "Helps reject ciphertexts that were copied across namespaces". The
pair is one flat space shared by all three vocabularies, `sys_secret` declares
it non-unique by design, and nothing reserves a name in one vocabulary against
another — so the sentence is replaced by the guarantee that actually holds:
such a binding rejects a swap WITHIN one producer's vocabulary and does NOT
exclude a cross-vocabulary pair. The docblock records this as the contract's
present state and names the intended end state so the weak guard is not read
as the designed one.
The identical settings-only prose on `DatasourceSecretBinderDeps.namespace`
is corrected in the same change.
Documentation only: no behavior change, no schema shape change — `gen:schema`,
`gen:openapi` and `gen:docs` all regenerate byte-identically over this diff.
Recorded under the maintainer ruling of 2026-08-27 on #12599.
Co-authored-by: Claude <noreply@anthropic.com>
@os-sales
os-sales marked this pull request as draft August 28, 2026 02:25
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/service-datasource, @objectstack/spec, touching 4 documentable anchor(s).

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/data-modeling/external-datasources.mdx(via ICryptoProvider (symbol))
  • content/docs/data-modeling/validation-rules.mdx(via ICryptoProvider (symbol))
  • content/docs/protocol/kernel/config-resolution.mdx(via CryptoHandle (symbol), ICryptoProvider (symbol))

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

  • content/docs/releases/implementation-status.mdx(via ICryptoProvider (symbol))

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
  • 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.

Coarse fallback — 126 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 f907fbe9ed62c68d3de1a8a49d5ac3b9ba13abfcpackageMentionDocs.

Which tree this was computed on

This run read content/docs from dbc59088e7d910b68fd2d47bc272308fd54bba2f — the merge of head 9cb1c6eb03138c48e215945185ef91f9c6321599 into base f907fbe9ed62c68d3de1a8a49d5ac3b9ba13abfc, 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 dbc59088e7d910b68fd2d47bc272308fd54bba2f && git checkout dbc59088e7d910b68fd2d47bc272308fd54bba2f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f907fbe9ed62c68d3de1a8a49d5ac3b9ba13abfc 9cb1c6eb03138c48e215945185ef91f9c6321599 && git checkout -B drift-repro f907fbe9ed62c68d3de1a8a49d5ac3b9ba13abfc && git merge --no-ff 9cb1c6eb03138c48e215945185ef91f9c6321599
node scripts/docs-audit/affected-docs.mjs --json f907fbe9ed62c68d3de1a8a49d5ac3b9ba13abfc

⚠️ 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 f907fbe9ed62c68d3de1a8a49d5ac3b9ba13abfc → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Aug 28, 2026
@os-sales
os-sales marked this pull request as ready for review August 28, 2026 04:32
@os-sales
os-sales enabled auto-merge August 28, 2026 04:32
@os-sales
os-sales added this pull request to the merge queueAug 28, 2026
Merged via the queue into main with commit 776a098Aug 28, 2026
41 checks passed
@os-sales
os-sales deleted the claude/issue-12599-cryptocontext-doc-drift branch August 28, 2026 04:55
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CryptoContext.namespace / .key document themselves as settings-only, one layer below sys_secret's three producers

2 participants

@os-sales@claude