Skip to content

feat(spec): sink the #7865 injected-column provenance derivation into @objectstack/spec/data and warn at lint time - #8342

Merged
hotlong merged 6 commits into
mainfrom
claude/issue-8116-provenance-predicate-to-spec
Aug 13, 2026
Merged

hotlong merged 6 commits into
mainfrom
claude/issue-8116-provenance-predicate-to-spec

Conversation

@hotlong

@hotlong hotlong commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #8116

What this does

Implements the 2026-08-12 maintainer ruling on #8116 (option 1, verbatim 「接受你的全部建议。」): sink the #7865 injected-column provenance derivation into @objectstack/spec, keep @objectstack/metadata-core re-exporting it so nothing downstream breaks, and let @objectstack/lint consume the spec export to deliver the author-time warning the card exists for.

1. The move (packages/spec/src/data/injected-system-column-provenance.ts)

Moved from @objectstack/metadata-core, beside the WHICH-half derivation (resolveInjectedSystemColumns, #5378):

Scope fence respected: the served-document injection/strip pair (#6562) and every other derivation stay in @objectstack/metadata-core; no unrelated derivation migrated.

2. The shim (packages/metadata-core/src/injected-system-columns.ts)

Re-exports every previously-public moved name from @objectstack/spec/data — metadata-core's public surface is unchanged. Proof: the #7865 producer test (packages/metadata-core/test/injected-column-provenance.test.ts, the 20-assertion matrix) is byte-unchanged and passes against the re-export. All downstream importers (objectql, metadata-protocol, plugin-security, plugin-sharing, qa/dogfood) import via metadata-core and need no change.

3. The warning (packages/lint)

  • system-fields.ts: unprovisionedInjectedColumnsFor(objectDef) — the marker in per-object set shape, delegating to the spec export (never a hand-copied predicate).
  • validate-expressions.ts: every object-bound expression surface (flow/edge conditions, validation rules, field requiredWhen / readonlyWhen / visibleWhen, per-option visibleWhen, action visible / disabled, sharing-rule conditions, hook conditions, field formulas) warns when it reads record.ANCHOR / previous.ANCHOR and the anchor is an injected system column on an ADR-0015 external object — registered and addressable, but backed by no storage, so the predicate silently degrades at query time (on SQLite: constant-false, HTTP 200, zero rows, no error). AST-based member reads only (has() covered); bare identifiers are never judged, so flow variables cannot false-positive.
  • validate-semantic-roles.ts: stageField / highlightFields pointers at an unprovisioned anchor get the new advisory rule semantic-role-field-unprovisioned (barrel-exported per the FLOW_TRIGGER_UNKNOWN_EVENT 规则 id 常量没从 @objectstack/lint 导出 —— 消费者拿不到,只能对字面量 #5648 contract).

Severity: warning, not error (dispatch assumption 2 confirmed): the #7219 family's criterion — an error needs a closed oracle, and lint cannot see the remote deployment's schema; the degradation is non-fatal; the security-critical members of the class are fenced at runtime (#7833 / #7859 / #7858). The 'author' fail direction is preserved end to end: an author-declared column of the same name is the author's real remote column and is never warned (#7859's tenant-wall direction, pinned in tests on both surfaces).

File-surface note (declared surface + 2 files) and the view-filter residual

The dispatch's lint surface named system-fields.ts / validate-expressions.ts; delivering the ruling's highlight half required validate-semantic-roles.ts (the one rule that resolves stageField / highlightFields per object) plus its barrel line in index.ts (a #5648-enforced consequence of the new rule id). No in-flight claim touches either file. View filters are not covered here: the filter-position field checks resolve against the object-independent blanket SYSTEM_FIELDS, so there is no per-object resolution site to attach the marker to without converting those rules first — #5378-shaped work beyond this card's "provenance predicate only" fence. Out of scope: #8340 remains open and tracks it.

Mechanism assumptions (dispatch), verified

  1. Spec-representable, no runtime inputs — confirmed: every input is a document-declared key (external, fields, the plan inputs); the moved module imports only spec siblings.
  2. Warning severity — chosen and justified above.
  3. Producer test passes against the re-export unchanged — confirmed, file untouched, 162/162 metadata-core tests green.

Verification (all local, real readings)

Changeset: minor for @objectstack/spec + @objectstack/lint, patch for @objectstack/metadata-core. Not breaking — no ADR-0087 disposition required.


Generated by Claude Code

claude added 3 commits August 13, 2026 05:02
… @objectstack/spec/data and warn at lint time (#8116)

Move the injected-system-column definition tables (AUDIT_FIELD_DEFS and
siblings), injectedSystemColumnDefs, and the #7865 provenance trio
(platformProvisionsStorage / resolveInjectedColumnProvenance /
unprovisionedInjectedColumns) into packages/spec/src/data, per the
2026-08-12 maintainer ruling on #8116 (option 1 — the WHAT-half move
#3786 anticipated, scoped to the provenance predicate).
@objectstack/metadata-core re-exports every previously-public name, so
its surface and every downstream import are unchanged; the served-
document injection/strip pair (#6562) stays there, now consuming the
spec tables plus the newly exported isInjectedColumnDefinition.

@objectstack/lint (spec-only by contract) consumes the export:
validate-expressions warns on record.<anchor> / previous.<anchor> reads,
and validate-semantic-roles warns on stageField / highlightFields
pointers, when the anchor is an injected system column on an ADR-0015
external object — registered, addressable, and backed by no storage.
Warning severity per the #7219 criterion (no closed oracle over the
remote schema); an author-declared column of the same name is 'author'
provenance and never warned (#7859's security direction).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
…mpleteness guard

The new unprovisioned-anchor pass introduces five locals whose member
reads are Map/Set/AST plumbing, never metadata keys; the meta-guard's
completeness check requires them excused by name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
…ta exports (10 added, 0 removed)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
@vercel

vercel Bot commented Aug 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 13, 2026 9:32am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/lint, @objectstack/metadata-core, @objectstack/spec.

106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/lint, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-core, packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via packages/lint, @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/permissions/system-context.mdx (via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/metadata-core, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

⛔ 7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/metadata-core, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/lint, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

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.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

claude added 3 commits August 13, 2026 08:59
…tsc errors the TEST_DEBT ratchet caught (#8116)

The #8116 test block's helper took Array<{ severity?: string }>, so every
.message/.where read off its result was TS2339 under the lifted-exclusion
measurement (recorded 20 -> measured 29). Typed over the module's own
ExprIssue, the lifted-exclusion count is back to exactly the recorded 20;
the ledger entry is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
…tree (#8116 x #8341/#8335)

Discharges the os-regen deferral from the preceding merge commit: the
data.json shards regenerate with both sides present — this PR's 10 new
provenance exports and main's landed entries (zodIssuesToFields intact
in the api.json shards).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
@hotlong
hotlong marked this pull request as ready for review August 13, 2026 09:52
@hotlong
hotlong added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 2d8dba3 Aug 13, 2026
27 checks passed
@hotlong
hotlong deleted the claude/issue-8116-provenance-predicate-to-spec branch August 13, 2026 10:22
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…t serve, and refuse them at authoring time (objectstack-ai#7912) (objectstack-ai#8426)

* fix(rest,lint,spec): prune nav entries whose destination object cannot serve, and refuse them at authoring time (objectstack-ai#7912)

A `type: 'object'` nav entry pointing at an object that cannot answer a list
was served in the `/meta` payload anyway. Two independent conditions make a
destination unservable — `enable.apiEnabled: false` (404) and an
`enable.apiMethods` whitelist without `list` (405) — and both are pure
functions of the object's own `enable` block, so the destination is dead for
every persona. That is why no `requiredPermissions` gate on the entry could
ever prune it.

Per the maintainer ruling of 2026-08-12 (option (c)): derive the fact, mint no
new key.

- `filterAppForUser` consults the destination's `enable` for every
  `type: 'object'` entry, on both `/meta` app routes and inside `children` and
  `areas[]`. Fail-open on unknown objects and unreadable metadata, so
  `requiresObject`'s client-only pin and objectstack-ai#3770 both stand.
- The mandatory companion: `os validate` / `os build` / `os lint` now fail with
  `nav-object-unservable`, naming the entry, the object, the offending `enable`
  key path and which condition fired. The serving side logs the same facts.
- The two-step gate order is declared once as `apiExposureDenialReason` /
  `canServeApiOperation` in `@objectstack/spec/data`. The REST data gate, the
  nav prune and objectstack-ai#7909's invariant test all read that one export instead of
  re-spelling it — the third spelling is what this extraction removes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7vaLs7bhBPi9m3JyzkhDj

* chore(spec): regenerate api-surface / export-origins after merging origin/main (objectstack-ai#7912)

Both artifacts were merged without a text merge: this branch and objectstack-ai#8342 each
added exports to `@objectstack/spec/data`, so neither side's baseline covered
the union. Regenerated from the merged tree, after rebuilding dist — the gate
reads the BUILT dist, and on a stale one it reports phantom removals that the
generator would then write.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7vaLs7bhBPi9m3JyzkhDj

* fix(rest): give the objectstack-ai#7912 nav-servability test's import an explicit .js extension (objectstack-ai#7912)

`check:type-check-debt` went red: @objectstack/rest's TEST_DEBT records 155 raw
tsc errors and the re-measure reported 156 (+1).

Attributed, not assumed. The package-level `typecheck` is genuinely clean —
`packages/rest` is one of the 20 packages whose tsconfig hides its own tests from
tsc, so nothing local can see the test layer. Replaying the ledger's own program
(the package tsconfig with the test globs dropped from `exclude`) gives 156, of
which exactly ONE is in the new file and exactly 155 are not — matching the
recorded number, so nothing pre-existing on main drifted:

  meta-app-nav-servability-gate.test.ts(22,28): error TS2835: Relative import
  paths need explicit file extensions in ECMAScript imports when
  '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './rest-server.js'?

The package resolves NodeNext, so the extensionless spelling the older test
files use is a TS2835 — 67 of them are frozen in the ledger. The fix is the
extension, so a new file does not add the 68th.

⛔ The TEST_DEBT entry was NOT raised, and `scripts/check-type-check-coverage.mjs`
was not touched. The ledger is a ratchet: `--re-measure` now reports "none above
its recorded number / surplus: none — every entry sits exactly at its
measurement".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P7vaLs7bhBPi9m3JyzkhDj

---------

Co-authored-by: Claude <noreply@anthropic.com>
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/xl tests tooling

Projects

None yet

2 participants