Skip to content

feat(verify): extract dogfood engine into public @objectstack/verify + CLI - #2041

Merged
os-zhuang merged 3 commits into
mainfrom
feat/verify-package
Jun 19, 2026
Merged

feat(verify): extract dogfood engine into public @objectstack/verify + CLI#2041
os-zhuang merged 3 commits into
mainfrom
feat/verify-package

Conversation

@os-zhuang

@os-zhuangos-zhuang commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Why

ObjectStack is a platform where third parties have an AI author arbitrary metadata. The real risk isn't "a platform change broke the CRM example" — it's "the AI used a valid primitive the examples don't exercise, and it silently breaks at runtime" (the #2018 timezone-bucketing class: green on build / 900+ unit tests / spec-liveness / CodeQL, only visible when the real engine + services + HTTP run together).

The internal @objectstack/dogfood package already contained an app-agnosticobjectstack verify engine in embryo (its derive/verify comments literally say "point it at any app … a third-party app like hotcrm"). This PR productizes that engine so third-party and template authors can run the same runtime proofs against their own apps.

What changed

New public library @objectstack/verify (packages/verify)

  • bootStack (was bootDogfoodStack), deriveCrudCases, runCrudVerification, runRlsProofs + report types — moved & generalized out of packages/dogfood/src.
  • tsup ESM+CJS+DTS, publishConfig.access: public, third-party-facing README.

New objectstack verify CLI command (packages/cli/src/commands/verify.ts)

  • oclif command reusing the existing loadConfig; flags --app/--rls/--multi-tenant/--json.
  • Exit-code contract (CI-usable): create-failed / read-failed / fidelity-gaps / rls-hole → exit 1; inconclusive verdicts (needs-fixture / skipped / member-visible) warn and exit 0.

@objectstack/dogfood kept, slimmed (single source of truth)

Release plumbing

  • @objectstack/verify added to the changeset fixed group (@objectstack/dogfood stays private/excluded); check-changeset-fixed.mjs passes (73 packages in sync). Changeset added for verify + cli.

Validated end-to-end on a real third-party app (hotcrm)

Ran the built CLI against ../hotcrm (a standalone marketplace CRM on published @objectstack@^9.9.1, with real sharing / territory / role-hierarchy rules — not in this repo):

  • Booted hotcrm's full 14-object stack through the real HTTP surface and verified data fidelity.
  • Demonstrated the exit-1 red path on a real appcrm_product.sku reads back uppercased (an intentional normalization hook), correctly flagged as a fidelity-gaps mismatch → exit 1.
  • fix(security)[P0]: enforce RLS on by-id writes — close member-edits-others'-records hole (#1985) #1994 authorization invariant holds on hotcrm: --rls --multi-tenant8 consistent / 0 holes (a fresh member can neither read 404 nor mutate 403 cross-org records) across its real sharing rules.

The exercise also surfaced two @objectstack/verifytool-quality issues (not hotcrm bugs), both addressed here:

  1. Fixed — the CLI ran fidelity + RLS proofs on the same in-process stack, so the RLS phase's admin-creates collided with the fidelity phase's rows on unique-constrained fields (a 409 that silently skipped those objects). The RLS phase now boots a separate pristine stack (hotcrm --rls --multi-tenant: 5-consistent/3-skipped → 8-consistent/0-skipped-by-409).
  2. Documented — fields normalized on write (uppercase/trim hooks, canonicalizing formulas) read back as fidelity-gaps even when working as designed; the report shows the wrote → read diff. A declared-transform allowlist is a planned enhancement.

Validated across the template corpus (9 apps)

Ran the CLI across all 9 apps in ../templates (the AI-authored starter corpus: expense, contracts, content, compliance, todo, project, procurement, hr, helpdesk), on an older @objectstack than this branch — a cross-version run:

Coverage caveat: the auto-derive skips objects whose required fields it can't synthesize (lookups / master-detail), so relational-heavy templates have ~half their objects skipped — "0 holes" is over the auto-exercised subset. Auto-synthesizing related records in topological order to reach those objects is a planned enhancement.

Verification

  • @objectstack/verify builds (ESM+CJS+DTS).
  • dogfood: 5 files / 57 tests green after the extraction and after rebasing onto the latest main (which carries spec/RLS schema changes) — zero behavior change.
  • objectstack verify against the framework examples: crm 4 verified / 2 skipped / exit 0, crm --rls0 holes, showcase exit 0; clean process exit (fixed a hang: the in-process stack leaves handles open after stop(), so the command forces this.exit()).
  • objectstack verify against hotcrm (real third-party): boots, verifies, proves exit-1 and the fix(security)[P0]: enforce RLS on by-id writes — close member-edits-others'-records hole (#1985) #1994 invariant (above).
  • canonical lint, check-changeset-fixed.mjs, and ci.yml YAML all green/valid.

Fix found along the way

The harness used a port-less loopback inject origin (http://localhost) which fails better-auth's default dev trusted-origins (http://localhost:*) → objectstack verify got a 403 on dev-admin sign-in in a bare node CLI (the dogfood tests passed only because turbo's strict-env run masked it). Switched to a ported loopback base so sign-in is deterministic across the node CLI and the test runner.

🤖 Generated with Claude Code

…+ CLI
Productize the internal dogfood regression engine as a published library and an
`objectstack verify` CLI so third-party and template authors can run the same
runtime proofs (auto-derived CRUD round-trip fidelity + the cross-owner RLS
invariant) against their own apps.
- new public @objectstack/verify: bootStack / deriveCrudCases /
runCrudVerification / runRlsProofs, moved+generalized from packages/dogfood/src
(tsup ESM+CJS+DTS, publishConfig public)
- new `objectstack verify` oclif command (--app/--rls/--multi-tenant/--json);
exits 1 on create-failed/read-failed/fidelity-gaps/rls-hole
- dogfood now consumes @objectstack/verify; drop 3 redundant auto-verify tests
(replaced by an `objectstack verify` CI step over the example apps); keep the
hand-written golden regressions (#2018 tz, #1994 RLS, #2004 field fidelity)
- fix: the harness used a port-less loopback inject origin (http://localhost)
that fails better-auth's default dev trusted-origins (http://localhost:*);
use a ported base so dev-admin sign-in passes in a bare node CLI and the test
runner alike
- add @objectstack/verify to the changeset `fixed` group; changeset for verify+cli
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercelBot commented Jun 18, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 19, 2026 12:12am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file tests tooling size/l labels Jun 18, 2026
@github-actions

github-actionsBot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cli, @objectstack/dogfood, @objectstack/verify.

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

  • content/docs/concepts/cloud-artifact-api.mdx(via packages/cli)
  • content/docs/concepts/implementation-status.mdx(via @objectstack/cli)
  • content/docs/concepts/packages.mdx(via @objectstack/cli)
  • content/docs/getting-started/cli.mdx(via @objectstack/cli)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/cli)
  • content/docs/guides/authentication.mdx(via @objectstack/cli)
  • content/docs/guides/client-sdk.mdx(via @objectstack/cli)
  • content/docs/guides/hook-bodies.mdx(via packages/cli)
  • content/docs/guides/packages.mdx(via @objectstack/cli)
  • content/docs/guides/project-scoping.mdx(via @objectstack/cli)
  • content/docs/guides/runtime-services/data-service.mdx(via packages/cli)
  • content/docs/guides/runtime-services/index.mdx(via packages/cli)
  • content/docs/guides/skills.mdx(via packages/cli)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/cli)
  • content/docs/protocol/objectos/realtime-protocol.mdx(via @objectstack/cli)

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.

…delity gaps
Surfaced by running `objectstack verify` against the real third-party hotcrm app:
- The CLI ran data-fidelity and RLS proofs against the SAME in-process stack, so
the RLS phase's admin-creates collided with rows the fidelity phase had already
written on unique-constrained fields (e.g. a unique `sku`/`account_number`) →
a 409 that silently skipped those objects' authorization check. Boot a separate
pristine stack for the RLS phase. hotcrm `--rls --multi-tenant` goes from
5-consistent/3-skipped(409) to 8-consistent/0-holes.
- Document the known limitation that fields normalized on write (uppercase/trim
hooks, canonicalizing formulas) read back as `fidelity-gaps` even when working
as designed (hotcrm's `sku`/`account_number` uppercase hooks).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ctstack/verify
ADR-0054 assigned the prove-it-runs mechanism to @objectstack/dogfood; this PR
extracted that engine into the published @objectstack/verify. Append an Update
addendum (and list it as a consumer) mapping the package to the ADR's phases —
dogfood stays the gate (hand-written golden proofs) and now runs on the verify
engine; Phase 1's field/RLS matrix is the published derive/verify/rls; Phase 3's
generative pass has deriveCrudCases as its seed — and stating the honest scope of
the auto-derived path (scalar round-trip + by-id RLS only) so it doesn't read as
subsuming the golden proofs. Decision unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@os-zhuang
os-zhuang merged commit fd2e1a2 into mainJun 19, 2026
16 of 17 checks passed
@os-zhuang
os-zhuang deleted the feat/verify-package branch June 19, 2026 00:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang