docs content: meta descriptions too thin to serve as snippets — median 46 chars, 228 of 403 under 70 #12238
Copy link
Copy link
Closed
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationdomain:devxpriority:p1High: required for production / M2High: required for production / M2size/l
Description
One-liner
Every page has a description (good), but the median is 46 characters and 228 of 403 are under 70 — far below the ~155 characters a result gets. Google discards a description that thin and writes its own snippet from body text, so the one line we control is wasted. At the other end, 42 pages run past 160 and get cut mid-sentence.
Measured
description length: n=403 min=20 median=46 max=381 <70 chars: 228 >160 chars: 42
Expected
- Rewrite to 120–155 characters: what the page lets you do, in the words a reader would search, ending on a reason to click.
- Trim the 42 over-long ones to fit rather than letting the SERP truncate them.
- Add a repo gate that fails a doc page whose
descriptionis outside 70–160 characters, so the fix does not decay.
Acceptance
- every
content/docs/**description is 70–160 characters - a
check:*gate enforces the range and runs inLint & Repo Gates - descriptions read as sentences, not as truncated titles
Source
Found in an SEO review of the docs site (apps/docs) run on 2026-08-25, measured against the local dev server and against production. The canonical origin is https://objectstack.ai — maintainer ruling recorded in #10659:
这个仓的文档站规范 URL 是 https://objectstack.ai
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationdomain:devxpriority:p1High: required for production / M2High: required for production / M2size/l
Activity
os-zhuang commentedon Aug 25, 2026
Held — hard serial on
content/docs/**, behind #12236 and then #12237. Known trap: the description rewrite and the title rewrite touch the same frontmatter block of the same files, so they cannot run in parallel with each other either; and the length gate this card adds and the one #12237 may add should be one script, not two.claude commentedon Aug 31, 2026
pm:queue→pm:blocked— the hold was real, documented, and invisible to every querydomain:devxPM seat (#6023), R33. This card came up as the only remaining dispatch candidate in the lane, so this seat measured its fence before taking it rather than either obeying or ignoring it. The measurement said do not take it, and then said something more useful: the label was lying.What the hold actually is
os-zhuang recorded it on 2026-08-25, and it is not a vague fence:
⇒ a named predecessor chain and a named technical reason. Measured today:
<h1>)pm:blocked⇐ this card's immediate predecessor, has not runpm:queue— i.e. advertising itself as dispatchable⇒ dispatching this now would run the description rewrite before the title rewrite, into the same frontmatter block of the same files — the exact collision the hold names.
⛔ So the label is corrected, not the plan
Blocked-by:lines — none of them reads a sentence in a comment. For six days this card has read "free to dispatch" to every query while carrying an explicit serial hold, and it took being the last candidate in the lane for anyone to open it.⇒ ⭐ This is the same residue class this lane keeps filing (#13526, #13561) in its third shape: not a stale
pm:dispatched, not an assignee with no claim, but a real constraint that was written down in the one place the state machine cannot see. Putting it in the vocabulary means it now inherits the existing unlock scan and ageing machinery for free — ⛔ no new label, no new sweep.⛔ Nothing about the card's substance, grade, priority, size or ownership is touched.
domain:devx,priority:p1,size/l,repo:objectstackall stand. The hold is os-zhuang's and is not overridden — it is being made machine-readable.domain:devxhas zero dispatchable cards and runs below its standing concurrency of 4. That is a measured fact with its exclusions shown, ⛔ not an assertion — and a fence honoured is a legitimate reason to run short, where forcing a fourth by crossing one is not.Generated by Claude Code
claude commentedon Sep 1, 2026
Label note:
repo:objectstackremoved by the domain:devx seat (sessionsession_01WLJQhde67SeTccsmnBVarV) executing the triage retirement ruling on #13991 (comment 5487742846, 2026-09-01); ledger record landed via PR #14156. Routing is unchanged —documentation+domain:devxalready fully determine it.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
Maintainer rulings recorded: scope, rewrite volume, no new gate · 2026-09-27T14:48Z
domain:devxseat 2 (#20163),session_018mA64scZ8fmpiPkrHVAwXj. Three questions were put to the maintainer in this session's chat, with the seat's recommendation marked on each. The answers are verbatim option picks. ⛔ Do not re-open them at dispatch.Readings they rest on (
origin/main0d3ec471, measured by the seat; the dev re-derives them):descriptionlengthcontent/docs/**minusreferences/**,releases/**)references/**releases/**(release-owned, ⛔ out)The card body's "median 46, 228 of 403 under 70" was the mix of the two populations. Authored pages have since improved; the generated half is still the bulk.
references/**. The generator lives underpackages/spec/scripts/(domain:spec), which makes this a cross-lane card by the maintainer's order. The claim will declare both halves' file surface, and the spec seats get a notice.check:*gate enforces the range" is dropped by this ruling. The fix is content only.The card body's maintainer-voice caveat still stands: the PR carries the rule and the full before/after table, and it stays draft for the maintainer's review.
Dispatch waits only on this card's
Blocked-by: #12237. PR #20170 is in the merge queue now. When it lands, this card is released and dispatched in the same round.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
Release: the
pm:blockedhold (Blocked-by: #12237, recorded in5473104258) is discharged. #12237 closedcompletedat 15:13Z when PR #20170 squashed as5983d112. The unlock was re-derived before release: no other blocker is named on this card. The maintainer's rulings5856895911settle scope, rewrite volume and the gate. Destination: theClaim:below.Claim: PM loop round 2 (seat
domain:devx#2)Session:
session_018mA64scZ8fmpiPkrHVAwXjAccount:
os-litantBranch:
claude/issue-12238-description-ruleWorktree:
objectstack-issue-12238(in the dev's cloud container)Domain:
domain:devx(cross-lane by the maintainer's ruling 「一张卡全做」: the generator half lives indomain:spec'spackages/spec/scripts/)Seat:
domain:devx#2File surface:
description:line of the authoredcontent/docs/**/*.mdxpages outside 70–160 characters (about 52).packages/spec/scripts/build-docs.ts, the description emission only (:479module pages,:912category index pages), plus its tests.content/docs/references/**, regenerated bygen:docsand never hand-edited.packages/spec/src/**,title:/navTitle:lines,releases/**,apps/docs/**ormeta.json. On a breach the dev stops and explains it in the report.Container & model: L (card
size/l),mode:cloud,model: opus.dispatch-gates --tieranswers "no path-derived mandate … floor sonnet · default opus · ceiling fable". The default tier is chosen because the generator derivation and the rewrite of 52 rows need judgement.Clause-②: no
Thread-read: 5856895911
Serial constraints cleared: open-PR census at 2026-09-27T15:16Z covered all 12 open PRs, with file lists paged. Five touch authored or generated docs:
references/**pages. That is os-regen: resolved by regeneration on merge, withos-regen-merge.sh.os migrate meta --stored, not silence (#17321) #20244 (deployment/cli.mdx).None claims
build-docs.ts. LatestClaim:on the openpm:dispatchedcards: [finding] a joined report'schart— container andblocks[].chart— parses and is never drawn, while the liveness ledger names the joined branch as its reader #20161, import mapping: no fieldMapping target can build a compound (address) value from separate CSV columns — a dotted target passes validate and dry-run, then fails every row on commit #20149, [finding] After PR #19962 rewrites the RLScheckdescribe, three texts still quote the old "defaults to USING clause if not specified" contract, and theusingtext never says it is the insert check when nocheckis declared #19967, [finding]os generateprojects ObjectStackDefinitionSchema through THREE override-lessz.toJSONSchemacalls — the schema an author's editor validates against is wider than the runtime, at 7 measured sites #19098 and [Deferred by ruling] Unify flow field-expression assignment onto the CEL engine — the B half of the #11060 ruling, awaiting maintainer appetite #11182 name authored pages for body edits. This card changes only onedescription:line per page, so this is ordinary concurrency. docs(spec): carry the page-title rule into the docs GENERATOR — 225 of 405 pages are emitted, so a hand edit is reverted (split (b) of #12237) #15403 (domain:spec) will editbuild-docs.ts:478, the title emission, adjacent to this card's:479. It is not in flight; a serial note is left on it.Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
os-dev-report
{ "issue": 12238, "status": "done", "branch": "claude/issue-12238-description-rule", "pr": "https://github.com/objectstack-ai/objectstack/pull/20258", "session": "session_01RCEEP3Z95jrpXCeF3it3Y2", "premise_still_valid": true, "summary": "Both halves in one draft PR, per ruling 「一张卡全做」. (1) The authored half rewrites the 52 descriptions outside 70-160 (15 under, 37 over; counts re-derived on base e0f17a3 and matching the seat's reading) to 120-155 characters. Only the description line changes; title and navTitle lines are untouched. (2) The generator half: build-docs.ts now takes each module page's description from the module doc block that findModuleDocBlock already selects, via the new scripts/lib/page-description.ts (18-case test). A thin lead is completed with the page's schema names, a module with no doc block falls back to a schema-name sentence, category overviews get an in-range phrase, and the value is emitted JSON-double-quoted. There is no src edit and no new gate. Result: all 392 non-release pages are in 70-160 with 0 exceptions (authored median 117 → 129; references median 28 → 138, 210 under 70 → 0). Module-page tally: 115 from the doc block, 19 doc block + schema names, 62 on the schema-name fallback (no module doc block), plus 14 category indexes. main moved during the work and was merged via os-regen-merge.sh. builtin-node-config.mdx changed on both sides and was regenerated in its own commit (4b7d63cc). PR assignee os-litant; card assignee not written.", "tests": "On HEAD 4b7d63cc, after a real `pnpm --filter @objectstack/spec build` (os-verify-lock VERDICT command-exit 0): `check:generated` exit 0 with every gate ✓, `check:docs` reporting '226 generated files in sync'. `dispatch-gates --commands` derived 94 families; `--ran` with recorded exit codes gave '94 derived, 92 run, 2 NOT-MEASURED, 0 UNRUN' (exit 0), and all 92 exit 0. `check:pm-dispatch-gates` (a 711s self-test, 1925 cases) was run once on pre-merge head 652b36d; the other 93 families were re-run on 4b7d63cc. NOT MEASURED: check:dual-build-cjs-loads and check:type-check-debt --re-measure, both exit 3 PREREQUISITE NOT MET because they need the full packages/* build closure; CI builds that. `pnpm --filter @objectstack/spec typecheck` exit 0. vitest: page-description.test.ts 18/18; local project 3 files / 68 tests; repo project (file-description, references-banner, category-title, root-index) 4 files / 146 tests, all pass. Ad hoc: js-yaml parse of all 392 frontmatters gave 0 errors and 0 descriptions outside 70-160. No ablation: no gate was added.", "gates": "94 derived / 92 run exit 0 / 2 NOT-MEASURED (exit 3: check:dual-build-cjs-loads, check:type-check-debt) / 0 unrun; check:generated green on 4b7d63cc after a real spec build", "line_budget": "265 files, +801 / -266 = 1,067 changed lines vs origin/main, generated files included — under 5,000", "files_changed": "52 authored content/docs/**/*.mdx (description line only); 210 content/docs/references/**/*.mdx (regenerated, description line only); packages/spec/scripts/build-docs.ts; packages/spec/scripts/lib/page-description.ts (new); packages/spec/scripts/page-description.test.ts (new)", "deviations": [ "The file surface named build-docs.ts 'description emission and its tests'. The emission rule lives in a NEW module, packages/spec/scripts/lib/page-description.ts, beside build-docs.ts. Reason: build-docs.ts is a side-effecting top-level script and cannot be unit-tested; file-description/format-type/schema-section were extracted the same way. The build-docs.ts hunks are listed in the PR body for #15403.", "check:pm-dispatch-gates: its 711s self-test verdict was taken on pre-merge head 652b36d and not re-run on 4b7d63cc. It is checker-health only and the merge touched none of its inputs." ], "changeset": "skip-changeset (measured): packages/spec files[] excludes scripts/; modulePageDescription/categoryIndexDescription have 0 hits in every shipped path after a build, while the positive control ObjectSchema has 56 hits in dist; content/docs belongs to no package", "mcp_calls": "3 — mcp__github__issue_read (get), mcp__github__issue_read (get_comments), mcp__github__list_pull_requests; all reads, no write tool", "api_writes": "3 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches) carrying 4 ops: pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft forced) · labels_add skip-changeset (POST /issues/20258/labels) + assign os-litant (POST /issues/20258/assignees) · comment (POST /issues/12238/comments, this report). Plus git push (not REST)", "open_questions": [ { "question": "Two generated pages (references/data/validation, references/marketplace/package) end on a word-boundary ellipsis. Their first doc-block sentence is over 160 characters and has no clause boundary that keeps 70 or more. Acceptable?", "options": ["A keep the ellipsis (honest cut, in range)", "B fall back to the schema-name sentence for any over-long lead with no clause boundary"], "recommendation": "A: the page's own words beat a template, and the cut is visible rather than silent. B is a one-line change in shorten() if the maintainer's voice review prefers it." }, { "question": "Generated descriptions are written double-quoted (JSON.stringify), while authored pages mostly use plain scalars. Should the generator quote only when needed?", "options": ["A always quote (deterministic, safe for ': ' and quotes in doc-block prose)", "B quote only when the YAML needs it"], "recommendation": "A: every value comes from free prose, and one rule is easier to keep correct than a YAML-special-character predicate." } ], "out_of_scope_findings": [ "carrier: none (承接者:无) · 62 packages/spec/src modules have no module-level doc block, so their reference pages use the schema-name fallback (e.g. data/object, api/contract, kernel/plugin). Writing those docblocks is a src edit on the clause-② path limb. Noted in the PR's Acceptance notes and not filed: it is a polish item, not a defect, contract violation or authoring trap.", "carrier: none (承接者:无) · some module doc-block leads read as internal notes rather than reader copy (e.g. kernel/metadata-protection 'Phase 1 introduces the item-level lock …'). The generator reproduces the source faithfully. Noted in the Acceptance notes and not filed." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
PM review — PR #20258: ACCEPT (head
4b7d63cc) · 2026-09-27T16:51Zdomain:devxseat 2,session_018mA64scZ8fmpiPkrHVAwXj, reviewer of record. Report5857657129. Every reading below was taken on GitHub or the tree, not from the report.main, internal head. The first body line isFixes #12238, and it is the only closing keyword. Assigneeos-litant.e4621867: 52 authoredcontent/docs/**/*.mdx, 210content/docs/references/**(regenerated), and 3 underpackages/spec/scripts/. 0 underpackages/spec/src/**, so the clause-② path limb is not hit. 0 underreleases/**.description:line changed; 0 body and 0 other-frontmatter changes, sotitle:/navTitle:are untouched. Every old value was outside 70–160. Every new value is 138–155 (all 52 inside the card's 120–155).description:line only, 0 body changes. New values are 70–160, median 139.build-docs.tsswaps its two template emissions (:479module pages,:912category indexes) forlib/page-description.ts, which reads the doc blockfindModuleDocBlockalready selects. The output is deterministic: no clock, randomness or environment input. It adds a run-summary tally and has an 18-case test.build-docs.ts(scripts/lib/page-description.ts+ test) because the top-level script cannot be unit-tested. It follows the existinglib/extraction pattern and stays in the same directory and concern, so it is accepted.skip-changesetis correct:packages/specfiles[]does not shipscripts/, and the docs are not published.4b7d63ccmcp_calls3, all reads, 0 write tools. Writes went only through the relay.references/data/validation,references/marketplace/package) is copy, and the card says descriptions "read as sentences". It goes to the maintainer with the voice review, on PR docs(content,spec): search-ready page descriptions — 52 authored rewrites and derived reference descriptions #20258.src/**edit on the clause-② path.needs-user-decisionand a quick-read; this card stayspm:dispatched.Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
Maintainer approval recorded — PR #20258 · patch round ordered · 2026-09-28T02:13Z
domain:devxseat 2,session_018mA64scZ8fmpiPkrHVAwXj. Every reading below was taken on GitHub at this act.Approval. Review
5333290305byhotlong,APPROVED, submitted 2026-09-28T02:11:00Z on head4b7d63cc, body empty, 0 inline comments.hotlongis one of the two authorized approval accounts (os-zhuang,hotlong). No new comment on this card or on the PR since the quick-read5857844797. This discharges the card body's maintainer voice review: the rule and the before/after tables stand as approved. Under the protocol, a later push does not expire the approval.needs-user-decisionleaves the PR in the same act.The A/B row. The approval carries no text, so it does not pick A or B. Seat reading:
…rows (references/data/validation,references/marketplace/package) do not meet it.Why a push is owed anyway (landing section A).
mainmoved 45 commits past the PR's merge basee4621867(nowd498113b).content/docs/references/**pages changed on both sides:api/{dispatcher,error-code-ledger,plugin-rest-api,rest-server},automation/schemaless-node-config,data/{mapping,validation},security/{permission,rls},ui/report.packages/spec/src/**doc sources also changed onmain.os-regen-merge.shplus a full regenerate is required before the PR queues.Patch round (sent to the dev session
session_01RCEEP3Z95jrpXCeF3it3Y2):origin/mainviabash scripts/pm/os-regen-merge.sh, then regenerate the docs. ⛔ No rebase and no force-push.packages/spec/scripts/lib/page-description.ts, a doc-block lead that cannot fit 70–160 without an ellipsis cut falls back to the schema-name sentence. There is no…output path left. Update the test battery to pin this.os-dev-reportdelta on this card and update the PR body's generator section.After the delta, the seat re-reviews and then lands. The card stays
pm:dispatched.Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
Correction to
5862075970— B and the patch round RETRACTED · the maintainer landed the PR as it stands · 2026-09-28T02:15Zdomain:devxseat 2,session_018mA64scZ8fmpiPkrHVAwXj.What I missed. The PR timeline shows that
hotlongdid more than approve.hotlongthen landed the PR personally, and all of it came BEFORE my record5862075970:APPROVEDat 2026-09-28T02:11:00Z;ready_for_reviewat 2026-09-28T02:11:04Z;auto_merge_enabledat 2026-09-28T02:11:18Z;added_to_merge_queueat 2026-09-28T02:12:19Z.The events reached this seat late. I wrote the record after reading the reviews and comments, but without re-reading the PR object or its timeline. That was the lapse.
Reading, corrected. The maintainer's own landing act on head
4b7d63ccsettles the A/B row as A: the two…rows stay as they are. It also answers the regen question for this landing. The merge queue'smerge_grouprun is the drift gate on the merged tree. So:5862075970.session_01RCEEP3Z95jrpXCeF3it3Y2was interrupted at 2026-09-28T02:14:54Z. At that moment the branch head was still4b7d63cc(git ls-remote), so nothing was pushed and the queue entry is intact.needs-user-decisionremoval from the PR stands, because the approval discharged it.Now. The PR is in the merge queue (
gh-readonly-queue/main/pr-20258-8af914a3…), with auto-merge byhotlong. The seat follows it to MERGED and then closes out this card.merge_groupis red (for example generated drift from the 45maincommits), the seat handles the kick-out under landing section A:os-regen-merge.sh+ regenerate, with the approved content unchanged, and A kept.Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
Landed — PR #20258 merged as
9daced0b· 2026-09-28T02:43Zdomain:devxseat 2,session_018mA64scZ8fmpiPkrHVAwXj. Landing record for claim5857109111.main:9daced0bisorigin/main's HEAD at this read. It touches 265 files, +801 / −266.hotlongmerged it through the merge queue at 2026-09-28T02:41:39Z. Spot reads onorigin/main:kernel/architecture.mdxandpermissions/authorization.mdxcarry the approved rewrittendescription:rows (143 and 156 characters).references/data/mapping.mdxcarries a derived sentence in place of the old template.build-docs.tsemitsmodulePageDescription(…)(:489) andcategoryIndexDescription(…)(:931).… protocol schemas/Complete reference for all …template descriptions remain undercontent/docs/references/**.mainhad also changed carry, onmain, exactly the PR head'sdescription:lines.merge_grouprun on9daced0bwas green:CI,Build Docs,Lint & Repo Gates,Lint & Type Check,Governed Surface Guard,Spec Liveness Check,Closing-Target Claim Guard.5857839052.hotlongAPPROVED (review5333290305), then marked the PR ready, enabled auto-merge and enqueued it at 02:11–02:12Z, keeping the 2 ellipsis rows as they are (A).5862075970was retracted in5862098826before any push.5856895911: 「一张卡全做」 · 「只改超范围的 52 页」 · 「不加门禁」.completedbyFixes #12238.pm:dispatchedis removed in this act;domain:devx/priority:p1stay.domain:spec) can takebuild-docs.ts:478(title emission) with no serial wait. PR docs(content,spec): search-ready page descriptions — 52 authored rewrites and derived reference descriptions #20258's body names the description hunks.session_01RCEEP3Z95jrpXCeF3it3Y2is archived after this record.Generated by Claude Code
docs(content,spec): search-ready page descriptions — 52 authored rewr…