feat(cli): liveness author-warning lint — close the spec-liveness loop#1966
Merged
Conversation
The liveness ledgers classify every authorable property live/experimental/ dead with evidence, and the CI gate enforces classification completeness — but that knowledge never reached the author (very often an AI) writing the metadata. This feeds it back at build time. New `compile` lint (lint-liveness-properties.ts) reads the ledgers and warns when an authored object/field sets a misleading property — e.g. `object.enable.feeds` (no feed runtime), `object.versioning` (no engine), `field.columnName` (driver ignores it), `field.maxRating`/`vectorConfig` (renderer reads a different key) — with a corrective hint. Advisory only; never fails the build, like the existing flow anti-pattern lint. Signal-over-noise by design: opt-in per ledger entry via a new `authorWarn`/`authorHint` annotation (experimental entries warn by default). Booleans warn only when truthy and only `default(false)` flags are marked, so schema defaults (enable.trash/searchable) never trip it. Coverage grows by annotating more entries, not by touching lint code. - spec: ledger entries gain optional authorWarn/authorHint; `liveness/` now shipped in package `files` so the CLI can read it. Seeded the misleading object capability flags + aspirational blocks and dead field props. - README documents the authorWarn convention + the default-false caveat. Verified end-to-end via a real `objectstack compile` (warnings fired for enable.feeds/versioning/columnName; the lint also caught two genuine pre-existing dead-prop usages in app-showcase). CLI 451 + 9 new lint tests green; liveness gate green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 92 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
17 tasks
os-zhuang
pushed a commit
that referenced
this pull request
Jul 18, 2026
…uthor-lint) The author-side liveness lint (lintLivenessProperties, #1966) auto-warns on every `experimental` prop. enable.trash / enable.mru default to `true`, and the lint cannot distinguish an authored `true` from the schema default — so tagging them experimental warned on the default value of every object, tripping the "does NOT warn on a default-on flag left alone (enable.trash)" contract test in Test Core. Revert those two to `dead` (their audit classification) with a ledger note explaining why; drop the [EXPERIMENTAL] marker from their spec .describe(). Their #1893 disposition (prune-or-build) stays tracked in the sub-issue. All other #1893 experimental markers are on ungoverned types the lint never loads, so they are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ
os-zhuang
pushed a commit
that referenced
this pull request
Jul 18, 2026
…uthor-lint) The author-side liveness lint (lintLivenessProperties, #1966) auto-warns on every `experimental` prop. enable.trash / enable.mru default to `true`, and the lint cannot distinguish an authored `true` from the schema default — so tagging them experimental warned on the default value of every object, tripping the "does NOT warn on a default-on flag left alone (enable.trash)" contract test in Test Core. Revert those two to `dead` (their audit classification) with a ledger note explaining why; drop the [EXPERIMENTAL] marker from their spec .describe(). Their #1893 disposition (prune-or-build) stays tracked in the sub-issue. All other #1893 experimental markers are on ungoverned types the lint never loads, so they are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ
os-zhuang
added a commit
that referenced
this pull request
Jul 18, 2026
…props experimental + declare renderer-read props (#1878) (#3223) * chore(spec): mark aspirational props experimental + declare renderer-read props (#1878) Metadata-liveness audit follow-through (umbrella #1878). Resolves the unambiguous framework-spec portions of the open P2 sub-issues. #1893 (aspirational config — prune or mark experimental): add [EXPERIMENTAL — not enforced] markers to properties that parse but have no runtime consumer, so authors are not misled (ADR-0049): - object enable.trash / enable.mru (ledger dead -> experimental) - job retryPolicy / timeout - theme spacing / breakpoints / rtl / density / touchTarget - translation messageFormat:'icu' / cache - webhook authentication (non-HMAC bearer/basic/api-key) - PortalSchema (entire — not registered, no route/renderer) #1891 / #1894 (naming drift + inverse drift — app cluster): declare the props the objectui renderers already read so a strict Schema.parse() holds: - app branding accentColor (ConsoleLayout) - nav item badgeVariant (NavigationRenderer) - nav item `separator` type (AppContent nav divider) - agent knowledge.sources as the canonical key, topics kept as deprecated alias Regenerated reference docs (content/docs/references) to match. All spec gates green: check:liveness, check:docs, check:spec-changes; full spec suite 6763 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ * fix(spec): keep object enable.trash/mru dead, not experimental (CI: author-lint) The author-side liveness lint (lintLivenessProperties, #1966) auto-warns on every `experimental` prop. enable.trash / enable.mru default to `true`, and the lint cannot distinguish an authored `true` from the schema default — so tagging them experimental warned on the default value of every object, tripping the "does NOT warn on a default-on flag left alone (enable.trash)" contract test in Test Core. Revert those two to `dead` (their audit classification) with a ledger note explaining why; drop the [EXPERIMENTAL] marker from their spec .describe(). Their #1893 disposition (prune-or-build) stays tracked in the sub-issue. All other #1893 experimental markers are on ungoverned types the lint never loads, so they are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ * docs(spec): mark ToolSchema as a read-only projection, not an execution entry point (#1892) #1892 tool disposition (ADR-0049 line): the ledger already documents that tool metadata is a one-way, write-only projection (no executor loads a metadata-authored tool; the runtime uses a separate AIToolDefinition in cloud service-ai). Surface that on the SPEC itself so an author/AI reading the Zod schema — not just the ledger — knows a hand-authored tool will not run in the open edition. Non-breaking describe-only change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The spec-liveness ledgers (
packages/spec/liveness/*.json) classify every authorable property live / experimental / dead with evidence, and the CI gate enforces that classification is complete. But that knowledge lived only in CI — it never reached the person (very often an AI generating templates) writing the metadata. So an author could keep settingenable.feeds: trueorfield.columnNameforever, expecting them to do something, while they silently do nothing.This closes the loop: the ledger now warns the author at build time.
What
New
compilelintpackages/cli/src/utils/lint-liveness-properties.ts, wired as an advisory stage in the compile pipeline (alongside the existing flow anti-pattern lint — never fails the build). It reads the shipped ledgers and warns when an authored object/field sets a misleading property, with a corrective hint:Signal over noise — opt-in per ledger entry
A property being merely
deadis not enough to warn (plenty of dead props are benign display/doc metadata). Warnings opt in via a new annotation:"authorWarn": trueexperimentalentry also warns by default — a declared-but-unenforced guarantee)"authorHint": "…"note)Two rules keep it false-positive-free: (1) only genuinely misleading dead props are marked; (2) booleans warn only when set
trueand onlydefault(false)flags are marked — so schema defaults likeenable.trash/enable.searchablenever trip it. (Discovered the hard way during verification:enable.searchabledefaultstrue, so it's deliberately left unmarked — see its_authorWarnSkipped.) Documented inliveness/README.md.The lint is ledger-driven: coverage grows by annotating more entries, not by touching lint code. v1 covers
object(incl.enable.*) andfield— the highest-signal surfaces.Seeded annotations
enable.{files,feeds,activities,trackHistory}(dead default-false capability flags) +versioning/partitioning/softDelete/search/recordName/defaultDetailForm/keyPrefix(aspirational/duplicate blocks).columnName,referenceFilters,index,maxRating,vectorConfig,fileAttachmentConfig(misleading dead — imply behavior that isn't wired).@objectstack/specnow shipsliveness/in packagefilesso the installed CLI can read the ledgers.Verification
objectstack compileend-to-end: injectedenable.feeds/versioning/columnNameinto a showcase object → all three warned with hints; default-onenable.trashcorrectly silent. The lint also caught two genuine pre-existing dead-prop usages already inapp-showcase(f_rating.maxRating,f_vector.vectorConfig) — flagged as a follow-up.lint-liveness-properties.test.ts) run against the real shipped ledgers, so they double as a contract test (removing anauthorWarnannotation fails the matching assertion).@objectstack/cli451 tests green; liveness gate green (new fields tolerated);@objectstack/specledger JSON validates.This is the productization of the whole spec-liveness effort: measurement (ledger) + completeness gate (CI) + drift re-audit (monthly cron) + now author-facing prevention — directly serving the "templates are AI-authored; avoid AI mistakes" north star.
🤖 Generated with Claude Code