Skip to content

content(blog): what os verify proves in two stages on ObjectStack 17.7.0 (slot 2026-10-24) - #281

Open
objectstack-fleet[bot] wants to merge 1 commit into
mainfrom
claude/pm-dispatch-objectos-ju9td1-issue-271
Open

objectstack-fleet[bot] wants to merge 1 commit into
mainfrom
claude/pm-dispatch-objectos-ju9td1-issue-271

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #271

Slot: Sat 2026-10-24, on the shared calendar on #267. Merge on the slot day only.

Seat review. The seat read the post and checked the pipeline diagram at 1366 and the zh-Hans fold at 1440.

ACCEPT.

Slate 1 post, slot Sat 2026-10-24. Staged on lin/issue-271 from origin/main (3c5b6c6), one commit, 3e45b04. Not pushed by the dev; the seat pushes the branch and merges on the slot day.

Re-scope: what the card asked for does not exist on 17.7.0

The card's title promised "the Six Invariants It Only Proves on Request", its ownable concept was the three verdicts proven / inconclusive / excluded, and proof artifact #3 was a deliberately failing --delete-behaviors run. None of that is on the published @objectstack/cli 17.7.0, which npm create objectstack@latest installs (npm dist-tags: latest 17.7.0, next 18.0.0-next.2). Evidence, all from the published binary in a fresh scaffold:

$ npx os --version
@objectstack/cli/17.7.0 linux-x64 node-v22.22.2

$ npx os verify --help
USAGE
  $ os verify [-a VALUE] [--rls] [--multi-tenant] [--json]
FLAGS
  -a, --app=VALUE     Path to the app config (defaults to ./objectstack.config.{ts,js,mjs})
      --json          Emit the structured report as JSON
      --multi-tenant  Boot org-scoped (register the @objectstack/organizations plugin) so tenant-isolation RLS policies apply (…)
      --rls           Also run the cross-owner RLS invariant (a fresh member must not write what it cannot read)

$ npx os verify --delete-behaviors --json; echo $?
objectstack: INVOCATION ERROR — Nonexistent flag: --delete-behaviors. The command never ran: nothing was started and nothing is listening. Invoked as: objectstack verify --delete-behaviors --json
2
$ npx os verify --reference-shapes; echo $?
objectstack: INVOCATION ERROR — Nonexistent flag: --reference-shapes. (…)
2

Source-side: tag @objectstack/cli@17.7.0 packages/cli/src/commands/verify.ts:95-108 declares exactly app, rls, multi-tenant, json. The five other probes (--reference-shapes, --delete-behaviors, --unique-scopes, --parent-write-reach, --dashboard-windows) sit in packages/cli/CHANGELOG.md at origin/main inside the ## 18.0.0-next.0 section (entries at :937, :970, :1002, :1040, :1065; section bounds :871 and :2330). The word "inconclusive" appears 0 times in the 17.7.0 content/docs/deployment/cli.mdx and 3 times at origin/main. Seat decision: option A, re-scope to what 17.7.0 ships, keep the slot, no mention of unreleased material.

What this PR adds

