Skip to content

feat(objectql): the silent skips stop being silent — registration-time completeness diagnostics (ADR-0078 Phase 4) - #4599

Merged
os-zhuang merged 1 commit into
mainfrom
claude/adr-0078-phase4-runtime-warns
Aug 2, 2026
Merged

feat(objectql): the silent skips stop being silent — registration-time completeness diagnostics (ADR-0078 Phase 4)#4599
os-zhuang merged 1 commit into
mainfrom
claude/adr-0078-phase4-runtime-warns

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Phase 4 of #4544 — decided rather than deferred. The phase had two halves; they got opposite verdicts, both decided on evidence already in hand rather than parked for evidence that will never arrive.

Rejected — the generative rule sweep (not deferred: rejected)

A generator can enumerate candidates ("which optional keys might be load-bearing?") but cannot verify runtime skip sites, and a rule without its skip-site citation is a false prescription. This campaign shipped four of those; every one was caught by the verification pass a generator would structurally skip. No amount of waiting fixes that — the route is wrong, not early. Recorded in the changeset so nobody re-proposes it as "finally have enough data".

Built — registration-time diagnostics at the choke point every door shares

The author-time gate (validate-functional-completeness, Phase 1) only protects metadata that passes through os build / validate / lint. Two shipped instances prove the other doors are real, not hypothetical:

SchemaRegistry.registerObject is where every door converges — declared stacks, plugin objects, extend contributions, saveMetaItem, raw registerObject calls. It now runs the same shared predicate (checkFieldCompleteness from @objectstack/spec/kernel) and emits one aggregated warning per incomplete object, carrying the same rule ids the lint reports — a boot log greps straight into the same docs and suppression story.

WARN, never throw — deliberately. ADR-0078 §1 maps error severity to "the instance is dead", not "the system is dead". An inert field must not kill a boot that thousands of healthy objects share. Errors block at author time; the registry's job is that the silence never survives to runtime unobserved.

Shape follows warnStrippedLegacyApiMethods (#3543) exactly: module-level once-per-object dedup, injectable warn, pure observation, hot path untouched (one line per object, all findings aggregated).

The webhook skip now names itself

auto-enqueuer.ts's if (triggers.size === 0) return null sat under a comment blessing the empty case as "a manual-only webhook" — a mode #3196 removed (no manual fire path exists; the Phase 3 finding). The skip now warns with the author-time rule id (webhook/without-triggers) and the comment tells the truth.

Verified, not assumed: only active rows reach parseRow (where: { active: true }), so a deliberately disabled webhook stays warning-free — zero false positives on the repo's one real webhook (shipped inactive, full trigger list).

Scope honesty

Field rules + the webhook rule get the runtime twin. view/layout-without-binding stays author-time-only: views don't register through this choke point, and the renderer half of the evidence lives in objectui.

Verification

This closes the ADR-0078 loop end to end: author-time error, runtime warning, one shared predicate deciding both.


Generated by Claude Code

…e completeness diagnostics (ADR-0078 Phase 4)

Phase 4 had two halves; they got opposite verdicts, decided on evidence already
in hand rather than deferred for evidence that will never arrive.

## Rejected — the generative rule sweep (not deferred: rejected)

A generator can enumerate candidates ("which optional keys might be
load-bearing?") but cannot verify runtime skip sites, and a rule without its
skip-site citation is a false prescription. This campaign shipped four of those;
every one was caught by the verification pass a generator would structurally
skip. No amount of waiting fixes that — the route is wrong, not early.

## Built — registration-time diagnostics at the choke point every door shares

The author-time gate (validate-functional-completeness) only protects metadata
that passes through `os build` / `validate` / `lint`. Two shipped instances
prove the other doors are real: #3896 (Setup authoring inserted
`sys_sharing_rule` rows directly, bypassing the schema that "required"
`criteria`) and cloud's `rowColor.mapping` (an `as never` cast bypassed tsc,
then the strip-era parse dropped the key).

`SchemaRegistry.registerObject` is where EVERY door converges — declared
stacks, plugin objects, `extend` contributions, `saveMetaItem`, raw
registerObject calls. It now runs the SAME shared predicate
(`checkFieldCompleteness` from `@objectstack/spec/kernel`) and emits one
aggregated warning per incomplete object, carrying the SAME rule ids the lint
reports — a boot log greps straight into the same docs and suppression story.

WARN, never throw — deliberately: ADR-0078 §1 maps error severity to "the
INSTANCE is dead", not "the system is dead". An inert field must not kill a
boot that thousands of healthy objects share. Errors block at author time; the
registry's job is that the silence never survives to runtime unobserved.

Shape follows `warnStrippedLegacyApiMethods` (#3543) exactly: module-level
once-per-object dedup, injectable `warn`, pure observation, hot path untouched.

## The webhook skip now names itself

`auto-enqueuer.ts`'s `if (triggers.size === 0) return null` sat under a comment
blessing the empty case as "a manual-only webhook" — a mode #3196 removed (no
manual fire path exists). The skip now warns with the author-time rule id
(`webhook/without-triggers`) and the comment tells the truth. Verified, not
assumed: only ACTIVE rows reach parseRow (`where: { active: true }`), so a
deliberately disabled webhook stays warning-free — zero false positives on the
repo's one real webhook (shipped inactive, full trigger list).

## Scope honesty

Field rules + the webhook rule get the runtime twin. `view/layout-without-
binding` stays author-time-only: views do not register through this choke point
and the renderer half of the evidence lives in objectui.

## Verification

- registry 85/85 (6 new, incl. an integration test through a raw
  registerObject call — the #3896 class of door)
- auto-enqueuer 15/15 (1 new)
- Full suite 132/132. The dogfood boots double as the authoritative sweep:
  every shipped stack (platform objects, showcase, CRM, Todo) registers with
  ZERO functionally-incomplete warnings — no false positives, and no inert
  fields hiding behind doors the author-time gate could not see.

Closes the ADR-0078 loop end to end: author-time error, runtime warning, one
shared predicate deciding both. Tracked in #4544.

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

vercel Bot commented Aug 2, 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 2, 2026 9:38am

Request Review

@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 09:38
@os-zhuang
os-zhuang enabled auto-merge August 2, 2026 09:38
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/objectql, @objectstack/plugin-webhooks.

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

  • content/docs/automation/webhooks.mdx (via packages/plugins/plugin-webhooks)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql, @objectstack/plugin-webhooks)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/query-syntax.mdx (via packages/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql, @objectstack/plugin-webhooks)

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.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Aug 2, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 257d97a Aug 2, 2026
21 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0078-phase4-runtime-warns branch August 2, 2026 09:56
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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants