Skip to content

Translations are hand-maintained with no provenance: 86% of a docs PR is churn, and 16 of 256 are already stale #66

Closed

Description

@os-zhuang

Problem

AGENTS.md rule #1 already says English is the single source of truth and every locale is derived. Nothing enforced it and nothing measured it, and both halves of that gap are now measurable:

Cost. The last two content PRs spent 86% of their diff on hand-maintained locale siblings — #63 changed 63 files, 54 of them translations; #62 changed 28, 24 of them translations. Every English edit obligates its author to also produce six translations, so the marginal cost of a one-line English fix is six file edits in languages the author may not read.

Undetectable drift. 256 translations are checked in with no record of which English revision they were derived from. Walking git history (for each translation, did its English sibling change after the translation's last commit?) finds 16 already stale, across three English pages:

  • content/docs/configure/authentication.* — 5 locales
  • content/docs/index.* — 5 locales
  • content/docs/resources/faq.* — 6 locales

Nothing reports this today, and nothing can: with no recorded provenance, a translation that no longer matches its source is indistinguishable from one that does.

This matters more than a missing translation. Fumadocs falls back to English when a locale sibling is absent, so a missing translation renders correct English. A stale one renders content the English source no longer claims — on a customer-facing site, on pages including resources/license and reference/security.

Coverage for reference (English pages without a sibling): zh-Hans 17, ja 40, de 41, es 40, fr 40, ko 40.

Required outcome

Translations become a generated artifact with machine-checkable provenance, and the split "humans write English, the translation pass writes translations" becomes a CI rule rather than a convention:

  1. Every translation records the sha256 of the English sibling it was derived from, so staleness is detectable.
  2. A gate that blocks on unaccounted-for translations (no provenance, or English source deleted) but not on staleness — an English edit landing alone is the design, not an oversight. Forcing the English author to also produce six translations is the cost this removes.
  3. A worklist a periodic translation pass can consume, so "translate the stale ones" is a bounded task rather than a full retranslation.
  4. Ownership enforced by PR author, so neither half of the split can erode.
  5. A written contract for the translation pass: what is never translated, the glossary, and the pre-PR checks.

Constraints: no locale is dropped (all six stay); the checks must run with no dependencies, no network and no credentials, so they work on fork PRs and add no secret to this public repository.

Process note

This issue is filed after the work — PR #65 already implements it. That is a deviation from claim-before-work and it is recorded here rather than papered over. The PR is linked below and the claim comment follows.

Activity

  1. self-assigned this
    on Aug 18, 2026
  2. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 1 (retroactive — recorded after the work, see deviations below)
    Session: session_01CJPxtTxoxTUnjNdTbiEaRa
    Branch: claude/objectos-docs-content-strategy-w8fcm0
    Worktree: none — worked in the primary checkout
    Domain: n/a — objectos is not in the pm-dispatch lane model (it covers objectstack / objectui / cloud); no pm:* labels exist in this repository and no seat owns it. Filed as a decision for the maintainer.
    File surface: .github/scripts/, .github/workflows/, content/docs/**/*.<locale>.mdx (frontmatter only), docs/TRANSLATION.md, AGENTS.md, CONTRIBUTING.md
    Container & model: M, in-session (not dispatched to an os-dev agent)
    Clause-②: no — no contract surface touched; packages/spec is in a different repository and this changes no accept/reject behaviour and widens no public API.
    Serial constraints cleared: none — no other in-flight claim in this repository (open issues are #61 and #64, both unassigned finding cards, neither touching content/docs frontmatter or .github/).

    Recorded deviations

    Three, stated rather than smoothed over:

    1. No issue before the work. The change was implemented and pushed as docs: make translations a generated artifact with a freshness gate #65 before this card existed. Claim-before-work is the rule; it was not followed.
    2. Not dispatched to an os-dev agent. The PM seat does not write code. This was written in-session.
    3. Branch does not follow claude/issue-<n>-<slug>. It predates the issue number, so it cannot.

    Deviations 1 and 2 are mine. Deviation 3 follows from 1. None of them are corrected by renaming things after the fact — the record is the correction.

    Verification carried out before this card existed

    • pnpm turbo run build and apps/docs type-check both pass (335 MDX files; the added frontmatter key is accepted — Fumadocs' pageSchema strips unknown keys).
    • The gate's stale count is derived independently of the ad-hoc history walk that first found it, and reproduces the same 16 files.
    • --baseline is idempotent (a second run stamps 0 files).
    • The ownership check was exercised across all four branches: variable unset, human/English-only, human/translation (fails), bot/artifacts-only, bot/English (fails).
    • CI on docs: make translations a generated artifact with a freshness gate #65: Ownership & freshness passed on the real runner, with output matching the local run.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions