Repository navigation
docs: every docs code sample parses with @objectstack/spec 17.7.0, held by a CI gate (closes #316) - #321
Merged
Conversation
…ds or fewer Adds a `seoTitle:` frontmatter line to every English page whose built `<title>` read as one or two words plus the ` | ObjectOS` suffix, so the tab/result title carries the terms a reader searches for while the H1, sidebar and breadcrumb keep the short noun (#166's mechanism). - 67 pages: each gains exactly one line; no `title`, `description` or body line changes. - Every title leads with the page's own specific term, lifted from its description and headings, and renders at 52–60 characters including the suffix (measured on the built HTML). - The three duplicated titles (Approvals, Dashboards, Notifications — each used by a build/configure page and a use page) are now distinct. - English only. Locale siblings are translation artifacts that a non-translator commit may not modify (AGENTS.md, Translation workflow; check-translation-ownership.mjs); the translation pass carries the new key over, and the output report lists the 163 siblings now missing it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…AQ headings, title-weighted per-locale search, consistency pass - Light-mode muted foreground to hsl(0 0% 40%); code comments recoloured in both shiki themes. - Tables get an always-drawn scrollbar and a scroll-driven trailing fade. - FAQ and License FAQ questions become headings. - /api/search builds one locale's index on that locale's first search and weights title > heading > text; check-search-locales gains own-title-buried; smoke-docs asks /api/search in every locale with a nonce control. - Consistency: one data-residency table, one license-validation sentence, ObjectSchema.create, "license" spelling, Configure title, glossary order plus AI seat and Position, logo to the docs home, a translated llms.txt example, three unsourced configure/ai claims removed (with their locale siblings), release-following lines pointed at a populated feed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…comments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ix apiMethods primitives
The Views page declared views inside a defineObject call under an
object-level `view` key. ObjectStack provides no defineObject, and
ObjectSchema.create rejects `view` as an unknown key. Its views are a
defineView container ({ list, listViews, form, formViews }, each view
bound through `data`) registered on the stack with `views: [...]`, which
both samples now show; both parse with @objectstack/spec 17.6.0.
The REST API page's allowed apiMethods values drop the eight retired ones
the spec strips at parse.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ype-check `next typegen` loads next.config.mjs, and fumadocs-mdx 15.0.7's createMDX() starts init() without awaiting it (dist/next/index.js:14-20). init rewrites every .source/*.ts with fs.writeFile (dist/core-DlDe_Eze.js:232-236), which truncates first. typegen ends in process.exit(0), so it can exit inside that window and leave .source/server.ts empty for tsc: TS2306, CI run 37478051451. Running the fumadocs-mdx CLI after typegen makes the CLI, which awaits its writes, the last writer before tsc. typegen does not read .source. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ries, zh-Hant 404, Open-in links follow the page shown - patches/fumadocs-ui@16.8.12.patch: the nine accessible names fumadocs-ui 16.8.12 hard-codes in English (Open Search, Toggle Theme, Open/Collapse Sidebar, Copy Anchor Link, Copy/Copied Text, Toggle Menu, and Radix's "Main") read from its i18n context with the old literal as default. Eight keys are a backport of upstream 16.9.0's own names; lib/ui-text supplies all nine through RootProvider in every locale. - app/[lang]/docs/layout.tsx: page-tree entries (sidebar, breadcrumb, prev/next footer) for pages a locale has no translation of carry lang="en", using the docs page's own translatedLocales detection. - app/not-found.tsx: the 404 copy moves into lib/ui-text (notFound), so the zh-Hant string is generated from zh-Hans by gen-zh-hant and checked by --check like every other Traditional string. - Open in ChatGPT / Claude on a translated page sends the assistant to the translated page itself; English pages and fallbacks keep the English .mdx. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…pec 17.7.0 views.mdx: every list-view fragment carries its required top-level columns, fontWeight is a string, the list view types table states the required keys the spec declares, and each fragment says what it omits. flows.mdx: every sample is rewritten from the old trigger/steps shape to FlowSchema's nodes and edges. Email goes through a notify node with channels: ['email']; requires lists automation and triggers. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ative GitHub icon, code blocks off the landmark list, a localized Open-in prompt axe 4.14.0 reported four failures on every docs page in every locale, English included (#308): - landmark-one-main: the docs layout has no main landmark. DocsPage passes its other props to the article it renders, so the docs page sets role="main" there; no patch needed. - label-content-name-mismatch: the language switcher shows the current language but was named "Choose a language" only. It is now named "English — Choose a language", "Deutsch — Sprache wählen", visible text first, both halves from the i18n context. - svg-img-alt: the GitHub icon was an svg role="img" with no name inside a link already named "GitHub"; it is aria-hidden now. - landmark-unique: every code block's scroll viewport was an unnamed role="region". The role goes; tabIndex 0 stays for keyboard scrolling. The last three are hunks added to patches/fumadocs-ui@16.8.12.patch; its header says why each is a hunk and not a slot, and what an upgrade must re-check. None of the three is fixed upstream as of 16.16.2. The "Open in ChatGPT / Claude" prompt sentence was English in every locale. It is now the ui-text key pageActionsOpenInLLMPrompt, upstream 16.9.0's key name, placeholder and English, translated in six locales and generated for zh-Hant. ui-text's table() now also holds every locale's placeholders to English, so a translation that drops {url} fails the build. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ree entries #298 and #305 made two promises about every localized docs page that no gate checked afterwards: no control is named in English, and every page-tree entry for an untranslated page carries lang="en". The locale surface gate now reads them off the prerendered HTML under apps/docs/.next/server/app/<locale>/, script bodies (the RSC payload) skipped: - english-chrome-name: an accessible name (aria-label, title, alt, placeholder, svg title, .sr-only text) on a localized page that is one of the English pages' names, outside lang="en". The English set is read off the built English pages, minus GitHub and www.objectos.ai. - untranslated-entry-unmarked: a sidebar item or previous/next card for a page the locale has no source file for, whose text does not resolve to lang="en". The oracle is the content tree, not the app's detection. - translated-entry-marked-english: the over-marking direction. Guards keep it from passing over nothing (a page missing from a locale's build, no English name to compare, no entry of a kind recognised in a locale), and a live control feeds both #305 shapes, built from the run's real oracle values, through the same reader on every run. Ten self-test cases, and the control shown red with a reader blinded to names or to lang. On the HTML main built at cec227a it reports 6239 English names and 5974 unmarked entries; on #305's tree, 0 and 0. No ci.yml change: the existing Locale surface step runs the gate after the build, and pnpm turbo run test runs its self-test. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
Below 1280px fumadocs-ui 16.8.12 shows the page's table of contents as a bar rendered in a <header> outside every sectioning element, so the page had two banner landmarks: the site header (#nd-subnav) and this bar. axe 4.14.0 at 390px reported landmark-unique and landmark-no-duplicate-banner on all 48 runs of the #308 sample (8 sections, en/zh-Hans/de, light/dark), on the tree that already carried the other #308 fixes. The bar is a disclosure for the page's headings, so the patch renders it as a <div>; no CSS selects header by element, and the 390px screenshots do not change. Upstream 16.16.2 still renders it as a <header>. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…e inside an English body #305 localized the names of the heading-anchor and code-copy buttons. On a fallback page both buttons sit in the page body, which #298 marks lang="en", so "Ankerlink kopieren" was read with English rules: WCAG 3.1.2, the inverse of what #305 fixed. On main at cf449fa that was 520 + 115 names per Latin-script locale over 55 fallback pages, and 336 + 58 in zh-Hans and zh-Hant over 31. Both buttons now take locale from the useI18n() they already read and render it as their own lang (patches/fumadocs-ui@16.8.12.patch, the two #305 hunks). On a page in the route locale this repeats what html lang says; inside an English body it keeps the name in its own language. check-locale-surface.mjs gains the inverse rule, localized-name-marked-english: one of a locale's own names (read off its built pages, the names that resolve to the locale, minus the English set) inside a lang="en" region with no lang of its own fails. Two self-test cases (red as #305 shipped it, green through an inherited lang), the fixture body now carries a localized anchor button with its own lang, and the live control feeds the inverse shape too, shown red with a reader blind to lang on names. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
The "nothing built" guard in check-locale-surface.mjs fired artifact-missing only when no locale directory held any HTML at all. The legal pages and the locale roots live in the same directories, so a build (or a fixture tree) holding them but no docs page fell through to one docs-page-html-missing per page plus the blind-reader guards. #312 adds legal-page fixtures to every self-test case, and with them this file's "docs pages not built" case read exactly that way. Measured on this tip with #312's own two commits applied in memory (git merge-tree --merge-base 4da46c5): before this change 1 self-test case failed, after it 48 cases over 25 rules pass. The guard now asks whether any <locale>/docs page was built. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ce; zh-Hant generated from zh-Hans - privacy and terms on de, ja, es, fr and ko: the English entry is marked lang="en" (title, date, body, back link) and introduced by the #298 notice (ui-text notTranslated) in the route locale. en and zh-Hans render as before. - The zh-Hans entry of each page moves, unchanged, into a zh-Hans.json beside it; gen-zh-hant converts it to zh-Hant.json like lib/ui-text, so /zh-Hant/privacy and /zh-Hant/terms show Traditional text and gen-zh-hant --check covers it. contentLocales, hreflang and the sitemap gain zh-Hant. - check-locale-surface: STATIC_PAGES lists zh-Hant, and three rules read the built legal pages (legal-english-unmarked, legal-translation-shows-english, legal-page-unread), with self-test cases. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…econd main HomeLayout already renders main#nd-home-layout around its header and the page, so the page's own main was a nested, duplicate landmark on /privacy and /terms in every locale (axe: landmark-no-duplicate-main, landmark-main-is-top-level, landmark-unique). Same classes, so nothing moves on screen. The check-locale-surface legal fixture now mirrors that structure. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…capability claim Rule 3 ended "When in doubt, delete rather than leave behind", and the Retiring a page section told authors never to leave a translation behind for a page "rewritten to say something different". Read literally, both delete a whole translated page over a changed port number, which AGENTS.md step 2 and the new step 3 say stays with the translation pass. Both now state the ruled line: an English correction that removes or reverses a capability assertion deletes the page's locale siblings in the same PR, and wording and number drift stay with the pass. Rule 3 links the ruling. GUIDE_REV is not bumped: no existing translation output becomes invalid. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…ack/spec 17.7.0 First half of the docs code-sample family close-out (#316): the samples on eight English pages now parse with @objectstack/spec 17.7.0, the npm latest. - workflows: the XState-style StateMachineConfig left the spec. A workflow is the `state_machine` validation rule on the object, with `requiredWhen` for "no resolved case without a resolution". The side-effect flow gets its labels and node configs. automation/index stops promising events and guards. - approvals: labels on the start and end nodes, real `update_record` configs, and `resolveAs` moved onto the `expression` approver. - actions: `Action` from `@objectstack/spec/ui`; the confirm question moves from `confirmText` to `description`. There is no flow node that calls an action and no view `actions` key, so the flow-step surface goes, placement is the action's `locations`, and a list view names `rowActions` / `bulkActions`. - data/index: the stack namespace prefix, `inlineHelpText`, a `format` rule in place of field `pattern`, typed validation rules, the real ownership values and lifecycle shape, and no `decimal` type. - relationships, formulas, validation-rules: `Field.masterDetail` and `Field.lookup` take the reference first, `Field.decimal` does not exist, option placeholders become real options, and fragments say what they are. Locale siblings follow ruling A of #256: deleted for workflows, automation/index, actions and data/index (18 files), where a capability assertion is removed or reversed; kept where the change is code shape only. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
…17.7.0 Second half of the docs code-sample family close-out (#316), on 14 more English pages. - cel: the six one-liners become real slots (a formula field, a `script` rule's `condition`, `visibleWhen`, a start node's `condition`, a schedule's `expression`, a notify node's plain-text title), and the "where each tag is used" table names keys that exist. `tmpl` is not a notification slot: `NotifyConfigSchema.title` refuses it. - agents: no `knowledge` block (removed in 17.0.0), memory is `longTerm.enabled` / `maxEntries` / `reflectionInterval`, and flows reach an agent through a `type: 'flow'` action. - data-sources: a flat postgres config, no inline password (the secret is named in `external.credentialsRef`), `defineDatasource()`, a complete manifest, and a declared second datasource. - apps: `mobileNavigation` was removed in 17.0.0. dashboards: `refreshIntervalSeconds`, and no `certified` measures. - quickstart, record-access, rest-api, forms, pages, field-types, the two permission pages, objectql: builder signatures, required `fields`, real options, `requiredWhen`, and fragments that say what they are. The cel and objectql type signatures carry the doc-sample opt-out marker, an MDX comment that renders nothing. Locale siblings follow ruling A of #256: deleted for agents, cel, apps and dashboards (18 files), where a capability assertion is removed or reversed; kept where the change is code shape only. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
`.github/scripts/check-doc-samples.mjs` reads every ts/js block on every English page under content/docs and parses it with @objectstack/spec, as #307 did by hand: statements evaluated as published with only TypeScript syntax removed, every spec constructor call a parse, imports checked against the entry point (type imports through the TypeScript compiler), every flow's builtin nodes against their executor contracts, and a stack's `requires` judged with the flows on its page. A fragment's first comment says what it is, and the gate parses it inside the smallest whole it belongs to. A block that is not a spec sample is N/A; a block that matches no rule fails. An MDX comment `{/* doc-sample: skip — why */}` right before a fence opts one block out, for a counter-example or a type signature. It renders nothing and is stripped from the llms bodies. The spec is pinned exactly in `.github/scripts/doc-samples/` with its npm lockfile, outside the pnpm workspace: as a devDependency of tools/ci-scripts it re-resolved fumadocs-core's optional zod peer from 4.4.3 to 4.6.5 while fumadocs-mdx kept 4.4.3, two zod copies in the docs build. CI installs it with `npm ci --prefix`, and Dependabot gets its own entry for that directory, so a spec release that newly refuses a sample turns its own bump red. The gate's `--self-test` (51 cases, a pass and a refusal for each of the 22 fragment kinds) joins the runner in tools/ci-scripts. The CI step sits next to the zh-Hant check, before type-check. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr
This was referenced Oct 7, 2026
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.
Fixes #316
This is the second of two stacked PRs that close the docs code-sample family (#301, #307, #316). It is based on PR A (
staged/issue-316-a), and its diff here is against A. It does two things:@objectstack/spec17.7.0 (npmlatest; versioned in objectstack4e4e8814).ts/jsblock on every English page parsing against a pinned spec.With A and #315 (already on
main), every English code sample parses.Size: 4280 changed lines against A (+1100/−3180).
check-governed-merges --teston this PR's 38 paths, with that size, answers "NOT governed … 4280 changed line(s) ≤ 5000". Each English correction ships here with its own sibling deletions, as ruling A requires.Two commits on A's tip
e585f02:9144f75(the pages) anda45e682(the gate). This branch's tree equals the reviewed work merged ontomain:git merge-tree --write-tree dc8213d 853ed96gives80a304d, and so doesstaged/issue-316-b^{tree}, sogit diff dc8213d staged/issue-316-bis byte-identical to that merge's diff.What changed, per page
Sources are the published spec,
packages/spec/src/**at objectstack4e4e8814. The npm tarball ships the same files. ObjectStack's public docs at the same commit are cited as "ObjectStackcontent/docs/…".reference/cel.mdx:scriptrule'scondition, which is TRUE for the invalid record; a field'svisibleWhen; a start node'scondition; a schedule'sexpression: cron…; and a notify node's plain-stringtitle.Field.conditionalRequiredbecomesrequiredWhen: the alias was removed in protocol 17 (data/field.zod.ts:1817).Validation.predicatebecomes ascriptrule'scondition.Flow.step.whenbecomes a start node's or an edge'scondition.Action.guardbecomesvisible/disabled.tmplfor notification subjects/bodies is reversed. Measured,NotifyConfigSchemarefuses atmplvalue fortitle("expected string"). The typed template slots are the deprecatedtitleFormat(data/object.zod.ts:2239) and the AI prompt templates (ai/model-registry.zod.ts:121).{ dialect, source }type signature is opted out of the gate and renders as before.build/agents.mdx:knowledgewas removed in 17.0.0 (ai/agent.zod.ts:429). Grounding now goes ininstructions, and source access is set per source.memory.shortTerm(:479) andlongTerm.store(:196) were removed. The memory table now documentslongTerm.enabled,longTerm.maxEntriesandreflectionInterval.type: 'manual')" becomes atype: 'flow'action (ObjectStackai/actions-as-tools.mdx).configure/data-sources.mdx(it has no locale siblings: docs: delete the 14 locale siblings that still forecast federation as unshipped #290 deleted them):config.connectionis not a key; a postgres config is flat.passwordis refused, even one read from the environment. The secret is named inexternal.credentialsRef(data/datasource.zod.ts:318, prescription indata/driver/common.zod.ts:106).defineDatasource(). The claim that a plain object "is exactly what theexamples/app-crmstack does" is reversed: at4e4e8814that stack usesdefineDatasource.typeandname, andAnalyticsReplicais declared.build/interface/apps.mdx:mobileNavigationwas removed in 17.0.0, "fully unimplemented" (ui/app.zod.ts:1649).build/interface/dashboards.mdx:refreshIntervalSeconds(ui/dashboard.zod.ts:1775); nocertifiedmeasures, a key that does not exist.quickstart.mdx:Field.lookup('sys_user', …).configure/permissions/record-access.mdx,reference/rest-api.mdx: the objects get their requiredfields.build/interface/forms.mdx,build/interface/pages.mdx,configure/permissions/{field-level-security,permission-sets}.mdx,reference/field-types.mdx: fragment comments, real options, andconditionalRequired→requiredWhenin the field-types table.reference/objectql.mdx: the query-shape type signature is opted out and renders as before.Locale siblings: ruling A of #256 (
AGENTS.md, #319)reference/celtmplfor notifications is reversed; the table's keys are removed or renamedbuild/agentsbuild/interface/appsbuild/interface/dashboardsforms,pages,record-access,rest-api,field-level-security,permission-sets,field-types,objectqldata-sources,quickstart18 files are deleted. Before each deletion, I confirmed that the sibling carries the claim.
gen-zh-hant --checkpasses with 54 files.The gate:
.github/scripts/check-doc-samples.mjsThe script header has the full contract.
What it reads: every English page (the locales come from
apps/docs/lib/i18n.ts), and in it every fencedts/jsblock.How it judges a block, by the first rule that matches:
Every spec constructor call is a parse. Imports are checked against the entry point, and type imports go through the TypeScript compiler. Every flow is also parsed against its executor contracts, and a stack's
requiresis judged with its page's flows, as Docs code samples the current @objectstack/spec refuses: the remaining view fragments in build/interface/views.mdx and the send_email flow action in build/automation/flows.mdx #307 did. A block that matches no rule fails.The opt-out marker is
{/* doc-sample: skip — WHY */}, on the last line before the fence. It is an MDX comment: it renders nothing, andlib/source.tsstrips it from the llms bodies. Use it for a counter-example or a type signature. A marker without a reason, a marker that drifted off its fence, and a marker on an unread block all fail. Two blocks use it, both type signatures.The pin:
.github/scripts/doc-samples/package.jsonpins@objectstack/specto exactly17.7.0, with an npm lockfile. The gate refuses any other installed version.tools/ci-scripts, it re-resolvedfumadocs-core's optionalzodpeer from 4.4.3 to 4.6.5 whilefumadocs-mdxkept 4.4.3. That is two zod copies in the docs build.Bumping it: a Dependabot entry for
/.github/scripts/doc-samples, in theobjectstackgroup, opens the bump as a PR. The gate runs on that PR, so a release that newly refuses a sample turns its own bump red. By hand, runnpm install --prefix .github/scripts/doc-samples --save-exact @objectstack/spec@VERSION.CI:
npm ci --prefix .github/scripts/doc-samples, then the gate, next to "Generated zh-Hant is current", beforetype-check. The--self-testjoinstools/ci-scripts/run-self-tests.mjs.testtask's hash. Measured with the lockfile mutated and then restored:a36d68f→bd1b30c→a36d68f.Self-test: 51 cases. Each of the 22 fragment kinds must have a fixture it passes and a fixture it refuses.
Cost: the gate takes about 2 s and the self-test about 6 s;
npm ciinstalls 3 packages.Parse results:
@objectstack/spec17.7.0"Unchecked" means a fragment with no comment saying what it is; the gate fails it. The middle column adds only those comments.
Red and green:
dc8213d✗ doc samples: 66 block(s) refused or unchecked on 21 page(s) · 35 pass · 10 not a spec sample · 0 opted oute585f02)✗ doc samples: 39 block(s) refused or unchecked on 14 page(s) · 62 pass, exactly this PR's 14 pagesa45e682)✓ doc samples: every ts/js block on 79 English page(s) parses with @objectstack/spec 17.7.0 · 98 pass · 10 not a spec sample · 2 opted out--self-test✓ self-test: 51 case(s) hold, and each of the 22 fragment kinds has a fixture it passes and one it refuses (@objectstack/spec 17.7.0)Page-text ablation, on a scratch copy of the merged tree:
retention: { maxAge: '14d' }→'14d'(anchor 1 → 0): EXIT 1,lifecycle.retention: Invalid input: expected object, received string.Verification at
a45e682pnpm install --frozen-lockfilepnpm turbo run type-check --continue --force(lock)✓ Types generated successfully· 1 successful, 0 cachedNEXT_PRIVATE_STANDALONE=true pnpm turbo run build --force(lock)pnpm turbo run test --force(lock)✓ 11 self-test(s) passedcheck-doc-samples.mjs/--self-testcheck-locale-surface.mjs✓ every advertised URL has a source file and every source file is advertised; … neither llms consumer carries … an MDX commentcheck-positioning.mjs✓ positioning: 4 copies equal their constants; the brand is right in 659 pages and 2 llms bodies; no stale sentence in 79 English sources and the en entry of 2 legal pagescheck-search-locales.mjs✓ search locales: all 8 locales answer 200, find "permissions", find every own page by its title within the first 3 pages, and find nothing for a noncegen-zh-hant.mjs --check✓ zh-Hant: 54 generated file(s) match the zh-Hans sources byte for byte.git diff --name-status --no-renames staged/issue-316-a...HEAD),--actor hotlong,TRANSLATION_BOT_LOGINset✓ 38 file(s) changed: 18 translation artifact(s) deleted, none added or modified.With the bot as actor (the control): EXIT 1. Againstorigin/main...HEAD: EXIT 0 · 64 files, 36 deleted; the control is EXIT 1check-translations.mjs✓ translations gate passed. Reported, not blocking: zh-Hans 39 stale / 39 missing; the others 20 stale / 59 missingcheck-translation-output.mjs --self-test/--files✓ translation output gate passed (213 pre-existing finding(s) reported)check-node-floor.mjs --self-test/ run✓ self-test: 17 rule case(s), 24 satisfies case(s) and 18 range case(s) …/ EXIT 0 ·✅ Every declared floor clears what the dependency tree requires, and the declarations agree.check-half-states.mjs --self-test1551 cases passBrowser. These pages are byte-identical to the reviewed work, so its measurements still apply.
next startserved the build, and Chromium loaded the changed pages at 1440 and 390:scrollWidthequal to the viewport;/zh-Hant/docs/reference/celanswers 200 with the English body.I looked at the CEL examples and table, the agent memory table, the apps mobile note, the data-sources declaration and the objectql type signature.
NOT MEASURED: behaviour on a running ObjectOS runtime.
Acceptance notes
packages/spec/src/shared/expression.zod.ts's dialect table lists thetemplatedialect for "notification subjects/bodies". ButNotifyConfigSchema.titleisz.string(), and it refuses atmplvalue:defineFlowand the notify contract both answer "expected string, received object". The seam runs from the spec's template-dialect row toautomation/io-node-config.zod.tsNotifyConfigSchema.title.cel.mdxfollows the parse. The seat routes this to objectstack.reference/cel.mdx's variable table saysinputis available in "flow steps".check-node-floorreadspnpm-lock.yamlonly, so the spec'sengines.node >=22.0.0in the npm lockfile is outside it. That is below the repo floor (22.12.0), so nothing is missed today.维护者速读(草稿)
@objectstack/spec17.7.0 解析。按 [Decision] An English docs correction leaves its locale siblings asserting the corrected-away claim — #59 says delete them, the seat post says leave them, and #68 blocks the pass that would fix them #256 裁决 A,删除了 4 个页面的 18 个译文。新增 CI 门禁:每个 PR 都用锁定版本的 spec 解析全部英文示例。门禁内置 51 个自测用例。a45e682可去掉门禁,revert9144f75可撤回页面修复。Pushed head
a8ce2eaonclaude/pm-dispatch-objectos-ju9td1, a fast-forward with no force. It starts at the remote branch headc57caa2(PR #320), mergesorigin/main@5483c4a(#320's squash; after the merge the diff againstmainis empty), and cherry-picks9144f75anda45e682.git diff origin/main a8ce2eais byte-identical togit diff e585f02 a45e682. Size: 38 files, +1100/−3180 = 4280 changed lines, under the 5000-line human-merge line.Generated by Claude Code