New post content/blog/what-os-verify-proves-in-two-stages/ in en, zh-Hans, zh-Hant (generated by pnpm gen:zh-hant), ja, ko, de, es and fr; date: 2026-10-24, no updated, topic: app-building, audience: developer. Title: How Do You Test an AI-Written App Without Writing Tests? What os verify Proves in Two Stages on ObjectStack 17.7.0 (query-shaped, one number: two stages; the version named in the title, the lede and the footer).

  • Ownable concept (as ruled): the two-stage done-bar — the author-time rules first, the runtime second, and the second stage never starts if the first refuses. The hook is the 17.7.0 changelog's own before/after: a stack with a lookup to a missing object used to boot and print ✓ verify passed at exit 0 while validate/build/lint refused it — named in the post as a false green. Second beat, not the title: the --rls coverage rule, reported, never dropped (positionCoverage.notRun is a term of hardFailures; member-visible probes stay in the report as unproven).
  • Proofs (rule 5), all real runs on 17.7.0 (transcripts under scratchpad/issue-271/proof-a|b|c/):
    • (a) npm create objectstack@latest verify-demo (full command, skills installed; Create ObjectStack v17.7.0), then npx os verify --json > report.json → exit 0, crud.summary objects 1 / verified 1 / checked: 2, hardFailures: 0; 317 stderr lines, stdout exactly one JSON document (JSON.parse read it whole). Text face: Running author-time rules (49)… ✓ Author-time rules passed (49 rules).
    • (b) examples/app-crm at tag @objectstack/cli@17.7.0, run standalone against the published 17.7.0 packages (workspace:* pinned to 17.7.0), npx os verify --rls --json → exit 0, hardFailures: 0; crud: 4 verified, 1 needs-fixture (crm_opportunity, the app's own validation rules refused the derived record: "Discount cannot exceed 40% …; Close Date must be today or a future date"), 1 skipped (crm_opportunity_line_item, required relation); rls: base probe 6 rls-consistent (GET 404 / PATCH 404, row unchanged), positionCoverage declared = ran = [sales_rep, sales_manager, finance_approver], notRun: [], totals objects 24 / proven 6 / unproven 18 / memberVisible 18 / holes 0; text face says per position "this persona proved NOTHING — every object was member-visible".
    • (c) a stage-one refusal: a Field.lookup('verify_demo_project', …) added to the scaffold's one object → npx os verify exit 1, ✗ Author-time rules failed (1 issue) — the runtime stage did not run, rule object-reference-unknown; --json → exit 1, {"error": …, "errors": [{"severity": "error", "rule": "object-reference-unknown", "where": …, "path": "objects[0].fields.project.reference", "message": …, "hint": …}]}; 0 stderr lines (nothing booted); os validate prints the same finding. Field restored byte-identical afterwards.
  • Honesty (rule 7): a six-item "What a green os verify does not say" section — nothing about correctness (write tests for business logic), not all of os validate (the reference's own list), needs-fixture/skipped are not failures, --rls proves one invariant where a scenario exists (18 of 24 probes proved nothing on the CRM, and the run is green), opt-in and single-tenant by default, not the human verify of the getting-started loop.
  • ObjectOS appears once, as T4_STANDALONE verbatim from src/lib/positioning.ts, per locale. No pricing, signup URL or edition naming. No token figures. No competitor claims. CTA: point your agent at ObjectStack and let it run the done-bar; the README's own os verify line.
  • Internal links as the card lists: how-to-point-your-agent-at-objectstack, how-to-review-ai-generated-app-changes (twice: the declared → enforceable → correct ladder, and pass 2), how-to-build-a-crm-with-an-ai-agent, glossary declared-vs-enforced (/zh-Hans/glossary/… in zh-Hans, rewritten to /zh-Hant/ by the generator; /en/… elsewhere).
  • Assets: cover-en.svg / cover.svg (1200×675), two-stages-en.svg / two-stages.svg (1200×700). The diagram adds what the cover lacks: the per-object and per-probe status lists, which statuses count and which are only reported, and the six-term hardFailures sum. ja/ko/de/es/fr use the English set, zh-Hans/zh-Hant the Chinese pair. Explicit light backgrounds and text fills, so the images read the same in dark mode.

Updated post content/blog/how-to-review-ai-generated-app-changes/index.mdx (en only; it has no other locale): one back-link paragraph after its "What this review still cannot catch" list, pointing the runtime half at the new post; updated: 2026-10-15T10:00:00+08:00 → 2026-10-24T10:00:00+08:00 (the slot date, as the card rules). date untouched.

Claims and their sources

Claim in the post Source
"The done-bar: os verify green means the author-time rules pass and the app behaves at runtime. It runs two stages, in order, and the second starts only when the first passes." objectstack tag @objectstack/cli@17.7.0, content/docs/deployment/cli.mdx:1876-1878
Stage one is the registry os validate runs, over the stack prepared the way os validate prepares it; advisories never fail it; "the defineStack provenance refusal …, the package-docs lint, the capability-provider check, the picklist-reference and view-container-name checks and --strict stay os validate's, so run it too" cli.mdx:1886-1898 at the tag
Stage two: "for each object, a record derived from its fields is created, read back and compared"; "With --rls, a second fresh boot proves the cross-owner invariant — a member must not write what it cannot read — for a probe persona and for one persona per declared position"; --multi-tenant boots org-scoped cli.mdx:1899-1905 at the tag
Exit 0 / exit 1 meanings cli.mdx:1916-1917 at the tag
--json: stdout carries exactly one JSON document; log lines go to stderr; the report carries app, config, multiTenant, crud, rls (with --rls) and hardFailures; refused → { error, errors[] } cli.mdx:1919-1934 at the tag
The six-term hardFailures sum (quoted as code) packages/cli/src/commands/verify.ts:279-285 at the tag; emitted at :291
One persona per declared position; notRun counts verify.ts:251-262 at the tag (declaredPositionNames(config), positionFailures); packages/verify/src/rls.ts:212-223 ("REPORTED, never dropped")
The five RlsStatus values and their proven / not-proven reading packages/verify/src/rls.ts:147-157 at the tag
"A stack carrying a lookup to an object that does not exist … printed ✓ verify passed at exit 0, while os validate, os build and os lint all refused it. The documented done-bar … was green on a stack the build refuses to ship." (blockquote) and the two-stage fix f397608 / #21323 packages/cli/CHANGELOG.md at the tag, :29 and :37
318 log lines on stdout on a two-object stack; "used to exit 0 and leave a file no JSON parser accepts" (5155093 / #21324) packages/cli/CHANGELOG.md at the tag, :250-254
os verify # Boot the app in-process and verify it over real HTTP README.md:261 at the tag (the card cites :302 at origin/main)
The scaffold ships no verify script, hence npx os verify packages/create-objectstack/src/templates/blank/package.json:10-17 at the tag
"4 · You verify in the Console UI" is the human verify content/docs/getting-started/build-with-claude-code.mdx:30 at the tag
The three declared positions; crm_sales_user grants read on every CRM object; bound to the three positions examples/app-crm/src/security/sales-positions.ts:10-37, 45-66 and bind-position-sets.ts:9, 27 at the tag; objectstack.config.ts:100
Five of six objects declare sharingModel: 'public_read_write', the line item controlled_by_parent examples/app-crm/src/objects/{account,activity,contact,lead,opportunity}.object.ts and opportunity-line-item.object.ts:21 at the tag
T4 standalone src/lib/positioning.ts (T4_STANDALONE, and each locale's t4)
49 rules, 317 / 0 stderr lines, checked: 2, every number in the crud and rls blocks, the needs-fixture refusal text, the "proved NOTHING" lines the runs' own output: scratchpad/issue-271/proof-a/{verify-text.out,report.json,report.stderr}, proof-b/{report-rls.json,report-rls.stderr,verify-rls-text.out}, proof-c/{verify-text.out,report.json,report.stderr,validate.out,note.object.ts.orig,note.object.ts.mutated}, scaffold-full.log, version.txt, help.txt, delete-behaviors.stderr, reference-shapes.out

The runs, in order

  1. npm create objectstack@latest verify-demo (full, with the skills bundle; an earlier scaffold made with --skip-skills was kept as a second copy for the failing run — same packages, 17.7.0). npx os verify and npx os verify --json > report.json: exit 0 both.
  2. git archive of examples/app-crm at the tag into a standalone directory; workspace:* → 17.7.0 (and typescript ^6.0.3 → ^5.9.3, unused by os verify); pnpm install (build scripts ignored by pnpm 10's default; the run boots on sqlite-wasm); npx os verify --rls --json and the text face: exit 0 both, 799 stderr lines.
  3. On the second scaffold: Field.lookup('verify_demo_project', …) added (anchor hit, lookup count 0 → 1, diff saved); npx os verify exit 1, --json exit 1 with 0 stderr lines; npx os validate exit 1 with the same finding; file restored and cmp byte-identical.

Gates, on the tree committed as 3e45b04 (check and build through scripts/pm/os-verify-lock.sh, slot www-271)

Gate Exit Verdict line
pnpm content:lint 0 ✓ content lint passed (355 files, 46 glossary terms checked)
pnpm content:lint --published 0 same line
pnpm svg:lint 0 svg-text-fit: OK — … (122 SVGs, 2643 text boxes, 183 filtered elements, tolerance 2px, 1 allowlisted)
pnpm check 0 Result (160 files): 0 errors, 0 warnings, 0 hints
pnpm build 0 ✓ zh-Hant: generated 48, kept 0 hand-maintained, 8 with body links pointed at /zh-Hant/ · svg-text-fit: OK · [build] 920 page(s) built in 59.01s · ✓ content lint --dist passed (494 built blog pages checked) · CJK line breaks (920 pages, 348 zh/ja, 0 breaks), quotation marks (12856 curly marks, 0 wrong) and links (99458 internal links) passed · tree clean afterwards
pnpm seo:smoke 0 SEO smoke test passed (910 HTML pages checked; 594 sitemap URLs against 316 noindexed pages; 5679 canonical/hreflang annotations; 17411 prose blocks language-checked; 99448 internal links redirect-checked)

Lock: VERDICT command-exit 0 · held the lock 94s · waited 42s (final run). One earlier build was red and fixed: the ko page rendered 4 literal ** because two bold spans wrapping inline code sat against a Hangul particle; a space-separated noun was put after each.

Advisories, verbatim and expected: Date is in the future: Sat Oct 24 2026 ×8; Updated is in the future: 2026-10-24 on the back-linked post; title widths (en 114 chars; zh-Hans 58 chars / 82 columns; ja 69 / 104; ko 74 / 105; de 129; es 119; fr 123) against the 60-column snippet note; descriptions all ≤ 230 chars (en 229, zh-Hans 113, ja 136, ko 168, de 227, es 229, fr 229).

Browser check (final build served by astro preview on 127.0.0.1:49141, Playwright Chromium at /opt/pw-browsers/chromium)

scratchpad/issue-271/shots.mjs → scratchpad/www/shots-271/ (101 files, results.json): 219 of 219 assertions pass. The article in en and zh-Hans at 1366×625, 1440×750, 1512×830, 1920×945, 390×844 and 360×800, light and dark (prefers-color-scheme), lazy images scrolled into view first: HTTP 200, scrollWidth equal to the viewport, no element past the viewport outside a scroll container, cover renders, every body image loads, no repeated image. The back-linked post in en at 1440 and 390, light and dark, carries the new link and renders "Updated Oct 24, 2026". The en and zh-Hans blog lists at 1440 and 390 link the new post (it is the first card under Latest). Element crops of the two tables, both images and four code blocks at 360 and 1366 in en and zh-Hans. The four served SVGs opened at native size in light and dark: lowest text contrast 5.06:1 on the covers ("THE COUNT THE EXIT CODE READS" / "退出码读的那个计数") and 4.73:1 on the diagrams (the amber needs-fixture label on the pale status box); 0 text nodes on a dark fill.

Looked at: the folds in en at 1366 light, 390 dark and 1920 dark; zh-Hans at 1440 light and 360 dark; the zh-Hans full page at 1366 dark; the phone table (horizontal scroll container, as the site gives every post) and the diagram at phone width; a code block at 1366; both covers and both diagrams at native size; the blog list; the updated post's header line.

Two visual defects the check found, both fixed before the commit: the grey small text (#657872) read 4.24:1 inside the pink "refused" box and 4.29:1 on the green count bar, and by arithmetic 4.42:1 on the pale status boxes — .small and .foot are now #55685f in all four SVGs; and the two advisory lines at the bottom of the diagram's stage-1 box sat on its border and were lifted 8 px.

Deviations and notes

Acceptance notes (observations, not filed)


Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr

New post, slot Sat 2026-10-24, in en, zh-Hans, zh-Hant (generated), ja, ko,
de, es and fr, with a cover and a stage diagram in the English and Chinese
sets. Re-scoped to the published @objectstack/cli 17.7.0: two stages, one
count, the --rls coverage rule; every transcript is a real run.

Back-link from how-to-review-ai-generated-app-changes (en), its `updated`
set to the slot date.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post (slot Sat 2026-10-24): How Do You Test an AI-Written App Without Writing Tests? What os verify Proves in Two Stages on 17.7.0

2 participants