Repository navigation
Docs legal pages: /de, /ja, /es, /fr and /ko privacy and terms show English text without lang="en", and zh-Hant shows English instead of text derived from zh-Hans #312
Description
Activity
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsClaim: PM loop,
repo:objectosseat
Session:session_01FeA1nwBz1ohH65dvffUGKr
Account: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. This card builds on #305'sgen-zh-hant.mjschanges, so it is staged on #305's rebased local branchstaged/issue-305(4da46c5, base5d2f837). At push time only its own commits are replayed.
Worktree:objectos-issue-312
Domain: n/a (single-lane repo)
Seat:repo:objectos(objectstack-ai/objectstack#9831)
File surface:apps/docs/app/[lang]/{privacy,terms}/page.tsx;apps/docs/scripts/gen-zh-hant.mjs, plus any generated zh-Hant legal copy it writes;apps/docs/lib/ui-text*, for the fallback notice;- one case in
.github/scripts/check-locale-surface.mjs, coordinated with Docs accessibility baseline: no main landmark, the language switcher's name contradicts its text, an unnamed svg role=img, unnamed code regions — on every page in every locale #308.
No legal wording changes in en or zh-Hans.
Stop on breach and explain in the report.
Container & model: S,mode:subagent,model: default.
Clause-②: no
Thread-read: none
Serial constraints cleared: no. Pushes are serial on the one branch: #311 → #305 → #307 → #308 → this card.
Generated by Claude Code
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 312, "status": "staged", "branch": "staged/issue-312", "worktree": "/home/user/objectos-issue-312", "base": "4da46c5319f61856917e0266836ac4ff4ea7911f (staged/issue-305, itself on main 5d2f837)", "final_commit": "297882f1905dc2c7a4c69e02d930fe392c15e05b", "pushed": false, "pr": null, "pr_body": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/pr-body.md (first line: Fixes #312)", "session": "session_01FeA1nwBz1ohH65dvffUGKr (subagent; the parent seat session, per the Claim)", "premise_still_valid": true, "summary": "Premise confirmed on a fresh --force build of 4da46c5: de/ja/es/fr/ko legal pages showed 11 (privacy) / 13 (terms) English text nodes resolving to the route locale, with no lang=en and no notice, and zh-Hant showed the same English. Fix, one commit on staged/issue-312, not pushed. (1) app/[lang]/{privacy,terms}/page.tsx: a locale missing from content gets the English entry with lang=en on title, date, body and back link, introduced by the #298 notice (ui-text notTranslated, Callout role=note data-untranslated-notice) in the route locale. en and zh-Hans render as before; their HTML changes only by one new hrefLang=zh-Hant alternate. (2) The zh-Hans entry moved verbatim into zh-Hans.json beside each page, and gen-zh-hant (FIXED_PAIRS: ui-text, privacy, terms) writes zh-Hant.json, so zh-Hant is Traditional text derived from zh-Hans, covered by gen-zh-hant --check, and advertised through contentLocales (hreflang, canonical, sitemap). (3) check-locale-surface: STATIC_PAGES lists zh-Hant, and 3 rules over the built legal pages (legal-english-unmarked, legal-translation-shows-english, legal-page-unread) with 5 self-test cases. Red on the base build (14 findings), green on this branch. No legal wording changed in en or zh-Hans (proved, see checks). No machine translation into de/ja/es/fr/ko.", "files": [ "apps/docs/app/[lang]/privacy/page.tsx (fallback: lang=en on the English entry plus the #298 notice; zh-Hans and zh-Hant entries imported from JSON; en entry byte-identical)", "apps/docs/app/[lang]/terms/page.tsx (same)", "apps/docs/app/[lang]/privacy/zh-Hans.json (new: the zh-Hans entry, moved verbatim from page.tsx)", "apps/docs/app/[lang]/terms/zh-Hans.json (new: same)", "apps/docs/app/[lang]/privacy/zh-Hant.json (new, GENERATED by gen-zh-hant)", "apps/docs/app/[lang]/terms/zh-Hant.json (new, GENERATED by gen-zh-hant)", "apps/docs/scripts/gen-zh-hant.mjs (one ui-text pair becomes FIXED_PAIRS: ui-text, privacy, terms; header and drift message updated)", ".github/scripts/check-locale-surface.mjs (STATIC_PAGES + zh-Hant; legal block after expectedSitemapUrls; 3 rules; bodies.legal read; legal table in the summary; legalFixturePages + 5 CASES + fixture writer in selfTest)" ], "checks": { "no_wording_change": "scratchpad/issue-312/prove-copy.mjs: for privacy and terms, en block bytes equal HEAD~ (the check-positioning rule-c regex block), en deep-equal, zh-Hans.json deep-equal the 4da46c5 page.tsx zh-Hans entry: PROOF OK", "zh_hant_derivation": "per-string OpenCC s2twp(zh-Hans) == zh-Hant.json for every string (privacy 10 of 12 strings differ from Simplified, terms 13 of 14); gen-zh-hant --check 62 files (was 60)", "built_html_js_off": "scratchpad/issue-312/legal-check.mjs, Chromium parses each built page, DOM closest('[lang]') per text node of the page's own main: 16 of 16 pass. de/ja/es/fr/ko: html lang = route locale, 4 lang=en elements, every English text node resolves to en, notice visible and equal to ui-text notTranslated and resolving to the route locale. zh-Hant: text == zh-Hant.json, no English-entry text, no lang=en, canonical https://docs.objectos.ai/zh-Hant/LEGALPATH. hreflang on every page exactly en, zh-Hans, zh-Hant, x-default; fallback canonical = the English URL. Base 4da46c5: 16 of 16 fail (no notice, 11/13 nodes not lang=en, hreflang without zh-Hant, zh-Hant canonical the English URL)", "live_js_on": "same checks against next start of this build, hydrated, at 1440 and 390: 32 of 32 pass, 0 console errors; server process group stopped, 0 processes left", "html_vs_base": "en/privacy, en/terms, zh-Hans/privacy: 1 changed line each outside scripts and asset hashes (the new hrefLang=zh-Hant link); zh-Hans/terms the same plus one script-tag split; docs pages en/docs/operate/backup and de/docs/build/data identical", "ci_case_red_then_green": "committed gate (297882f) run against a fresh --force build of 4da46c5: exit 1, 14 findings = legal-english-unmarked x10 (ja/de/es/fr/ko x privacy/terms, e.g. 11 of the 11 English text node(s) de shows for privacy resolve to lang=de), legal-translation-shows-english x2 (zh-Hant x2), missing-url x2 (zh-Hant legal URLs). Same gate on this branch's build: exit 0, legal table wrong=0 on all 14 non-English pages, sitemap 301/301", "reverse_verification": "tsc: renaming back to backLink in privacy/zh-Hans.json (ablation-replace, committed HEAD) → tsc exit 2, TS2339 Property back does not exist on the content union; restored blob 983f34dec0cc == HEAD, git diff HEAD empty. The first attempt was a no-op (ablation-replace refused: the replacement text was not unique) and is not counted", "gate_ablation": "removing the header/nav skip from the legal reader → self-test red: clean baseline fires legal-english-unmarked + legal-translation-shows-english (brand text in the HomeLayout header inside the outer main); restored blob 9183f0ddcd6e == HEAD" }, "gates": [ "every line at HEAD 297882f", "pnpm install --frozen-lockfile: exit 0", "pnpm turbo run type-check --continue --force: Tasks 1 successful; os-verify-lock VERDICT command-exit 0 (run again after the tsc reverse check: VERDICT command-exit 0)", "NEXT_PRIVATE_STANDALONE=true pnpm turbo run build --force: Generating static pages using 3 workers (1038/1038), Tasks 1 successful; VERDICT command-exit 0 (332 OG font-fetch proxy warnings, same count on the base build)", "pnpm turbo run test --force: ✓ 10 self-test(s) passed; VERDICT command-exit 0", "check-locale-surface: exit 0, ✓ every advertised URL has a source file and every source file is advertised; ... (legal table: 14 pages, wrong 0)", "check-locale-surface --self-test: ✓ self-test: 36 case(s) over 18 rule(s) and 3 artifact(s) (was 31 over 15)", "check-positioning: ✓ 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", "check-search-locales: ✓ 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 nonce", "gen-zh-hant --check: ✓ zh-Hant: 62 generated file(s) match the zh-Hans sources byte for byte.", "Ownership, workflow argv (git diff --name-status --no-renames origin/main...HEAD; origin/main now 92a12d2, merge-base 5d2f837; 23 files = #305's 15 + this card's 8), actor hotlong: bot login unset exit 0 (This PR touches 0 translation artifact(s) and 23 other file(s)); armed: ✓ 23 file(s) changed, no translation artifacts touched (exit 0); CONTROL actor = bot login: ✗ translation PRs may only touch translation artifacts (exit 1, expected); this commit alone (4da46c5...HEAD): ✓ 8 file(s) changed, no translation artifacts touched", "Freshness: ✓ translations gate passed; Output --self-test: ✓ self-test: 29 rule case(s), 9 split case(s) and 5 derived-locale case(s) ...; Output --files: ✓ translation output gate passed (256 pre-existing finding(s) reported)", "check-node-floor: ✅ exit 0; --self-test ✓ exit 0; check-half-states --self-test: ✓ 1551 cases pass", "NOT MEASURED: Worker package, size budget and local-preview smoke (CI build-job steps after test), reason: not in this card's gate list; left to CI", "control-byte scan of the 8 changed files: none" ], "replay_with_308": { "hunks": "check-locale-surface.mjs hunks sit away from #308's: RULES after duplicate-url (not the tail), legal block after expectedSitemapUrls, legal read as bodies.legal (collect's return line and evaluate's signature untouched), legal findings pushed after the dotted-slug loop, legal table before the llms section, fixture after BASE_URLS, CASES after duplicated entries, fixture writer before the llms.mdx block. Every helper is prefixed legal, so nothing collides with #308's reader names (readHtml, primaryLanguage, squash, once, ...)", "measured": "git cherry-pick --no-commit 297882f onto staged/issue-308 (40fe51c) in a throwaway detached worktree: applied, no conflict (also git merge-file of the gate alone: 0 conflicts)", "one_line_fixup": "the merged self-test fails exactly one case, #308's docs pages not built (fired docs-page-html-missing no-chrome-names no-tree-entries, expected artifact-missing), because the legal fixtures share #308's build directory. Add legal: null to that case; merged self-test then: ✓ self-test: 46 case(s) over 24 rule(s) and 3 artifact(s). Diff: scratchpad/issue-312/replay/fixup-on-308.diff", "not_measured": "the merged gate against a real build of #308 + #312 (needs that tree built); #308's english-chrome-name rule also reads de/privacy.html, whose notice adds no accessible name (the Callout icon is aria-hidden)" }, "tests": "No unit-test surface in apps/docs. Evidence: the gates above, the built-HTML and live DOM checks (scratchpad/issue-312/legal-check.mjs, results in legal-check-before.json, legal-check-after-built.json, legal-check-after.json), the gate red/green logs (gate-before.log, gate-after.log), the tsc reverse verification and the gate ablation (reverse-tsc.log, ablation-chrome.log).", "screenshots": [ "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/de-privacy-1440.png (German notice above the English policy; header Suchen)", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/de-privacy-390.png", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/zh-Hant-terms-1440.png (服務條款, 許可, 託管服務, 條款變更, 聯絡方式, 返回首頁; header 搜尋; no notice)", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/zh-Hant-terms-390.png" ], "deviations": [ "The dispatch says #305 extended gen-zh-hant.mjs for the 404 copy. On 4da46c5 it did not: git diff 5d2f837 4da46c5 has no gen-zh-hant.mjs change, because #305 moved the 404 copy into lib/ui-text, which the generator already converted. This card generalizes that one ui-text pair into FIXED_PAIRS instead.", "Files beyond the Claim's literal list: the zh-Hans.json beside each page. It is the Simplified source the generator needs, moved verbatim from page.tsx (deep-equal proof in checks). It sits in the claimed route directories. No ui-text key was added: the notice reuses notTranslated.", "First base build attempt discarded: I edited page.tsx in this worktree while it built (TS2307 ./zh-Hant.json, exit 1). The baseline was rebuilt in a separate detached worktree at 4da46c5. That worktree was removed afterwards with a plain git worktree remove, after git status read empty.", "The replay check used a second throwaway detached worktree on staged/issue-308. It was removed with git worktree remove --force; its only uncommitted content was my own cherry-pick plus the one-line fixup, both kept (commit 297882f, replay/fixup-on-308.diff). The staged/issue-308 branch was not moved.", "The gate hunk is +287 lines on an S card: a self-contained reader, 3 rules, a fixture and 5 cases. It is kept separate from #308's reader on purpose. The two readers can be unified after the replay.", "The gate's final summary sentence was left unchanged, to keep the replay free of conflicts. The legal result prints in its own table.", "Commit trailers are model-free (Co-Authored-By: Claude), per the agent contract. The harness reminder asked for a model name.", "Moved during this run, not by me: origin/main moved 5d2f837 → 92a12d2 (#313, apps/docs/package.json only; git merge-tree origin/main HEAD is clean), and staged/issue-308 moved 295d79c → 40fe51c." ], "mcp_calls": "0", "api_writes": "1 -- POST /repos/objectstack-ai/objectos/issues/312/comments (this os-dev-report, via objectstack scripts/pm/post-stamped.mjs). Reads only otherwise (gh api GET issues 312, 305, 308 and their comments). No push, no PR, no label.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: public door, built /privacy and /terms in all 8 locales, en included: document.querySelectorAll('main').length === 2, because HomeLayout renders main#nd-home-layout around the header and the page renders its own main inside it (same on base 4da46c5) · same family as #308's landmark work (axe landmark rules); fold it into that family rather than a single card · dedupe words: nested main, nd-home-layout, landmark-no-duplicate-main, landmark-main-is-top-level, privacy, terms", "carrier: none · noted, not filed: s2twp renders 账号 as 賬號 in the zh-Hant privacy copy (Taiwan usage prefers 帳號); this is generated output and comes from the converter's vocabulary, the same kind as #305's 複製文本 note", "carrier: none · noted, not filed: check-locale-surface's missing-url text says has a source file in the content tree for STATIC_PAGES URLs too, which are declared rather than read from the content tree" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 312, "status": "staged", "supersedes": "https://github.com/objectstack-ai/objectos/issues/312#issuecomment-6020217734 (the first os-dev-report; this one adds the coordinator's landmark fix, axe, and the rebase check)", "branch": "staged/issue-312", "worktree": "/home/user/objectos-issue-312", "base": "4da46c5319f61856917e0266836ac4ff4ea7911f (staged/issue-305, itself on main 5d2f837)", "final_commit": "85b6b4b (two commits: 297882f lang=en + notice + zh-Hant + gate; 85b6b4b article instead of a nested main)", "pushed": false, "pr": null, "pr_body": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/pr-body.md (first line: Fixes #312)", "session": "session_01FeA1nwBz1ohH65dvffUGKr (subagent; the parent seat session, per the Claim)", "premise_still_valid": true, "summary": "Premise confirmed on a fresh --force build of 4da46c5: de/ja/es/fr/ko legal pages showed 11 (privacy) / 13 (terms) English text nodes resolving to the route locale, with no lang=en and no notice, and zh-Hant showed the same English. Fix, two commits on staged/issue-312, not pushed. (1) app/[lang]/{privacy,terms}/page.tsx: a locale missing from content gets the English entry with lang=en on title, date, body and back link, introduced by the #298 notice (ui-text notTranslated, Callout role=note data-untranslated-notice) in the route locale. en and zh-Hans render as before; their HTML changes only by one new hrefLang=zh-Hant alternate. (2) The zh-Hans entry moved verbatim into zh-Hans.json beside each page, and gen-zh-hant (FIXED_PAIRS: ui-text, privacy, terms) writes zh-Hant.json, so zh-Hant is Traditional text derived from zh-Hans, covered by gen-zh-hant --check, and advertised through contentLocales (hreflang, canonical, sitemap). (3) check-locale-surface: STATIC_PAGES lists zh-Hant, and 3 rules over the built legal pages (legal-english-unmarked, legal-translation-shows-english, legal-page-unread) with 5 self-test cases. Red on the base build (14 findings), green on this branch. No legal wording changed in en or zh-Hans (proved, see checks). No machine translation into de/ja/es/fr/ko. (4) Coordinator addition (from #308's axe run): the page's own wrapper is now an article, not a second main nested inside HomeLayout's main#nd-home-layout. It keeps the same classes. axe 4.14.0 on /privacy and /terms in en, de and zh-Hant (1440 light and dark, 390 light, 18 runs): landmark-no-duplicate-main, landmark-main-is-top-level and landmark-unique go from 18 nodes each to 0, and no new rule appears. The /de/privacy screenshots before and after, at 1440 and 390, are byte-identical PNGs.", "files": [ "apps/docs/app/[lang]/privacy/page.tsx (fallback: lang=en on the English entry plus the #298 notice; zh-Hans and zh-Hant entries imported from JSON; en entry byte-identical; wrapper main → article)", "apps/docs/app/[lang]/terms/page.tsx (same)", "apps/docs/app/[lang]/privacy/zh-Hans.json (new: the zh-Hans entry, moved verbatim from page.tsx)", "apps/docs/app/[lang]/terms/zh-Hans.json (new: same)", "apps/docs/app/[lang]/privacy/zh-Hant.json (new, GENERATED by gen-zh-hant)", "apps/docs/app/[lang]/terms/zh-Hant.json (new, GENERATED by gen-zh-hant)", "apps/docs/scripts/gen-zh-hant.mjs (one ui-text pair becomes FIXED_PAIRS: ui-text, privacy, terms; header and drift message updated)", ".github/scripts/check-locale-surface.mjs (STATIC_PAGES + zh-Hant; legal block after expectedSitemapUrls; 3 rules; bodies.legal read; legal table in the summary; legalFixturePages, which mirrors HomeLayout main + header + the page article, + 5 CASES + fixture writer in selfTest)" ], "checks": { "no_wording_change": "scratchpad/issue-312/prove-copy.mjs: for privacy and terms, en block bytes equal 4da46c5 (the check-positioning rule-c regex block), en deep-equal, zh-Hans.json deep-equal the 4da46c5 page.tsx zh-Hans entry: PROOF OK", "zh_hant_derivation": "per-string OpenCC s2twp(zh-Hans) == zh-Hant.json for every string (privacy 10 of 12 strings differ from Simplified, terms 13 of 14); gen-zh-hant --check 62 files (was 60)", "built_html_js_off": "scratchpad/issue-312/legal-check.mjs, Chromium parses each built page, DOM closest('[lang]') per text node of the page's own main: 16 of 16 pass on the 297882f build and again on the c3ad871 build. de/ja/es/fr/ko: html lang = route locale, 4 lang=en elements, every English text node resolves to en, notice visible and equal to ui-text notTranslated and resolving to the route locale. zh-Hant: text == zh-Hant.json, no English-entry text, no lang=en, canonical https://docs.objectos.ai/zh-Hant/LEGALPATH. hreflang on every page exactly en, zh-Hans, zh-Hant, x-default; fallback canonical = the English URL. Base 4da46c5: 16 of 16 fail (no notice, 11/13 nodes not lang=en, hreflang without zh-Hant, zh-Hant canonical the English URL)", "live_js_on": "same checks against next start, hydrated, at 1440 and 390: 32 of 32 on each build (297882f, c3ad871), 0 console errors; the server process group was stopped after each run, 0 processes left", "html_vs_base": "en/privacy, en/terms, zh-Hans/privacy: 1 changed line each outside scripts and asset hashes (the new hrefLang=zh-Hant link); zh-Hans/terms the same plus one script-tag split; docs pages en/docs/operate/backup and de/docs/build/data identical", "ci_case_red_then_green": "committed gate (297882f) run against a fresh --force build of 4da46c5: exit 1, 14 findings = legal-english-unmarked x10 (ja/de/es/fr/ko x privacy/terms, e.g. 11 of the 11 English text node(s) de shows for privacy resolve to lang=de), legal-translation-shows-english x2 (zh-Hant x2), missing-url x2 (zh-Hant legal URLs). Same gate on this branch's build: exit 0, legal table wrong=0 on all 14 non-English pages, sitemap 301/301. Commit 85b6b4b changes only the gate fixture and comments (the rule code is unchanged), and the gate is exit 0 on the c3ad871 build at 85b6b4b", "reverse_verification": "(at 297882f) tsc: renaming back to backLink in privacy/zh-Hans.json (ablation-replace, committed HEAD) → tsc exit 2, TS2339 Property back does not exist on the content union; restored blob 983f34dec0cc == HEAD, git diff HEAD empty. The first attempt was a no-op (ablation-replace refused: the replacement text was not unique) and is not counted", "gate_ablation": "(at 297882f; the reader code is unchanged in 85b6b4b) removing the header/nav skip from the legal reader → self-test red: clean baseline fires legal-english-unmarked + legal-translation-shows-english (brand text in the HomeLayout header inside the outer main); restored blob 9183f0ddcd6e == HEAD", "axe_landmarks": "axe 4.14.0 (scratchpad/issue-312/axe-legal.mjs, vendor/axe.min.js) on /privacy and /terms x en, de, zh-Hant x {1440 light, 1440 dark, 390 light}, 18 runs each side. Before (297882f build): landmark-no-duplicate-main 18, landmark-main-is-top-level 18, landmark-unique 18, svg-img-alt 12. After (c3ad871 build): svg-img-alt 12 only (the header GitHub icon, which #308 handles). New rules after: none. main elements per page: 2 → 1", "screenshots_unchanged": "/de/privacy, light, full page: shots-before/de-privacy-1440.png == shots-after/de-privacy-1440.png (sha256 ed1644f3e921...), shots-before/de-privacy-390.png == shots-after/de-privacy-390.png (sha256 9f32ffbe995e...); byte-identical PNGs, and both were looked at", "rebase_onto_main": "origin/main = cf449fa (#305 as #314, over 92a12d2 #313). git diff 4da46c5 cf449fa touches only apps/docs/package.json (#313). git merge-tree --write-tree --merge-base 4da46c5 origin/main HEAD: exit 0. git merge-tree --write-tree origin/main HEAD: exit 0. So rebase --onto origin/main 4da46c5 should be trivial; not performed" }, "gates": [ "type-check, build and the post-build gates at c3ad871. 85b6b4b = c3ad871 plus a comment reflow in check-locale-surface.mjs (git diff --stat: that 1 file, +3/-2), so the app tree is identical. turbo test, check-locale-surface and its self-test were rerun at 85b6b4b: exit 0. The first round of the same gates at 297882f was also green", "pnpm install --frozen-lockfile: exit 0", "pnpm turbo run type-check --continue --force: Tasks 1 successful; os-verify-lock VERDICT command-exit 0", "NEXT_PRIVATE_STANDALONE=true pnpm turbo run build --force: Generating static pages using 3 workers (1038/1038), Tasks 1 successful; VERDICT command-exit 0 (332 OG font-fetch proxy warnings, the same count on the base build)", "pnpm turbo run test --force: ✓ 10 self-test(s) passed; VERDICT command-exit 0 (at c3ad871 and at 85b6b4b)", "check-locale-surface: exit 0, ✓ every advertised URL has a source file and every source file is advertised; ... (legal table: 14 pages, wrong 0)", "check-locale-surface --self-test: ✓ self-test: 36 case(s) over 18 rule(s) and 3 artifact(s) (was 31 over 15)", "check-positioning: ✓ 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", "check-search-locales: ✓ 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 nonce", "gen-zh-hant --check: ✓ zh-Hant: 62 generated file(s) match the zh-Hans sources byte for byte.", "Ownership, workflow argv (git diff --name-status --no-renames origin/main...HEAD; origin/main now cf449fa, merge-base still 5d2f837; 23 files = #305's 15 + this card's 8), actor hotlong: bot login unset exit 0 (This PR touches 0 translation artifact(s) and 23 other file(s)); armed: ✓ 23 file(s) changed, no translation artifacts touched (exit 0); CONTROL actor = bot login: ✗ translation PRs may only touch translation artifacts (exit 1, expected); this card's commits alone (4da46c5...HEAD, what the list becomes after the rebase): ✓ 8 file(s) changed, no translation artifacts touched", "Freshness: ✓ translations gate passed; Output --self-test: ✓ self-test: 29 rule case(s), 9 split case(s) and 5 derived-locale case(s) ...; Output --files: ✓ translation output gate passed (256 pre-existing finding(s) reported)", "check-node-floor: ✅ exit 0; --self-test ✓ exit 0; check-half-states --self-test: ✓ 1551 cases pass", "NOT MEASURED: Worker package, size budget and local-preview smoke (CI build-job steps after test), reason: not in this card's gate list; left to CI", "control-byte scan of the 8 changed files: none" ], "replay_with_308": { "hunks": "check-locale-surface.mjs hunks sit away from #308's: RULES after duplicate-url (not the tail), legal block after expectedSitemapUrls, legal read as bodies.legal (collect's return line and evaluate's signature untouched), legal findings pushed after the dotted-slug loop, legal table before the llms section, fixture after BASE_URLS, CASES after duplicated entries, fixture writer before the llms.mdx block. Every helper is prefixed legal, so nothing collides with #308's reader names (readHtml, primaryLanguage, squash, once, ...)", "measured": "git cherry-pick --no-commit 297882f 85b6b4b onto staged/issue-308 (3159847; the first commit was also tried on 40fe51c) in a throwaway detached worktree: applied, no conflict", "one_line_fixup": "the merged self-test fails exactly one case, #308's docs pages not built (fired docs-page-html-missing no-chrome-names no-tree-entries, expected artifact-missing), because the legal fixtures share #308's build directory. Add legal: null to that case; merged self-test then (both commits on 3159847): ✓ self-test: 46 case(s) over 24 rule(s) and 3 artifact(s). Diff: scratchpad/issue-312/replay/fixup-on-308.diff", "not_measured": "the merged gate against a real build of #308 + #312 (needs that tree built); #308's english-chrome-name rule also reads de/privacy.html, whose notice adds no accessible name (the Callout icon is aria-hidden)" }, "tests": "No unit-test surface in apps/docs. Evidence: the gates above, the built-HTML and live DOM checks (scratchpad/issue-312/legal-check.mjs, results in legal-check-before.json, legal-check-after-built.json, legal-check-after.json), the gate red/green logs (gate-before.log, gate-after.log), the tsc reverse verification and the gate ablation (reverse-tsc.log, ablation-chrome.log). axe: axe-before.json / axe-after.json; screenshots before/after: shots-before/, shots-after/.", "screenshots": [ "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/de-privacy-1440.png (German notice above the English policy; header Suchen) (retaken on the c3ad871 build)", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/de-privacy-390.png", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/zh-Hant-terms-1440.png (服務條款, 許可, 託管服務, 條款變更, 聯絡方式, 返回首頁; header 搜尋; no notice)", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots/zh-Hant-terms-390.png", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots-before/de-privacy-1440.png and shots-before/de-privacy-390.png (297882f, nested main)", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots-after/de-privacy-1440.png and shots-after/de-privacy-390.png (c3ad871, article; byte-identical to before)" ], "deviations": [ "The dispatch says #305 extended gen-zh-hant.mjs for the 404 copy. On 4da46c5 it did not: git diff 5d2f837 4da46c5 has no gen-zh-hant.mjs change, because #305 moved the 404 copy into lib/ui-text, which the generator already converted. This card generalizes that one ui-text pair into FIXED_PAIRS instead.", "Files beyond the Claim's literal list: the zh-Hans.json beside each page. It is the Simplified source the generator needs, moved verbatim from page.tsx (deep-equal proof in checks). It sits in the claimed route directories. No ui-text key was added: the notice reuses notTranslated.", "First base build attempt discarded: I edited page.tsx in this worktree while it built (TS2307 ./zh-Hant.json, exit 1). The baseline was rebuilt in a separate detached worktree at 4da46c5. That worktree was removed afterwards with a plain git worktree remove, after git status read empty.", "The replay check used a second throwaway detached worktree on staged/issue-308. It was removed with git worktree remove --force; its only uncommitted content was my own cherry-pick plus the one-line fixup, both kept (commit 297882f, replay/fixup-on-308.diff). The staged/issue-308 branch was not moved.", "The gate hunk is +287 lines on an S card: a self-contained reader, 3 rules, a fixture and 5 cases. It is kept separate from #308's reader on purpose. The two readers can be unified after the replay.", "The gate's final summary sentence was left unchanged, to keep the replay free of conflicts. The legal result prints in its own table.", "Commit trailers are model-free (Co-Authored-By: Claude), per the agent contract. The harness reminder asked for a model name.", "Moved during this run, not by me: origin/main moved 5d2f837 → 92a12d2 (#313) → cf449fa (#305 landed), and staged/issue-308 moved 295d79c → 40fe51c → 3159847.", "The landmark fix is a second commit, not folded into the first, so it can be reviewed and replayed apart. The second commit was amended once, locally, for a comment reflow (c3ad871 → 85b6b4b); nothing was pushed.", "The first report (comment 6020217734) listed the nested main as an out-of-scope finding. The coordinator then ruled it in scope, so it is fixed here and dropped from out_of_scope_findings." ], "mcp_calls": "0", "api_writes": "2 -- POST /repos/objectstack-ai/objectos/issues/312/comments ×2 (the first os-dev-report, comment 6020217734, and this final one), both through objectstack scripts/pm/post-stamped.mjs and the fleet-write relay. Reads only otherwise. No push, no PR, no label.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: s2twp renders 账号 as 賬號 in the zh-Hant privacy copy (Taiwan usage prefers 帳號); this is generated output and comes from the converter's vocabulary, the same kind as #305's 複製文本 note", "carrier: none · noted, not filed: check-locale-surface's missing-url text says has a source file in the content tree for STATIC_PAGES URLs too, which are declared rather than read from the content tree" ] }
Generated by Claude Code
- added a commit that references this issue
on Oct 6, 2026 objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsos-dev-report-addendum
{ "issue": 312, "status": "staged", "addendum_to": "https://github.com/objectstack-ai/objectos/issues/312#issuecomment-6020507178", "branch": "staged/issue-312", "worktree": "/home/user/objectos-issue-312", "tip": "e6bf7467d7c8ffd84e424fa0c41ec0ec12d270cc", "commits": [ "39b76e1 docs: legal pages mark their English fallback lang=\"en\" with the notice; zh-Hant generated from zh-Hans", "e6bf746 docs: legal pages render an article inside HomeLayout's main, not a second main" ], "base": "9d3ff08 (main: #317 = #308, over 553ef7b #315 = #307, over cf449fa #314 = #305)", "previous_tip": "85b6b4b on 4da46c5 (commits 297882f, 85b6b4b)", "pushed": false, "pr": null, "pr_body": "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/pr-body.md (first line Fixes #312; new sections: Branch and rebase, Verification on the rebased tip)", "session": "session_01FeA1nwBz1ohH65dvffUGKr", "rebase": "git fetch -q origin main && git rebase --onto origin/main 4da46c5 staged/issue-312: Successfully rebased, NO conflicts. git range-diff 4da46c5..85b6b4b origin/main..HEAD: commit 1 (297882f → 39b76e1) differs only in diff context around collect's return line and evaluate's signature, both of which #308 changed; commit 2 (85b6b4b → e6bf746) is patch-identical (=).", "resolutions": [ "None needed. Git applied every check-locale-surface.mjs hunk cleanly on top of #308's rule. The merged file keeps both cards' work: #308's english-chrome-name, page-tree rules, readHtml reader and live control; this card's three legal rules, legalMainText reader, legalFixturePages and 5 cases.", "The legal: null fixup is NOT needed and was NOT applied. #308's 42da2b1 (the built-pages guard counts docs pages only) already covers it: the merged self-test passes as-is, with docs pages not built firing [artifact-missing] and legal pages not built firing [artifact-missing]." ], "gates": [ "every line at HEAD e6bf746, against a real --force build of it", "pnpm install --frozen-lockfile: exit 0 (Lockfile is up to date)", "pnpm turbo run type-check --continue --force: Tasks 1 successful; os-verify-lock VERDICT command-exit 0", "NEXT_PRIVATE_STANDALONE=true pnpm turbo run build --force: Generating static pages using 3 workers (1038/1038), Tasks 1 successful; VERDICT command-exit 0 (332 OG font-fetch proxy warnings, same count as every earlier build)", "pnpm turbo run test --force: ✓ 10 self-test(s) passed; VERDICT command-exit 0", "check-locale-surface: exit 0, ✓ every advertised URL has a source file and every source file is advertised; ... Legal table: wrong 0 on all 14 non-English pages (fallbacks 12/14 text nodes, of them 11/13 English, all lang=en). #308's built-pages table: 82 pages read per locale; English chrome names 0, unmarked untranslated entries 0, translated entries marked English 0 in all 7 locales; live control fired. sitemap 301/301", "check-locale-surface --self-test: ✓ self-test: 48 case(s) over 25 rule(s) and 3 artifact(s) (before the rebase: 36 over 18)", "check-positioning: ✓ 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", "check-search-locales: ✓ 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 nonce", "gen-zh-hant --check: ✓ zh-Hant: 62 generated file(s) match the zh-Hans sources byte for byte.", "Ownership, workflow argv (git diff --name-status --no-renames origin/main...HEAD; merge-base 9d3ff08, so 8 files = this card only), actor hotlong: bot login unset exit 0 (This PR touches 0 translation artifact(s) and 8 other file(s)); armed: ✓ 8 file(s) changed, no translation artifacts touched (exit 0); CONTROL actor = bot login: ✗ translation PRs may only touch translation artifacts (exit 1, expected)", "Freshness: ✓ translations gate passed; Output --self-test ✓; Output --files: ✓ translation output gate passed (256 pre-existing finding(s) reported)", "check-node-floor + --self-test: ✅/✓ exit 0; check-half-states --self-test: ✓ 1551 cases pass", "control-byte scan of the 8 changed files: none", "NOT MEASURED: Worker package, size budget and local-preview smoke, reason: not in this card's gate list; left to CI" ], "checks": { "no_wording_change": "prove-copy.mjs against origin/main 9d3ff08: en block bytes equal, en deep-equal, zh-Hans.json deep-equal the main page.tsx zh-Hans entry, for privacy and terms: PROOF OK", "built_html_js_off": "legal-check.mjs (Chromium DOM, JS off) over the rebased build: 16 of 16 pass (lang=en on the fallback English entry, notice in the route locale, zh-Hant == zh-Hant.json, hreflang en/zh-Hans/zh-Hant/x-default, canonical as before)", "live_js_on": "next start of the rebased build, hydrated, 1440 and 390: 32 of 32 pass, 0 console errors; server process group stopped, 0 processes left", "axe": "axe 4.14.0 on /privacy and /terms x en, de, zh-Hant x {1440 light, 1440 dark, 390 light}, 18 runs: 0 violations of any rule. landmark-no-duplicate-main 0, landmark-main-is-top-level 0, landmark-unique 0 (1 main per page). svg-img-alt is now 0 too, down from 12 before the rebase: #308's patch makes the header GitHub icon aria-hidden, and the built /de/privacy has 0 svg role=img", "screenshots": "retaken on the rebased build and looked at; the /de/privacy PNGs are byte-identical to the pre-rebase ones (sha256 ed1644f3e921... at 1440, 9f32ffbe995e... at 390)" }, "screenshots": [ "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots-rebased/de-privacy-1440.png", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots-rebased/de-privacy-390.png", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots-rebased/zh-Hant-terms-1440.png", "/tmp/claude-0/-home-user/2224823d-3484-535e-94a5-c071ba6af395/scratchpad/issue-312/shots-rebased/zh-Hant-terms-390.png" ], "deviations": [ "The red-before CI case was not repeated after the rebase. The legal rule code is unchanged (range-diff shows context-only differences), and the earlier red was measured against a fresh build of 4da46c5 (14 findings).", "In the PR body, the pre-rebase sections Rebase onto main and Replay with #308 are replaced by Branch and rebase and Verification on the rebased tip. The pre-rebase verification is kept below them.", "Otherwise the same as the final report: model-free trailers, no push, the worktree is kept." ], "mcp_calls": "0", "api_writes": "3 in total on this card -- POST /repos/objectstack-ai/objectos/issues/312/comments ×3 (the first os-dev-report 6020217734, the final os-dev-report 6020507178, and this addendum), all through objectstack scripts/pm/post-stamped.mjs and the fleet-write relay. No push, no PR, no label.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: check-locale-surface now has two small HTML readers (#308's readHtml and this card's legalMainText); the legal rules could move onto readHtml in a follow-up", "carrier: none · noted, not filed: check-locale-surface's final ✓ summary sentence does not mention the legal rules; their result is printed in their own table" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsACCEPT: PR #318 on head
7c17974a2e426ab1bc494f89d00ef3bf8942d5f0· 2026-10-06T16:51Z. I am landing it now: no governed path is touched, no legal wording changes, and every check is green.Path surface (
get_files): 8 files, +485/−80.apps/docs/app/[lang]/{privacy,terms}/page.tsx- each page's new
zh-Hans.json(moved verbatim) and its generatedzh-Hant.json apps/docs/scripts/gen-zh-hant.mjs.github/scripts/check-locale-surface.mjs
Checks on
7c17974:build,Ownership & freshnessandNode floorsucceeded;Deploy docswas skipped.mergeable_stateis clean on base9d3ff08.Push: fast-forward with no force.
ff/issue-312starts at the remote branch headfa2390f, mergesorigin/main@9d3ff08(the diff againstmainis then empty), and cherry-picks39b76e1ande6bf746. Those commits were rebased onto9d3ff08with no conflicts.git diff origin/main 7c17974is byte-identical to the rebased branch.Review:
- Legal text is unchanged.
prove-copy.mjsshows, for privacy and terms, that theenblock is byte-equal tomain's and thatzh-Hans.jsondeep-equalsmain's inline zh-Hans entry.- zh-Hant is new and Traditional. It comes only from the repo's s2twp generator, and
gen-zh-hant --checknow covers 62 files. - The de, ja, es, fr and ko pages are not machine-translated. They show the English text, marked
lang="en", under 290 English-fallback locale URLs render English under lang="xx" with no notice, and the docs chrome (search, TOC, Copy Markdown, language picker) is English in every locale #298's "not translated" notice. - Hreflang lists only en, zh-Hans, zh-Hant and x-default.
- zh-Hant is new and Traditional. It comes only from the repo's s2twp generator, and
- Results:
- Built HTML, JS off: 16/16 pass, against 16/16 failing on the base.
- Hydrated, at 1440 and 390: 32/32 pass, 0 console errors.
- The new CI rules were red on the base with 14 findings, and are green here.
- The merged self-test has 48 cases over 25 rules. Docs accessibility baseline: no main landmark, the language switcher's name contradicts its text, an unnamed svg role=img, unnamed code regions — on every page in every locale #308's
42da2b1made the plannedlegal: nullfixup unnecessary.
- The landmark fix (folded in from Docs accessibility baseline: no main landmark, the language switcher's name contradicts its text, an unnamed svg role=img, unnamed code regions — on every page in every locale #308's axe run). The page's own wrapper is an
articleinside HomeLayout'smain. axe across 18 runs (en, de, zh-Hant × 1440 light/dark, 390): 0 violations of any rule.svg-img-altis now 0 too, thanks to Docs accessibility baseline: no main landmark, the language switcher's name contradicts its text, an unnamed svg role=img, unnamed code regions — on every page in every locale #308. The/de/privacyscreenshots are byte-identical before and after. - Noted, not blocking: s2twp renders 账号 as 賬號 (Taiwan usage prefers 帳號). That is generator vocabulary, the same kind of note as Docs chrome still speaks English inside localized pages: fumadocs' hard-coded aria-labels, English page-tree names without lang="en", no zh-Hant 404 copy #305's.
After merge: watch the deploy verdict and smoke, then post the landed note here. #316 follows on the branch.
Generated by Claude Code
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsLanded and live · 2026-10-06T17:00Z
- PR docs: legal pages mark their English fallback and get zh-Hant from zh-Hans; one main landmark #318: squash
94ce848, merged by the seat.Fixes #312closed this card. - CI on
main(run 37499459314, attempt 1):buildsucceeded, includingcheck-locale-surfacewith the legal rules.Node floor,Deploy docs / Publish the tested WorkerandDeploy docs / Smoke-check the live sitealso succeeded; roll back was skipped. - Deploy verdict:
✓ deploy: 55931ed0-c63e-4e00-a96a-43bb717c03e2 is serving, replacing ab3a6513-3b45-452b-94d3-1cac61bd329e. - Live result:
/de,/ja,/es,/frand/koprivacy and terms pages show the English text markedlang="en", under the "not translated" notice./zh-Hant/privacyand/zh-Hant/termsare Traditional Chinese, generated from zh-Hans.- Each page has one
mainlandmark.
- Housekeeping: the seat removes
pm:dispatchedfrom this card.
Generated by Claude Code
- PR docs: legal pages mark their English fallback and get zh-Hant from zh-Hans; one main landmark #318: squash
Found while #305 was rebased onto
5d2f837on 2026-10-06; the finding is in #305's addendum, comment 6019526340. Confirmed by the seat onmain@5d2f837. Priority: P2, accessibility and localization.What happens
apps/docs/app/[lang]/privacy/page.tsxandterms/page.tsxkeep their copy in acontentrecord with two keys,enandzh-Hans./LOCALE/privacyand/LOCALE/termsrender the English text inside a page whose<html lang>is that locale. Nothing marks the English text: nolang="en"on the content, and no fallback notice of the kind 290 English-fallback locale URLs render English under lang="xx" with no notice, and the docs chrome (search, TOC, Copy Markdown, language picker) is English in every locale #298 added to docs pages./zh-Hant/privacyand/zh-Hant/termsrender English. Every other zh-Hant surface in this repo is derived from zh-Hans bygen-zh-hant(pages,ui-text/zh-Hant.json, and after Docs chrome still speaks English inside localized pages: fumadocs' hard-coded aria-labels, English page-tree names without lang="en", no zh-Hant 404 copy #305 the 404 copy).Done looks like
gen-zh-hant --checkcovers them. Do not hand-write Traditional text.lang="en", and the page says it is shown in English, reusing 290 English-fallback locale URLs render English under lang="xx" with no notice, and the docs chrome (search, TOC, Copy Markdown, language picker) is English in every locale #298's fallback notice wording through ui-text. Do not machine-translate legal text.langmark on a localized page) covers these two routes, or a case for them is added. Show it red before and green after./de/privacyand/zh-Hant/termsat 1440 and 390.Order
After #305; this card builds on its
gen-zh-hant.mjschanges. Coordinate with #308's CI rule.Generated by Claude Code