You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Docs metadata: the index share card prints a 511-character description over its title, /privacy and /terms ship no metadata, and an internal MDX note leaks into llms-full.txt and Copy Markdown #299
Found by the seat's site-wide audit of docs.objectos.ai on 2026-10-06, which built main @ b754364. Priority: P1 for the share card, P2 for the rest. Page titles are #167's and stay there. This card covers everything else in the head and the export.
Findings
Share card overflow
/og/docs/en/image.png, the index card, prints its 511-character description over the title, the divider and the brand line.
About 15 English pages have descriptions over 130 characters (e.g. build/ai-skills) and overflow the same way.
Cause: apps/docs/app/og/docs/[...slug]/route.tsx:30-33 passes the raw description.
The {/* Naming, decided under #79… */} comment at resources/license.mdx:13-22 ships in /docs/resources/license.mdx, in llms-full.txt (around lines 11063-71) and in what Copy Markdown copies.
Cause: getLLMText (apps/docs/lib/source.ts:60) does not strip MDX comments.
Done looks like
Share cards: the OG route clamps the description at a word boundary, about 120 characters with an ellipsis. Spot-render the index card and 3 long-description cards and look at them.
Index: the /docs meta description is a short form of 160 characters or fewer, and the full paragraph stays in the page body.
The positioning gate's copy rule (a) must then compare the right string. Either add a short-description constant to apps/docs/lib/positioning.ts that the gate checks, or have the gate compare the body.
State the choice in the PR.
Descriptions: the other over-long and generic descriptions are rewritten to 160 characters or fewer, English only. Siblings are not touched.
Legal pages:/privacy and /terms get generateMetadata, with title, description, canonical, alternates only for authored locales, and og:title. A footer link reaches both.
Export:getLLMText strips {/* … */} comments, pinned by a test.
Gates: green.
Surface
apps/docs/app/og/**, apps/docs/app/[lang]/{privacy,terms}/page.tsx (metadata only), apps/docs/lib/source.ts, apps/docs/lib/positioning.ts, .github/scripts/check-positioning.mjs (rule (a) wiring only), the English frontmatter description: lines, and the footer component.
Order
After #294, because it touches the same legal page files. It can run before or after #167.
Claim: PM loop, repo:objectos seat
Session: session_01FeA1nwBz1ohH65dvffUGKr
Account: hotlong (the seat's linked user, as GET /user answers it; always the card's assignee)
Branch: claude/pm-dispatch-objectos-ju9td1, the session's one designated push branch for this repo. It is about to carry #296's PR (queue recorded on #1676010721523). This card's work is therefore staged: it is built and verified in its own worktree on a local branch cut from origin/main, then rebased and pushed when its turn in the queue comes.
Worktree: objectos-issue-299
Domain: n/a (single-lane repo)
Seat: repo:objectos (objectstack-ai/objectstack#9831)
File surface: apps/docs/app/og/**, apps/docs/app/[lang]/{privacy,terms}/page.tsx (metadata only), apps/docs/lib/source.ts, apps/docs/lib/positioning.ts, .github/scripts/check-positioning.mjs (rule (a) wiring only), English frontmatter description: lines, and the footer component. Titles stay with #167.
Stop on breach and explain in the report.
Container & model: M, mode:subagent, model: default.
Clause-②: no
Thread-read: none
Serial constraints cleared: no. Pushes on this repo are serial on the one branch; the queue order is recorded on the coordination comment. Staging runs in parallel because each card's surface is disjoint from the PR ahead of it.
{
"issue": 299,
"status": "staged",
"branch": "staged/issue-299",
"worktree": "/home/user/objectos-issue-299",
"final_commit": "d6431d6",
"base": "origin/main @ 53ba2f3 (#303); rebased from 6b0e9a5 -> 3b17984 (per PM) -> 53ba2f3 (main moved again before the final gate run); 3 commits: 5bed493 implementation, 7608a30 og clamp never ends inside an open parenthesis, d6431d6 locale-surface verdict line names the new rule",
"pr": null,
"pr_body_draft": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-299/pr-body.md",
"session": "session_01FeA1nwBz1ohH65dvffUGKr (parent seat session; this is a subagent run)",
"premise_still_valid": true,
"summary": "All five parts of #299 are implemented, committed on staged/issue-299 and not pushed. (1) The OG route clamps the description at a word boundary with an ellipsis: 120 width units under a one-line title, one 40-unit line fewer per extra title line, CJK characters counting two, and never ending inside an open parenthesis. (2) /docs gets a 153-character POSITIONING_SHORT; the full POSITIONING paragraph is now the index opening paragraph, and check-positioning rule (a) checks BOTH copies: frontmatter against POSITIONING_SHORT, opening paragraph against POSITIONING. (3) Nine English descriptions are rewritten to 160 characters or fewer: six over-long ones and the three generic ones. (4) /privacy and /terms get generateMetadata through one lib/seo.ts helper, staticPageMetadata, and the docs sidebar footer links to both. (5) getLLMText strips MDX comments outside code fences, pinned by a new mdx-comment rule in check-locale-surface over both llms consumers, with an ablation that went red. Premise check: 6 (not 9) other English descriptions were over 160 on main; 6 + 3 generic = 9 rewritten.",
"files": [
".github/scripts/check-locale-surface.mjs (1859 -> 1896 lines: mdx-comment rule, tally column, 2 red fixtures, per-consumer coverage, verdict line)",
".github/scripts/check-positioning.mjs (189 -> 195 lines: rule (a) checks frontmatter vs POSITIONING_SHORT and opening paragraph vs POSITIONING; self-test 3 -> 4 findings)",
"apps/docs/app/[lang]/docs/layout.tsx (sidebar footer: Privacy / Terms links, locale-prefixed)",
"apps/docs/app/[lang]/privacy/page.tsx (generateMetadata + description per written locale; body text unchanged)",
"apps/docs/app/[lang]/terms/page.tsx (same)",
"apps/docs/app/og/docs/[...slug]/route.tsx (clampDescription)",
"apps/docs/lib/positioning.ts (POSITIONING_SHORT + header)",
"apps/docs/lib/seo.ts (staticPageMetadata helper)",
"apps/docs/lib/source.ts (stripMdxComments in getLLMText)",
"content/docs/index.mdx (short description; full paragraph as opening paragraph)",
"content/docs/build/ai-skills.mdx (description only)",
"content/docs/extend-existing-systems.mdx (description only)",
"content/docs/reference/environment-variables.mdx (description only)",
"content/docs/deploy/kubernetes.mdx (description only)",
"content/docs/quickstart.mdx (description only)",
"content/docs/deploy/air-gapped.mdx (description only)",
"content/docs/resources/faq.mdx (description only)",
"content/docs/configure/webhooks.mdx (description only)",
"content/docs/configure/permissions/record-access.mdx (description only)"
],
"description_changes": [
{
"file": "content/docs/index.mdx",
"before_len": 511,
"after_len": 153,
"before": "POSITIONING (the full positioning paragraph)",
"after": "ObjectOS is the commercial runtime environment built on ObjectStack, hosted (ObjectOS Cloud) or self-managed (ObjectOS Enterprise). You own the ontology."
},
{
"file": "content/docs/build/ai-skills.mdx",
"before_len": 186,
"after_len": 159,
"before": "Install the ObjectStack skills into your coding agent so Claude Code, Cursor, Copilot, Codex and friends know how to author ObjectStack metadata — the ontology ObjectOS runs — correctly.",
"after": "Install the ObjectStack skills so Claude Code, Cursor, Copilot, Codex and other coding agents author correct ObjectStack metadata — the ontology ObjectOS runs."
},
{
"file": "content/docs/extend-existing-systems.mdx",
"before_len": 180,
"after_len": 158,
"before": "Federate a database you already run into ObjectOS as an external datasource — read-only by default, and early — and model the tables you care about as objects, without a migration.",
"after": "Federate a database you already run into ObjectOS as an external datasource — read-only by default, and early — and model its tables as objects, no migration."
},
{
"file": "content/docs/reference/environment-variables.mdx",
"before_len": 176,
"after_len": 156,
"before": "The environment contract of a self-hosted ObjectOS deployment — what each variable decides, which combinations are refused at startup, and the names that no longer do anything.",
"after": "The environment contract of a self-hosted ObjectOS deployment — what each variable decides, which combinations fail at startup, and which names are retired."
},
{
"file": "content/docs/deploy/kubernetes.mdx",
"before_len": 172,
"after_len": 156,
"before": "The properties any orchestrator must preserve when running the licensed ObjectOS image — digest pinning, migration ordering, probes, and what multi-replica makes mandatory.",
"after": "What any orchestrator must preserve to run the licensed ObjectOS image — digest pinning, migration ordering, probes, and what multi-replica makes mandatory."
},
{
"file": "content/docs/quickstart.mdx",
"before_len": 168,
"after_len": 156,
"before": "From zero to a running app on the open-source ObjectStack runtime — install one CLI, run one command. ObjectOS Cloud needs none of it, sign in and build in the browser.",
"after": "From zero to a running app on the open-source ObjectStack runtime: one CLI, one command. ObjectOS Cloud needs none of it — sign in and build in the browser."
},
{
"file": "content/docs/deploy/air-gapped.mdx",
"before_len": 161,
"after_len": 149,
"before": "Air-gap is a licence mode, not a firewall setting — the two settings a disconnected deployment must declare, and the combinations the runtime refuses at startup.",
"after": "Air-gap is a licence mode, not a firewall setting — the two settings a disconnected deployment must declare, and the combinations refused at startup."
},
{
"file": "content/docs/resources/faq.mdx",
"before_len": 43,
"after_len": 153,
"before": "Answers to questions we get asked the most.",
"after": "Common questions about ObjectOS — getting started, databases and multi-tenancy, migrations, permissions, integrations, operations, pricing and licensing."
},
{
"file": "content/docs/configure/webhooks.mdx",
"before_len": 48,
"after_len": 145,
"before": "Outbound webhook delivery, signing, and retries.",
"after": "Outbound webhooks from ObjectOS via a persistent outbox — at-least-once delivery, HMAC signing, bounded retries, and what a receiver must handle."
},
{
"file": "content/docs/configure/permissions/record-access.mdx",
"before_len": 47,
"after_len": 153,
"before": "Control which records a user can see or modify.",
"after": "Control which records a user can see or modify once object permissions allow it — sharing-model defaults, tenant isolation, sharing rules, record shares."
}
],
"description_census": "English descriptions over 160 characters: 7 -> 0 of 79 (measured on 53ba2f3 after the rebase); locale siblings untouched",
"metadata_changes": {
"/docs (en; zh-Hans etc. fall back to it)": "description and og:description 511 -> 153 (POSITIONING_SHORT); title, canonical and hreflang unchanged",
"/privacy": "before: title \"ObjectOS\", 511-character site description, no canonical, no og:title; after: title \"Privacy Policy | ObjectOS\", description 150, canonical https://docs.objectos.ai/privacy, hreflang en, zh-Hans, x-default, og:title \"Privacy Policy\", og:url, og:site_name ObjectOS, og:type website",
"/terms": "before: as /privacy; after: title \"Terms of Service | ObjectOS\", description 155, canonical https://docs.objectos.ai/terms, the same hreflang, og:title \"Terms of Service\"",
"/zh-Hans/privacy, /zh-Hans/terms": "title \"隐私政策 | ObjectOS\" / \"服务条款 | ObjectOS\", zh-Hans descriptions (52 / 64 chars), canonical is their own zh-Hans URL",
"/ja/privacy, /ja/terms (and the other unwritten locales)": "English head, canonical to the English URL, hreflang en, zh-Hans, x-default (before: no canonical)",
"legal descriptions (new)": {
"privacy en": "What ObjectStack AI LLC collects from its public websites and hosted accounts, and the data inside a self-managed deployment that it does not collect.",
"privacy zh-Hans": "ObjectStack AI LLC 从公开网站和托管账号收集哪些信息,以及不会收集的自管部署内部数据。",
"terms en": "How ObjectOS editions are licensed, the Apache-2.0 license of this site's content, the ObjectOS trademark, and responsibility for self-managed deployments.",
"terms zh-Hans": "ObjectOS 各版本的许可方式、本站内容采用的 Apache-2.0 许可、ObjectOS 商标,以及自管部署的责任归属。"
},
"footer": "docs sidebar footer slot (desktop sidebar foot + mobile drawer foot): Privacy -> /privacy, Terms -> /terms, locale-prefixed off en (e.g. /zh-Hans/privacy, /ja/terms)",
"llms-full.txt": "diff vs baseline is exactly two hunks: the index opening paragraph added (+8 lines), and the 11-line naming note (MDX comment) from resources/license.mdx removed; per-page /docs/resources/license.mdx body likewise clean"
},
"rule_a_choice": "Both halves, not either/or: a POSITIONING_SHORT constant in lib/positioning.ts that the gate compares the index frontmatter description against, AND the gate compares the index opening paragraph against POSITIONING, because the 511-character copy moved there and is the copy rule (a) exists to guard. The gate grows 189 -> 195 lines (composed() -> constants(); a 2-line lede()).",
"og_cards": "Budget = (4 - ceil(titleWidth/26), min 1) x 40 width units; 58 of 309 prerendered cards are clamped (route clamp replicated over every title/description pair). Viewed before/after: en index, en build/ai-skills (2-line title), en extend-existing-systems, en reference/environment-variables, en deploy/kubernetes, en build/interface/dashboards and en operate/backup (unclamped controls), and build/ai-skills in zh-Hans, ja, ko and es. All fit with no overlap.",
"tests": "All on final HEAD d6431d6 after the rebase onto 53ba2f3, heavy steps under os-verify-lock. BUILD: NEXT_PRIVATE_STANDALONE=true pnpm turbo run build --force --filter=@objectos/docs (local --env-mode=loose + proxy CA for next/og CJK font fetch) -> \"VERDICT command-exit 0\", 0 font-fetch failures. TEST: pnpm turbo run test --force -> \"✓ 10 self-test(s) passed\". TYPE-CHECK: pnpm turbo run type-check --continue --force -> script echoed \"fumadocs-mdx && next typegen && tsc --noEmit\", \"Tasks: 1 successful, 1 total\"; the lock wrapper (test + type-check) reported \"VERDICT command-exit 0\". gen-zh-hant --check -> \"✓ zh-Hant: 61 generated file(s) match the zh-Hans sources byte for byte.\" check-locale-surface (gate) exit 0 -> \"✓ … and neither `llms` consumer carries a numeric character reference, a malformed link target or an MDX comment\" (llms-full.txt 1/1 bodies, 691 targets, 0 MDX comments; llms.mdx 79/79, 691, 0); --self-test exit 0 -> \"✓ self-test: 31 case(s) over 15 rule(s) and 3 artifact(s) …\". check-positioning (gate) exit 0 -> \"✓ 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 pages\"; --self-test exit 0 -> \"✓ self-test: every rule fails its bad fixture and passes its good one\". check-search-locales (gate) exit 0 -> \"✓ search locales: all 8 locales answer 200 …\"; self-test \"✓ search locales self-test: 8 cases, all 6 rules can fire\". check-translations exit 0 -> \"✓ translations gate passed\" (the ai-skills/webhooks/record-access siblings are now stale: reported, not blocking). check-translation-output --self-test exit 0. Ownership with the workflow argv (name-status diff, --actor objectstack-fleet[bot], TRANSLATION_BOT_LOGIN set) exit 0 -> \"✓ 19 file(s) changed, no translation artifacts touched.\"; ownership --self-test exit 0. check-node-floor gate + self-test exit 0; check-half-states --self-test \"✓ … 1551 cases pass.\" WORKER: opennextjs-cloudflare build --skipNextBuild + wrangler deploy --dry-run: origin/main 53ba2f3 = 49098.99 KiB (weighed in a throwaway worktree, since removed) vs this branch 49074.15 KiB (-24.84 KiB); the legal pages importing lib/seo.ts (which imports source) added nothing measurable. CONTROL BYTES: grep -naP over the 19 changed files -> exit 1 (none); positive control exit 0. BROWSER (AGENTS rule 2): next start on the final build + Playwright Chromium, 1280x900 and 390x844, 0 console/page errors. /docs shows the short description under the H1 and the full paragraph as the first body paragraph; the sidebar Privacy/Terms links navigate to /privacy (\"Privacy Policy | ObjectOS\") and /terms (\"Terms of Service | ObjectOS\"); /zh-Hans/docs/quickstart -> /zh-Hans/privacy (self-canonical); /ja/terms canonical /terms with hreflang [en, zh-Hans, x-default]; on mobile the links appear in the drawer (0 -> 1 visible) and Terms navigates. Server stopped by its PID; port free. ABLATION (one-time, run on the pre-rebase commit b17e082, whose files are identical): ablation-replace.mjs WRAP mode removed only the stripMdxComments call (anchor 1 -> 0, blob 5feca67 -> 5b209b0, on-disk count 0); rebuilt; the built license.body carries the note (count 1); check-locale-surface exit 1 with exactly 2 findings, both mdx-comment (llms-full.txt line 11071; llms.mdx resources/license line 12); restore proven by blob == HEAD 5feca67 and `git diff HEAD` empty; the final build is from the restored committed tree. Strip unit check (scratch): flow comment removed with trailing blank lines; inline comment removed; a comment inside a ``` or ~~~ fence kept; EOF comment removed.",
"screenshots": {
"dir": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-299",
"og_before": [
"og/before/en.png",
"og/before/en_build_ai-skills.png",
"og/before/en_extend-existing-systems.png",
"og/before/en_reference_environment-variables.png",
"og/before/en_deploy_kubernetes.png",
"og/before/en_build_interface_dashboards.png",
"og/before/zh-Hans_build_ai-skills.png",
"og/before/ja_build_ai-skills.png",
"og/before/ko_build_ai-skills.png"
],
"og_after": [
"og/after/en.png",
"og/after/en_build_ai-skills.png",
"og/after/en_extend-existing-systems.png",
"og/after/en_reference_environment-variables.png",
"og/after/en_deploy_kubernetes.png",
"og/after/en_build_interface_dashboards.png",
"og/after/en_operate_backup.png",
"og/after/zh-Hans_build_ai-skills.png",
"og/after/ja_build_ai-skills.png",
"og/after/ko_build_ai-skills.png",
"og/after/es_build_ai-skills.png"
],
"browser": [
"shots/docs-desktop.png",
"shots/legal-nav-desktop.png",
"shots/privacy-en.png",
"shots/privacy-zh-Hans.png",
"shots/drawer-mobile.png"
],
"heads": [
"heads-before.txt",
"heads-after.txt"
],
"llms": [
"llms-full-before.txt",
"llms-full-after.txt"
]
},
"deviations": [
"Rebased twice: 6b0e9a5 -> 3b17984 on the PM note (no commits existed yet), then -> 53ba2f3 when main moved again before the final gate run. Clean, no conflicts. The before-state artifacts (OG cards, heads, llms-full, worker 51040.74 KiB) come from the 3b17984 baseline. The like-for-like worker baseline is 53ba2f3, measured separately.",
"Local build adds --env-mode=loose with NODE_EXTRA_CA_CERTS/NODE_USE_ENV_PROXY so next/og can fetch CJK fonts through the container TLS proxy (otherwise the CJK cards render tofu). Otherwise it is CI-shaped.",
"Rule (a): did both halves (short constant AND body comparison), where the card said either/or. Reason in rule_a_choice.",
"Surface beyond the card list: lib/seo.ts (one shared helper for both legal pages); app/[lang]/docs/layout.tsx (no footer component exists in apps/docs, so the sidebar footer slot was used); check-locale-surface.mjs (the export pin, wired where #282 already pins llms body shape).",
"OG clamp is title-aware (80 units under a two-line title), not a flat ~120: the card example build/ai-skills has a two-line title, and three description lines under it still overlap the divider.",
"A temporary detached worktree /home/user/objectos-299-basecheck was created to weigh origin/main and then removed (node_modules deleted, then git worktree remove without --force). The staged worktree is intact.",
"The comment was posted with objectstack scripts/pm/post-stamped.mjs --repo=objectstack-ai/objectos, because objectos has no comment write tool of its own."
],
"open_questions": [
{
"question": "POSITIONING_SHORT wording is new copy (built from the README definition, the edition names and \"you own it\"), not a README quote. Keep it?",
"options": [
"A keep as is",
"B maintainer rewords it (edit positioning.ts and the index.mdx frontmatter together; the gate holds them equal)"
],
"recommendation": "A, because it leads with ObjectOS and both editions inside 153 characters, and every phrase already appears in positioning.ts"
},
{
"question": "The zh-Hans description entries on the legal pages are hand-written in the TSX content record (the same record whose zh-Hans body #294 hand-wrote); the translation pass covers MDX only. Acceptable?",
"options": [
"A keep (#294 precedent)",
"B drop the zh-Hans description and let zh-Hans fall back to the English description"
],
"recommendation": "A, because B would ship an English meta description on a Chinese page"
},
{
"question": "The footer links read \"Privacy\" and \"Terms\" in every locale. The site configures no UI-string translations (search, \"On this page\" are English everywhere). Localize later?",
"options": [
"A English labels, as now",
"B use each legal page title per locale (隐私政策 / 服务条款)"
],
"recommendation": "A for now, because it matches the rest of the chrome; B is a small follow-up if the chrome is ever translated"
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed — the root layout site-wide description is still the 511-character POSITIONING (rule (a) pins it). After this PR only pages with no metadata of their own inherit it (_not-found, the locale-root redirect pages). Recorded in the PR Acceptance notes."
],
"mcp_calls": "0",
"api_writes": "1 — POST /repos/objectstack-ai/objectos/issues/299/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). Reads only otherwise: GET issues/299, GET pulls?state=closed, GET pulls/294. No push, no PR, no label."
}
{
"issue": 299,
"status": "done",
"addendum_to": "https://github.com/objectstack-ai/objectos/issues/299#issuecomment-6013695182 (staged report)",
"pr": "https://github.com/objectstack-ai/objectos/pull/304",
"pr_state": "open, draft, author objectstack-fleet[bot], assignee hotlong, no reviewers requested, no labels; body read back byte-identical to scratchpad pr-body.md, first line Fixes #299, head line names claude/pm-dispatch-objectos-ju9td1 @ d6431d6",
"pushed_head": "d6431d603719f0b3b8764c95320406e3711b0672",
"branch": "claude/pm-dispatch-objectos-ju9td1: 39e6653 -> d6431d6 (git push --force-with-lease=claude/pm-dispatch-objectos-ju9td1:39e66530058fa7b2ff15a4c165bfb244c95d278b, exit 0, ls-remote reads d6431d6)",
"base": "origin/main 53ba2f3, unchanged since the staged report (merge-base --is-ancestor exit 0), so nothing was re-run; the staged report's verdicts on d6431d6 stand",
"ci": "read once at addendum time, not awaited: Node floor completed/success, Ownership & freshness completed/success, build in_progress",
"cleanup": "worktree /home/user/objectos-issue-299 removed (node_modules deleted, then git worktree remove without --force, exit 0); local branch staged/issue-299 deleted (was d6431d6, equal to the remote head); no server running (port 3299 free)",
"open_questions": "A/A/A, accepted by the seat; the three questions stay in the PR body for the maintainer",
"note": "The shared checkout /home/user/objectos has local branch claude/pm-dispatch-objectos-ju9td1 at 2e6f0e6, now behind the remote d6431d6. I did not touch it.",
"mcp_calls": "0",
"api_writes": "this round 3 REST writes, all via the fleet relay as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectos/pulls (pr_create, draft forced), POST /repos/objectstack-ai/objectos/issues/304/assignees (label-write --assign hotlong, read back MATCHES), POST /repos/objectstack-ai/objectos/issues/299/comments (this addendum); plus 1 git push (not REST). Cumulative with the staged report: 4 REST writes + 1 push."
}
ACCEPT: PR #304 on head d6431d603719f0b3b8764c95320406e3711b0672 · 2026-10-06T09:56Z. I am landing it now: no governed path is touched, it changes 341 lines (under 5,000), and every check is green.
Path surface (get_files): 19 files, +284/−57.
apps/docs:
OG route;
lib/{positioning,seo,source}.ts;
privacy and terms generateMetadata;
the docs layout sidebar footer.
.github/scripts:
check-positioning.mjs: rule (a) gets two copies.
check-locale-surface.mjs: an MDX-comment rule.
10 English frontmatter description: lines, plus the index opening paragraph.
lib/seo.ts and docs/layout.tsx are outside the card's file list. The dev reported both: the repo has no footer component, so the sidebar footer slot holds the links, and seo.ts is the one shared helper. I accept both.
Checks on d6431d6:build, Ownership & freshness and Node floor succeeded; Deploy docs was skipped. mergeable_state is clean on base 53ba2f3.
Docs prose, checked by the seat sentence by sentence:
POSITIONING_SHORT (153 characters): "ObjectOS is the commercial runtime environment built on ObjectStack, hosted (ObjectOS Cloud) or self-managed (ObjectOS Enterprise). You own the ontology."
Every phrase comes from T4, E1 and the promise already in positioning.ts.
It follows today's E1 edition naming; objectos#295 may change that wording later.
The full 511-character paragraph is now the index's opening paragraph.
The gate holds both copies equal to their constants.
The nine other descriptions:
Six are shortened without changing their claims.
Three were generic and are now specific. I checked each against its page's headings:
faq: Getting started … Pricing & legal;
record-access: sharing-model defaults, default tenant isolation, sharing rules, record shares;
OG cards: clamped by width units that account for the title. 58 of 309 cards are clamped. I viewed the index and build/ai-skills cards in 5 locales before and after.
llms-full.txt: the diff is exactly two hunks: the opening paragraph is added and the MDX naming note is removed. The new export pin was shown red under ablation.
Worker size: −24.84 KiB.
Open questions: A/A/A, as the dev recommends: keep POSITIONING_SHORT, keep the hand-written zh-Hans legal descriptions, keep English footer labels. They stay in the PR body for the maintainer.
CI on main (run 37446509423):build, Node floor, Deploy docs / Publish the tested Worker and Deploy docs / Smoke-check the live site succeeded; roll back was skipped.
Deploy verdict:✓ deploy: d3d72442-b8e0-4031-bed6-64caafdd7309 is serving, replacing e76015ca-4f30-429b-a881-70aef7513852.
Housekeeping: the seat removes pm:dispatched from this card.
Activity
objectstack-fleet commentedon Oct 6, 2026
Claim: PM loop,
repo:objectosseatSession:
session_01FeA1nwBz1ohH65dvffUGKrAccount:
hotlong(the seat's linked user, asGET /useranswers it; always the card's assignee)Branch:
claude/pm-dispatch-objectos-ju9td1, the session's one designated push branch for this repo. It is about to carry #296's PR (queue recorded on #1676010721523). This card's work is therefore staged: it is built and verified in its own worktree on a local branch cut fromorigin/main, then rebased and pushed when its turn in the queue comes.Worktree:
objectos-issue-299Domain: n/a (single-lane repo)
Seat:
repo:objectos(objectstack-ai/objectstack#9831)File surface:
apps/docs/app/og/**,apps/docs/app/[lang]/{privacy,terms}/page.tsx(metadata only),apps/docs/lib/source.ts,apps/docs/lib/positioning.ts,.github/scripts/check-positioning.mjs(rule (a) wiring only), English frontmatterdescription:lines, and the footer component. Titles stay with #167.Stop on breach and explain in the report.
Container & model: M,
mode:subagent,model: default.Clause-②: no
Thread-read: none
Serial constraints cleared: no. Pushes on this repo are serial on the one branch; the queue order is recorded on the coordination comment. Staging runs in parallel because each card's surface is disjoint from the PR ahead of it.
Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
os-dev-report
{ "issue": 299, "status": "staged", "branch": "staged/issue-299", "worktree": "/home/user/objectos-issue-299", "final_commit": "d6431d6", "base": "origin/main @ 53ba2f3 (#303); rebased from 6b0e9a5 -> 3b17984 (per PM) -> 53ba2f3 (main moved again before the final gate run); 3 commits: 5bed493 implementation, 7608a30 og clamp never ends inside an open parenthesis, d6431d6 locale-surface verdict line names the new rule", "pr": null, "pr_body_draft": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-299/pr-body.md", "session": "session_01FeA1nwBz1ohH65dvffUGKr (parent seat session; this is a subagent run)", "premise_still_valid": true, "summary": "All five parts of #299 are implemented, committed on staged/issue-299 and not pushed. (1) The OG route clamps the description at a word boundary with an ellipsis: 120 width units under a one-line title, one 40-unit line fewer per extra title line, CJK characters counting two, and never ending inside an open parenthesis. (2) /docs gets a 153-character POSITIONING_SHORT; the full POSITIONING paragraph is now the index opening paragraph, and check-positioning rule (a) checks BOTH copies: frontmatter against POSITIONING_SHORT, opening paragraph against POSITIONING. (3) Nine English descriptions are rewritten to 160 characters or fewer: six over-long ones and the three generic ones. (4) /privacy and /terms get generateMetadata through one lib/seo.ts helper, staticPageMetadata, and the docs sidebar footer links to both. (5) getLLMText strips MDX comments outside code fences, pinned by a new mdx-comment rule in check-locale-surface over both llms consumers, with an ablation that went red. Premise check: 6 (not 9) other English descriptions were over 160 on main; 6 + 3 generic = 9 rewritten.", "files": [ ".github/scripts/check-locale-surface.mjs (1859 -> 1896 lines: mdx-comment rule, tally column, 2 red fixtures, per-consumer coverage, verdict line)", ".github/scripts/check-positioning.mjs (189 -> 195 lines: rule (a) checks frontmatter vs POSITIONING_SHORT and opening paragraph vs POSITIONING; self-test 3 -> 4 findings)", "apps/docs/app/[lang]/docs/layout.tsx (sidebar footer: Privacy / Terms links, locale-prefixed)", "apps/docs/app/[lang]/privacy/page.tsx (generateMetadata + description per written locale; body text unchanged)", "apps/docs/app/[lang]/terms/page.tsx (same)", "apps/docs/app/og/docs/[...slug]/route.tsx (clampDescription)", "apps/docs/lib/positioning.ts (POSITIONING_SHORT + header)", "apps/docs/lib/seo.ts (staticPageMetadata helper)", "apps/docs/lib/source.ts (stripMdxComments in getLLMText)", "content/docs/index.mdx (short description; full paragraph as opening paragraph)", "content/docs/build/ai-skills.mdx (description only)", "content/docs/extend-existing-systems.mdx (description only)", "content/docs/reference/environment-variables.mdx (description only)", "content/docs/deploy/kubernetes.mdx (description only)", "content/docs/quickstart.mdx (description only)", "content/docs/deploy/air-gapped.mdx (description only)", "content/docs/resources/faq.mdx (description only)", "content/docs/configure/webhooks.mdx (description only)", "content/docs/configure/permissions/record-access.mdx (description only)" ], "description_changes": [ { "file": "content/docs/index.mdx", "before_len": 511, "after_len": 153, "before": "POSITIONING (the full positioning paragraph)", "after": "ObjectOS is the commercial runtime environment built on ObjectStack, hosted (ObjectOS Cloud) or self-managed (ObjectOS Enterprise). You own the ontology." }, { "file": "content/docs/build/ai-skills.mdx", "before_len": 186, "after_len": 159, "before": "Install the ObjectStack skills into your coding agent so Claude Code, Cursor, Copilot, Codex and friends know how to author ObjectStack metadata — the ontology ObjectOS runs — correctly.", "after": "Install the ObjectStack skills so Claude Code, Cursor, Copilot, Codex and other coding agents author correct ObjectStack metadata — the ontology ObjectOS runs." }, { "file": "content/docs/extend-existing-systems.mdx", "before_len": 180, "after_len": 158, "before": "Federate a database you already run into ObjectOS as an external datasource — read-only by default, and early — and model the tables you care about as objects, without a migration.", "after": "Federate a database you already run into ObjectOS as an external datasource — read-only by default, and early — and model its tables as objects, no migration." }, { "file": "content/docs/reference/environment-variables.mdx", "before_len": 176, "after_len": 156, "before": "The environment contract of a self-hosted ObjectOS deployment — what each variable decides, which combinations are refused at startup, and the names that no longer do anything.", "after": "The environment contract of a self-hosted ObjectOS deployment — what each variable decides, which combinations fail at startup, and which names are retired." }, { "file": "content/docs/deploy/kubernetes.mdx", "before_len": 172, "after_len": 156, "before": "The properties any orchestrator must preserve when running the licensed ObjectOS image — digest pinning, migration ordering, probes, and what multi-replica makes mandatory.", "after": "What any orchestrator must preserve to run the licensed ObjectOS image — digest pinning, migration ordering, probes, and what multi-replica makes mandatory." }, { "file": "content/docs/quickstart.mdx", "before_len": 168, "after_len": 156, "before": "From zero to a running app on the open-source ObjectStack runtime — install one CLI, run one command. ObjectOS Cloud needs none of it, sign in and build in the browser.", "after": "From zero to a running app on the open-source ObjectStack runtime: one CLI, one command. ObjectOS Cloud needs none of it — sign in and build in the browser." }, { "file": "content/docs/deploy/air-gapped.mdx", "before_len": 161, "after_len": 149, "before": "Air-gap is a licence mode, not a firewall setting — the two settings a disconnected deployment must declare, and the combinations the runtime refuses at startup.", "after": "Air-gap is a licence mode, not a firewall setting — the two settings a disconnected deployment must declare, and the combinations refused at startup." }, { "file": "content/docs/resources/faq.mdx", "before_len": 43, "after_len": 153, "before": "Answers to questions we get asked the most.", "after": "Common questions about ObjectOS — getting started, databases and multi-tenancy, migrations, permissions, integrations, operations, pricing and licensing." }, { "file": "content/docs/configure/webhooks.mdx", "before_len": 48, "after_len": 145, "before": "Outbound webhook delivery, signing, and retries.", "after": "Outbound webhooks from ObjectOS via a persistent outbox — at-least-once delivery, HMAC signing, bounded retries, and what a receiver must handle." }, { "file": "content/docs/configure/permissions/record-access.mdx", "before_len": 47, "after_len": 153, "before": "Control which records a user can see or modify.", "after": "Control which records a user can see or modify once object permissions allow it — sharing-model defaults, tenant isolation, sharing rules, record shares." } ], "description_census": "English descriptions over 160 characters: 7 -> 0 of 79 (measured on 53ba2f3 after the rebase); locale siblings untouched", "metadata_changes": { "/docs (en; zh-Hans etc. fall back to it)": "description and og:description 511 -> 153 (POSITIONING_SHORT); title, canonical and hreflang unchanged", "/privacy": "before: title \"ObjectOS\", 511-character site description, no canonical, no og:title; after: title \"Privacy Policy | ObjectOS\", description 150, canonical https://docs.objectos.ai/privacy, hreflang en, zh-Hans, x-default, og:title \"Privacy Policy\", og:url, og:site_name ObjectOS, og:type website", "/terms": "before: as /privacy; after: title \"Terms of Service | ObjectOS\", description 155, canonical https://docs.objectos.ai/terms, the same hreflang, og:title \"Terms of Service\"", "/zh-Hans/privacy, /zh-Hans/terms": "title \"隐私政策 | ObjectOS\" / \"服务条款 | ObjectOS\", zh-Hans descriptions (52 / 64 chars), canonical is their own zh-Hans URL", "/ja/privacy, /ja/terms (and the other unwritten locales)": "English head, canonical to the English URL, hreflang en, zh-Hans, x-default (before: no canonical)", "legal descriptions (new)": { "privacy en": "What ObjectStack AI LLC collects from its public websites and hosted accounts, and the data inside a self-managed deployment that it does not collect.", "privacy zh-Hans": "ObjectStack AI LLC 从公开网站和托管账号收集哪些信息,以及不会收集的自管部署内部数据。", "terms en": "How ObjectOS editions are licensed, the Apache-2.0 license of this site's content, the ObjectOS trademark, and responsibility for self-managed deployments.", "terms zh-Hans": "ObjectOS 各版本的许可方式、本站内容采用的 Apache-2.0 许可、ObjectOS 商标,以及自管部署的责任归属。" }, "footer": "docs sidebar footer slot (desktop sidebar foot + mobile drawer foot): Privacy -> /privacy, Terms -> /terms, locale-prefixed off en (e.g. /zh-Hans/privacy, /ja/terms)", "llms-full.txt": "diff vs baseline is exactly two hunks: the index opening paragraph added (+8 lines), and the 11-line naming note (MDX comment) from resources/license.mdx removed; per-page /docs/resources/license.mdx body likewise clean" }, "rule_a_choice": "Both halves, not either/or: a POSITIONING_SHORT constant in lib/positioning.ts that the gate compares the index frontmatter description against, AND the gate compares the index opening paragraph against POSITIONING, because the 511-character copy moved there and is the copy rule (a) exists to guard. The gate grows 189 -> 195 lines (composed() -> constants(); a 2-line lede()).", "og_cards": "Budget = (4 - ceil(titleWidth/26), min 1) x 40 width units; 58 of 309 prerendered cards are clamped (route clamp replicated over every title/description pair). Viewed before/after: en index, en build/ai-skills (2-line title), en extend-existing-systems, en reference/environment-variables, en deploy/kubernetes, en build/interface/dashboards and en operate/backup (unclamped controls), and build/ai-skills in zh-Hans, ja, ko and es. All fit with no overlap.", "tests": "All on final HEAD d6431d6 after the rebase onto 53ba2f3, heavy steps under os-verify-lock. BUILD: NEXT_PRIVATE_STANDALONE=true pnpm turbo run build --force --filter=@objectos/docs (local --env-mode=loose + proxy CA for next/og CJK font fetch) -> \"VERDICT command-exit 0\", 0 font-fetch failures. TEST: pnpm turbo run test --force -> \"✓ 10 self-test(s) passed\". TYPE-CHECK: pnpm turbo run type-check --continue --force -> script echoed \"fumadocs-mdx && next typegen && tsc --noEmit\", \"Tasks: 1 successful, 1 total\"; the lock wrapper (test + type-check) reported \"VERDICT command-exit 0\". gen-zh-hant --check -> \"✓ zh-Hant: 61 generated file(s) match the zh-Hans sources byte for byte.\" check-locale-surface (gate) exit 0 -> \"✓ … and neither `llms` consumer carries a numeric character reference, a malformed link target or an MDX comment\" (llms-full.txt 1/1 bodies, 691 targets, 0 MDX comments; llms.mdx 79/79, 691, 0); --self-test exit 0 -> \"✓ self-test: 31 case(s) over 15 rule(s) and 3 artifact(s) …\". check-positioning (gate) exit 0 -> \"✓ 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 pages\"; --self-test exit 0 -> \"✓ self-test: every rule fails its bad fixture and passes its good one\". check-search-locales (gate) exit 0 -> \"✓ search locales: all 8 locales answer 200 …\"; self-test \"✓ search locales self-test: 8 cases, all 6 rules can fire\". check-translations exit 0 -> \"✓ translations gate passed\" (the ai-skills/webhooks/record-access siblings are now stale: reported, not blocking). check-translation-output --self-test exit 0. Ownership with the workflow argv (name-status diff, --actor objectstack-fleet[bot], TRANSLATION_BOT_LOGIN set) exit 0 -> \"✓ 19 file(s) changed, no translation artifacts touched.\"; ownership --self-test exit 0. check-node-floor gate + self-test exit 0; check-half-states --self-test \"✓ … 1551 cases pass.\" WORKER: opennextjs-cloudflare build --skipNextBuild + wrangler deploy --dry-run: origin/main 53ba2f3 = 49098.99 KiB (weighed in a throwaway worktree, since removed) vs this branch 49074.15 KiB (-24.84 KiB); the legal pages importing lib/seo.ts (which imports source) added nothing measurable. CONTROL BYTES: grep -naP over the 19 changed files -> exit 1 (none); positive control exit 0. BROWSER (AGENTS rule 2): next start on the final build + Playwright Chromium, 1280x900 and 390x844, 0 console/page errors. /docs shows the short description under the H1 and the full paragraph as the first body paragraph; the sidebar Privacy/Terms links navigate to /privacy (\"Privacy Policy | ObjectOS\") and /terms (\"Terms of Service | ObjectOS\"); /zh-Hans/docs/quickstart -> /zh-Hans/privacy (self-canonical); /ja/terms canonical /terms with hreflang [en, zh-Hans, x-default]; on mobile the links appear in the drawer (0 -> 1 visible) and Terms navigates. Server stopped by its PID; port free. ABLATION (one-time, run on the pre-rebase commit b17e082, whose files are identical): ablation-replace.mjs WRAP mode removed only the stripMdxComments call (anchor 1 -> 0, blob 5feca67 -> 5b209b0, on-disk count 0); rebuilt; the built license.body carries the note (count 1); check-locale-surface exit 1 with exactly 2 findings, both mdx-comment (llms-full.txt line 11071; llms.mdx resources/license line 12); restore proven by blob == HEAD 5feca67 and `git diff HEAD` empty; the final build is from the restored committed tree. Strip unit check (scratch): flow comment removed with trailing blank lines; inline comment removed; a comment inside a ``` or ~~~ fence kept; EOF comment removed.", "screenshots": { "dir": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-299", "og_before": [ "og/before/en.png", "og/before/en_build_ai-skills.png", "og/before/en_extend-existing-systems.png", "og/before/en_reference_environment-variables.png", "og/before/en_deploy_kubernetes.png", "og/before/en_build_interface_dashboards.png", "og/before/zh-Hans_build_ai-skills.png", "og/before/ja_build_ai-skills.png", "og/before/ko_build_ai-skills.png" ], "og_after": [ "og/after/en.png", "og/after/en_build_ai-skills.png", "og/after/en_extend-existing-systems.png", "og/after/en_reference_environment-variables.png", "og/after/en_deploy_kubernetes.png", "og/after/en_build_interface_dashboards.png", "og/after/en_operate_backup.png", "og/after/zh-Hans_build_ai-skills.png", "og/after/ja_build_ai-skills.png", "og/after/ko_build_ai-skills.png", "og/after/es_build_ai-skills.png" ], "browser": [ "shots/docs-desktop.png", "shots/legal-nav-desktop.png", "shots/privacy-en.png", "shots/privacy-zh-Hans.png", "shots/drawer-mobile.png" ], "heads": [ "heads-before.txt", "heads-after.txt" ], "llms": [ "llms-full-before.txt", "llms-full-after.txt" ] }, "deviations": [ "Rebased twice: 6b0e9a5 -> 3b17984 on the PM note (no commits existed yet), then -> 53ba2f3 when main moved again before the final gate run. Clean, no conflicts. The before-state artifacts (OG cards, heads, llms-full, worker 51040.74 KiB) come from the 3b17984 baseline. The like-for-like worker baseline is 53ba2f3, measured separately.", "Local build adds --env-mode=loose with NODE_EXTRA_CA_CERTS/NODE_USE_ENV_PROXY so next/og can fetch CJK fonts through the container TLS proxy (otherwise the CJK cards render tofu). Otherwise it is CI-shaped.", "Rule (a): did both halves (short constant AND body comparison), where the card said either/or. Reason in rule_a_choice.", "Surface beyond the card list: lib/seo.ts (one shared helper for both legal pages); app/[lang]/docs/layout.tsx (no footer component exists in apps/docs, so the sidebar footer slot was used); check-locale-surface.mjs (the export pin, wired where #282 already pins llms body shape).", "OG clamp is title-aware (80 units under a two-line title), not a flat ~120: the card example build/ai-skills has a two-line title, and three description lines under it still overlap the divider.", "A temporary detached worktree /home/user/objectos-299-basecheck was created to weigh origin/main and then removed (node_modules deleted, then git worktree remove without --force). The staged worktree is intact.", "The comment was posted with objectstack scripts/pm/post-stamped.mjs --repo=objectstack-ai/objectos, because objectos has no comment write tool of its own." ], "open_questions": [ { "question": "POSITIONING_SHORT wording is new copy (built from the README definition, the edition names and \"you own it\"), not a README quote. Keep it?", "options": [ "A keep as is", "B maintainer rewords it (edit positioning.ts and the index.mdx frontmatter together; the gate holds them equal)" ], "recommendation": "A, because it leads with ObjectOS and both editions inside 153 characters, and every phrase already appears in positioning.ts" }, { "question": "The zh-Hans description entries on the legal pages are hand-written in the TSX content record (the same record whose zh-Hans body #294 hand-wrote); the translation pass covers MDX only. Acceptable?", "options": [ "A keep (#294 precedent)", "B drop the zh-Hans description and let zh-Hans fall back to the English description" ], "recommendation": "A, because B would ship an English meta description on a Chinese page" }, { "question": "The footer links read \"Privacy\" and \"Terms\" in every locale. The site configures no UI-string translations (search, \"On this page\" are English everywhere). Localize later?", "options": [ "A English labels, as now", "B use each legal page title per locale (隐私政策 / 服务条款)" ], "recommendation": "A for now, because it matches the rest of the chrome; B is a small follow-up if the chrome is ever translated" } ], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed — the root layout site-wide description is still the 511-character POSITIONING (rule (a) pins it). After this PR only pages with no metadata of their own inherit it (_not-found, the locale-root redirect pages). Recorded in the PR Acceptance notes." ], "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectos/issues/299/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). Reads only otherwise: GET issues/299, GET pulls?state=closed, GET pulls/294. No push, no PR, no label." }Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
os-dev-report-addendum
{ "issue": 299, "status": "done", "addendum_to": "https://github.com/objectstack-ai/objectos/issues/299#issuecomment-6013695182 (staged report)", "pr": "https://github.com/objectstack-ai/objectos/pull/304", "pr_state": "open, draft, author objectstack-fleet[bot], assignee hotlong, no reviewers requested, no labels; body read back byte-identical to scratchpad pr-body.md, first line Fixes #299, head line names claude/pm-dispatch-objectos-ju9td1 @ d6431d6", "pushed_head": "d6431d603719f0b3b8764c95320406e3711b0672", "branch": "claude/pm-dispatch-objectos-ju9td1: 39e6653 -> d6431d6 (git push --force-with-lease=claude/pm-dispatch-objectos-ju9td1:39e66530058fa7b2ff15a4c165bfb244c95d278b, exit 0, ls-remote reads d6431d6)", "base": "origin/main 53ba2f3, unchanged since the staged report (merge-base --is-ancestor exit 0), so nothing was re-run; the staged report's verdicts on d6431d6 stand", "ci": "read once at addendum time, not awaited: Node floor completed/success, Ownership & freshness completed/success, build in_progress", "cleanup": "worktree /home/user/objectos-issue-299 removed (node_modules deleted, then git worktree remove without --force, exit 0); local branch staged/issue-299 deleted (was d6431d6, equal to the remote head); no server running (port 3299 free)", "open_questions": "A/A/A, accepted by the seat; the three questions stay in the PR body for the maintainer", "note": "The shared checkout /home/user/objectos has local branch claude/pm-dispatch-objectos-ju9td1 at 2e6f0e6, now behind the remote d6431d6. I did not touch it.", "mcp_calls": "0", "api_writes": "this round 3 REST writes, all via the fleet relay as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectos/pulls (pr_create, draft forced), POST /repos/objectstack-ai/objectos/issues/304/assignees (label-write --assign hotlong, read back MATCHES), POST /repos/objectstack-ai/objectos/issues/299/comments (this addendum); plus 1 git push (not REST). Cumulative with the staged report: 4 REST writes + 1 push." }Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
ACCEPT: PR #304 on head
d6431d603719f0b3b8764c95320406e3711b0672· 2026-10-06T09:56Z. I am landing it now: no governed path is touched, it changes 341 lines (under 5,000), and every check is green.Path surface (
get_files): 19 files, +284/−57.apps/docs:lib/{positioning,seo,source}.ts;generateMetadata;.github/scripts:check-positioning.mjs: rule (a) gets two copies.check-locale-surface.mjs: an MDX-comment rule.description:lines, plus the index opening paragraph.lib/seo.tsanddocs/layout.tsxare outside the card's file list. The dev reported both: the repo has no footer component, so the sidebar footer slot holds the links, andseo.tsis the one shared helper. I accept both.Checks on
d6431d6:build,Ownership & freshnessandNode floorsucceeded;Deploy docswas skipped.mergeable_stateis clean on base53ba2f3.Docs prose, checked by the seat sentence by sentence:
POSITIONING_SHORT(153 characters): "ObjectOS is the commercial runtime environment built on ObjectStack, hosted (ObjectOS Cloud) or self-managed (ObjectOS Enterprise). You own the ontology."positioning.ts.configure/webhooks.mdx:6-27).Behaviour, measured by the dev:
build/ai-skillscards in 5 locales before and after.Open questions: A/A/A, as the dev recommends: keep
POSITIONING_SHORT, keep the hand-written zh-Hans legal descriptions, keep English footer labels. They stay in the PR body for the maintainer.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
Landed and live · 2026-10-06T10:01Z
601bb37, merged by the seat.Fixes #299closed this card.main(run 37446509423):build,Node floor,Deploy docs / Publish the tested WorkerandDeploy docs / Smoke-check the live sitesucceeded; roll back was skipped.✓ deploy: d3d72442-b8e0-4031-bed6-64caafdd7309 is serving, replacing e76015ca-4f30-429b-a881-70aef7513852.pm:dispatchedfrom this card.main.Generated by Claude Code