feat(seo): fix 118 short meta descriptions reported by Bing#341
Merged
Conversation
Bing Webmaster 报告 118 个页面 meta description 太短。docs 页面直接读 MDX frontmatter description,缺失/空/极短时无 fallback。 新增 lib/seo-description.ts 的 ensureSeoDescription() 在 generateMetadata 里把 description 兜底到 ≥ 80 字符:原 description(如有)+ 主题 + 分区 面包屑 + 站点 tagline。中英文 tagline 各一份按 locale 选。 接入 4 处:docs/[...slug]、docs/、events/[id]、feed/。docs 动态路由的 TechArticle JSON-LD 同步走兜底。
新增 scripts/check-frontmatter-description.mjs:默认 --changed 模式
检查新增/修改的 MDX 必须有 description 且 ≥ 60 字符。
接入位置:
- .husky/pre-commit:本地提交前拦截
- .github/workflows/content-check.yml:PR 时按 GITHUB_BASE_REF diff
- package.json 新增 check:frontmatter / check:frontmatter:all 命令
豁免规则:
- content/docs/career/interview-prep/leetcode/ 全部豁免(程序化导入
的题解,靠 lib/seo-description.ts 兜底)
- *_translated.{md,mdx}(机翻产物)
老存量页面由 Layer 1 代码层兜底,本 lint 只阻止新增低质量 description。
新增 scripts/generate-descriptions.mjs:默认调 DeepSeek 给所有 description 缺失/空/极短的 MDX 生成精准摘要,写回 frontmatter。 设计: - 默认 dry-run 生成 scripts/.descriptions-report.json - --apply 真写回;--from-report --apply 跳过 LLM 复用已有报表 - --leetcode-only 模板模式(不调 LLM,离线 fallback) - --limit=N 小批量试运行 - Surgical edit 只动 description 行,不重格式化 yaml,git diff 干净 幂等性:已合格 description (>= 60 字符) 跳过,重跑安全。 本次跑完 DeepSeek 改了 253 个 MDX frontmatter description: - median 134 字符,min 64,max 264 - 0 errors,~$0.05 总成本 - 中英文按 .en 后缀决定生成语言 .gitignore 追加 scripts/.descriptions-report.json(dry-run 产物)。
补齐 32 个只有中文版的 mdx 对应的 .en.md/.en.mdx,解决 /en/ URL 时 fumadocs fallbackLanguage='zh' 兜底渲染中文内容 + 中文 description 导致 URL/description 语言不一致的 SEO 隐患。 由 translator agent (claude-sonnet-4-6) 分两批并行翻译,保留代码块、 数学公式、URL、组件名 / 非文本属性原样;frontmatter 加 lang=en / translatedFrom=zh / translatedAt / translatorAgent 4 个字段,docId 继承原文不变。 翻译范围: - 9 个分区 index.mdx(career/community/learn/projects 等) - 23 个 leetcode 题解 + 社区长文(PTE、UNSW 福利、Burnout、PPO 等) 翻译后中英对照对数从 97 → 129,zh-only 从 32 → 0。
补 dev_docs/seo_meta_description.md,完整记录这次 SEO 治理的方案: 为什么需要、Layer 1/2/3/4 各自做什么、决策记录、验证步骤、相关文件。
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses Bing Webmaster Tools reports of “meta descriptions too short” by introducing a runtime SEO description fallback for pages (especially docs) and adding guardrails/documentation to prevent future regressions, alongside large-scale frontmatter description backfills and additional EN translations to avoid locale/content mismatches.
Changes:
- Added
ensureSeoDescription()helper + unit tests and integrated it into multiplegenerateMetadatacall sites. - Added CI/pre-commit wiring (scripts + workflow + package scripts) to lint MDX frontmatter descriptions on changed files.
- Backfilled/translated many MD/MDX docs to improve frontmatter description quality and locale consistency.
Reviewed changes
Copilot reviewed 297 out of 298 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/seo-description.test.ts | Adds unit tests covering fallback behaviors and locale-specific tagline output. |
| package.json | Adds check:frontmatter and check:frontmatter:all scripts. |
| lib/seo-description.ts | Introduces centralized SEO description fallback logic. |
| dev_docs/seo_meta_description.md | Documents the multi-layer meta description remediation strategy. |
| app/[locale]/feed/page.tsx | Uses ensureSeoDescription() for the feed page metadata description. |
| app/[locale]/events/[id]/page.tsx | Uses ensureSeoDescription() for per-event metadata description fallback. |
| app/[locale]/docs/page.tsx | Applies ensureSeoDescription() to the docs landing page metadata. |
| app/[locale]/docs/[...slug]/page.tsx | Applies ensureSeoDescription() to docs pages’ Metadata + JSON-LD description. |
| .husky/pre-commit | Adds frontmatter description lint as a blocking pre-commit step. |
| .gitignore | Ignores description generation report artifact. |
| .github/workflows/content-check.yml | Adds PR-blocking step to check changed MDX frontmatter descriptions. |
| content/docs/projects/multimodal-rl.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/projects/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/projects/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/projects/ai-town.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/projects/ai-town.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/learn/cs/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/frontend/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/frontend/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/frontend/frontend-learning/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/frontend/frontend-learning/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/data-structures/linked-list/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/data-structures/linked-list/01-singly-linked-list.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/data-structures/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/data-structures/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/data-structures/array/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/data-structures/array/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/data-structures/array/02-dynamic-array.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/data-structures/array/01-static-array.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/mempool-simple.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/mempool-simple.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/handwritten-pool-components/2-handwritten-mempool1.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/handwritten-pool-components/2-handwritten-mempool1.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/handwritten-pool-components/1-handwritten-threadpool.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/handwritten-pool-components/1-handwritten-threadpool.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/easy-compile/5-vcpkg.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/easy-compile/5-vcpkg.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/easy-compile/4-cmake.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/easy-compile/4-cmake.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/easy-compile/3-make.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/easy-compile/3-make.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/easy-compile/2-base-gcc.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/easy-compile/2-base-gcc.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/cs/cpp-backend/easy-compile/1-cpp-libs.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/cs/cpp-backend/easy-compile/1-cpp-libs.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/reinforcement-learning/reinforcement-learning-overview.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/reinforcement-learning/ppo.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/reinforcement-learning/ppo.en.md | Adds EN translation + description. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note/wangshusen_recommend_note_retrieval.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note/wangshusen_recommend_note_retrieval.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_rerank.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_rerank.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_rank.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_rank.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_improvement.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_improvement.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_coldstart.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_note_coldstart.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_crossing.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/recommender-systems/wangshusen_recommend_crossing.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/recommender-systems/recommender-roadmap.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/VQVAE/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/VQVAE/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/multimodal/vit/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/vit/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/multimodal/video-mm-todo/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/VAE/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/VAE/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/multimodal/RQVAE/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/RQVAE/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/multimodal/qwenvl/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/multimodal-overview.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/mllm/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/mllm/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/multimodal/llava/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/courses/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/multimodal/courses/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/Multi-agents-system-on-Code-Translation/code-translation-intro.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/Multi-agents-system-on-Code-Translation/code-translation-intro.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/MoE/moe-update.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/MoE/moe-update.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/MoE/MOE-intro.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/model-datasets-platforms/platform-and-datasets.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/misc-tools/learning-toolkit.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/methodology/research-methodology.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/transformer/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/transformer/ai-by-hand/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/transformer/ai-by-hand/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/llm-basics/pytorch/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/llm-foundations.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/embeddings/qwen3-embedding/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/embeddings/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/embeddings/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/llm-basics/deep-learning/nlp/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/deep-learning/nlp/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/llm-basics/deep-learning/misc/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/deep-learning/misc/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/llm-basics/deep-learning/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/deep-learning/d2l/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/deep-learning/d2l/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/llm-basics/cuda/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/llm-basics/courses/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/Introduction-of-Multi-agents-system/introduction_of_multi-agents_system.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/Introduction-of-Multi-agents-system/introduction_of_multi-agents_system.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/learn/ai/generative-todo/generative-models-plan.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/training/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/rag/rag.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/rag/rag.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/foundation-models/rag/embedding.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/rag/embedding.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/foundation-models/rag/context-engineering-intro.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/rag/context-engineering-intro.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/foundation-models/qkv-interview/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/foundation-models-lifecycle.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/finetune/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/evaluation/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/deploy-infer/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/foundation-models/datasets/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/compute-platforms/model-compuational-resource-demand.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/compute-platforms/compute-platforms-handbook.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/probability-statistics/resources/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/probability-statistics/resources/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/ai-math-basics/probability-statistics/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/numerical-analysis/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/math-foundations.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/math_books.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/math_books.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/ai-math-basics/linear-algebra/resources/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/linear-algebra/resources/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/ai-math-basics/linear-algebra/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/information-theory/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/ai-math-basics/calculus-optimization/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/agents-todo/cs294-194-196/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/agents-todo/cs294-194-196/index.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/learn/ai/agents-todo/agent-ecosystem.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/learn/ai/agents-todo/agent-ecosystem.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/community/tools/swanlab.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/tools/swanlab.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/community/tools/perplexity-comet.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/tools/perplexity-comet.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/community/tools/index.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/tools/index.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/community/papers/prompt-repetition-improves-non-reasoning-llms.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/papers/prompt-repetition-improves-non-reasoning-llms.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/community/papers/leworldmodel.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/mental-health/index.mdx | Adds frontmatter description. |
| content/docs/community/mental-health/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/community/mental-health/burnout-guide.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/mental-health/burnout-guide.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/community/life/unsw-student-benefit.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/life/unsw-student-benefit.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/community/language/pte-intro.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/language/pte-intro.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/community/index.mdx | Adds frontmatter description. |
| content/docs/community/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/community/dev-tips/raspberry-guide.md | Adds frontmatter description. |
| content/docs/community/dev-tips/raspberry-guide.en.md | Adds frontmatter description. |
| content/docs/community/dev-tips/picturecdn.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/dev-tips/picturecdn.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/community/dev-tips/Katex/Seb2.mdx | Adds frontmatter description. |
| content/docs/community/dev-tips/Katex/Seb2.en.mdx | Adds frontmatter description. |
| content/docs/community/dev-tips/Katex/Seb1.mdx | Adds frontmatter description. |
| content/docs/community/dev-tips/Katex/Seb1.en.mdx | Adds frontmatter description. |
| content/docs/community/dev-tips/Katex/index.mdx | Adds frontmatter description. |
| content/docs/community/dev-tips/Katex/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/community/dev-tips/index.mdx | Adds frontmatter description. |
| content/docs/community/dev-tips/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/community/dev-tips/git101.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/dev-tips/git101.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/community/dev-tips/CommonUsedMarkdown.md | Adds frontmatter description. |
| content/docs/community/dev-tips/CommonUsedMarkdown.en.md | Adds frontmatter description. |
| content/docs/community/dev-tips/cloudflare-r2-sharex-free-image-hosting.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/community/dev-tips/cloudflare-r2-sharex-free-image-hosting.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/career/interview-prep/preparations-to-get-an-offer-as-a-student.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/interview-prep/preparations-to-get-an-offer-as-a-student.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/career/interview-prep/pre-interview.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/interview-prep/pre-interview.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/career/interview-prep/leetcode/sword-offer-ii-021-remove-nth-node-from-end-of-list.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/interview-prep/leetcode/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/counting-stars-inter-uni-programming-contest.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/counting-stars-inter-uni-programming-contest.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/Counting Stars-Inter-Uni Programming Contest.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/Counting Stars-Inter-Uni Programming Contest.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/brief-alternate-homework-help.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/994-rotting-oranges.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/93-restore-ip-addresses.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/93-restore-ip-addresses.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/9021-tut-3-25t1.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/9021-tut-3-25t1.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/9021_TUT_3_25T1.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/80-remove-duplicates-from-sorted-array-ii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/80_translated.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/76-minimum-window-substring.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/6323-distribute-money-to-maximum-children.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/538-convert-bst-to-greater-sum-tree.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/46-permutations.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/46-permutations.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/42.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/42.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/42-trapping-rain-water.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/345-reverse-vowels-of-a-string.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/3138. Minimum Length of Anagram Concatenation.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/3138. Minimum Length of Anagram Concatenation.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/3138-minimum-length-of-anagram-concatenation.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/3138-minimum-length-of-anagram-concatenation.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/3072-distribute-elements-into-two-arrays-ii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2894-divisible-and-non-divisible-sums-difference.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2679-sum-in-a-matrix.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2639-find-column-width-of-grid.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2582-pass-the-pillow.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2562-find-the-array-concatenation-value.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2490-circular-sentence.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2341-maximum-number-of-pairs-in-array.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2335-minimum-amount-of-time-to-fill-cups.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2309-greatest-english-letter-in-upper-and-lower-case.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2299-strong-password-checker-ii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2293-min-max-game.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2293_translated.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2270. Number of Ways to Split Array.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2270. Number of Ways to Split Array.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/2270-number-of-ways-to-split-array.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2270-number-of-ways-to-split-array.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/2241. Design an ATM Machine.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2241. Design an ATM Machine.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/2241-design-an-atm-machine.zh.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2241-design-an-atm-machine.en.md | Adds EN variant with translated frontmatter and content. |
| content/docs/career/interview-prep/leetcode/219-contains-duplicate-ii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/219_translated.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/2131-longest-palindrome-by-concatenating-two-letter-words.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/213-house-robber-ii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1828-queries-on-number-of-points-inside-a-circle.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1825-mk-average.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1664-ways-to-make-a-fair-array.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1653-minimum-deletions-to-make-string-balanced.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1545-find-kth-bit-in-nth-binary-string.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/146-lru-cache.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/142-linked-list-cycle-ii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1333-filter-restaurants-by-vegan-friendly-price-and-distance.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1234-replace-substring-for-balanced-string.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/121-best-time-to-buy-and-sell-stock.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1004-max-consecutive-ones-iii.en.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/leetcode/1004_translated.md | Adds a frontmatter description line. |
| content/docs/career/interview-prep/interview-tips.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/interview-prep/interview-tips.en.mdx | Updates EN frontmatter description to be non-empty. |
| content/docs/career/interview-prep/bq.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/interview-prep/bq.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/career/index.mdx | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/index.en.mdx | Adds EN variant with translated frontmatter and content. |
| content/docs/career/events/event-takeway.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/events/event-takeway.en.md | Updates EN frontmatter description to be non-empty. |
| content/docs/career/events/coffee-chat.md | Updates frontmatter description to be longer/more descriptive. |
| content/docs/career/events/coffee-chat.en.md | Updates EN frontmatter description to be non-empty. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+57
to
+71
| /** | ||
| * 把短/空/缺失的 description 兜底到 >= MIN_SEO_DESCRIPTION_LENGTH 字符。 | ||
| * | ||
| * @example | ||
| * ensureSeoDescription({ description: "", title: "2335. Min Time", sectionPath: ["career", "interview-prep", "leetcode"], locale: "zh" }) | ||
| * // → "主题:2335. Min Time。 所属分区:career › interview-prep › leetcode。 Involution Hell 社区文档 — ..." | ||
| */ | ||
| export function ensureSeoDescription(opts: EnsureSeoDescriptionOpts): string { | ||
| const raw = (opts.description ?? "").trim(); | ||
| if (raw.length >= MIN_SEO_DESCRIPTION_LENGTH) { | ||
| return raw; | ||
| } | ||
|
|
||
| const isEn = opts.locale === "en"; | ||
| const tagline = isEn ? SITE_TAGLINE_EN : SITE_TAGLINE_ZH; |
Comment on lines
+82
to
+87
| // title 拼接:如果 sectionPath 末段(已是 title slug)与 title 重复, | ||
| // 跳过 title 段避免 "主题:A 所属分区:x › A" 这种重复 | ||
| const titleStr = (opts.title ?? "").trim(); | ||
| if (titleStr) { | ||
| parts.push(isEn ? `Topic: ${titleStr}.` : `主题:${titleStr}。`); | ||
| } |
Comment on lines
+26
to
+35
| // 原 description 只有 24 字符(远低于 Bing 推荐的 150-160),统一走 ensureSeoDescription | ||
| // 兜底到 80+ 字符。社区分享墙是公开 SEO 页,搜索摘要质量直接影响 CTR。 | ||
| export const metadata: Metadata = { | ||
| title: "社区分享墙 · Involution Hell", | ||
| description: "群友精选好文,随手转发,沉淀有价值的信息流。", | ||
| description: ensureSeoDescription({ | ||
| description: "群友精选好文,随手转发,沉淀有价值的信息流。", | ||
| title: "社区分享墙", | ||
| sectionPath: ["feed"], | ||
| locale: "zh", | ||
| }), |
Comment on lines
54
to
+70
| interface Param { | ||
| params: Promise<{ id: string }>; | ||
| } | ||
|
|
||
| export async function generateMetadata({ params }: Param): Promise<Metadata> { | ||
| const { id } = await params; | ||
| const data = await fetchDetail(id); | ||
| if (!data) return { title: `活动 #${id} · Involution Hell` }; | ||
| if (!data) { | ||
| // 没拿到 event 也兜底 description(404 前的过渡态) | ||
| return { | ||
| title: `活动 #${id} · Involution Hell`, | ||
| description: ensureSeoDescription({ | ||
| title: `活动 #${id}`, | ||
| sectionPath: ["events"], | ||
| locale: "zh", | ||
| }), | ||
| }; |
Comment on lines
+147
to
+149
| # Important Note | ||
|
|
||
| If there are any errors or unclear explanations, please reach out for corrections. WeChat: m1197501753 |
CodeQL 在 PR 341 报 3 个 alert: 1. js/redos (line 430,2 处 backtracking 模式) surgical edit 用的 /^description:.*(?:\n(?:[ \t]+.*|\s*))*?(?=\n[\w-]+:|$)/m 内层 (?:[ \t]+.*|\s*) 在 \n 上 ambiguous,最坏情况指数回溯。 改成逐行扫描:找 description: 起始行,往下吃缩进/空行直到下一个顶级 yaml 键。逻辑一致但无 ReDoS 风险,4 个 yaml frontmatter case 测过。 2. js/incomplete-multi-character-sanitization (line 126) cleanBody 的 <[^>]+> 单次 replace 后嵌套残留(如 <<script>>)。 改成循环 replace 直到 stable,确保所有标签完全清理。 脚本只在离线 backfill 用,不接收外部输入;修复是为消除 CodeQL 高危告警 让 PR 能 merge。
Vercel build 在 PR 341 fail,根因:surgical edit 没考虑 title 用 YAML
folded/literal block scalar(>- / |- / >+ 等)时的多行续行。
case:
---
title: >-
line 1
line 2
date: "..."
---
之前逻辑在第一个顶级键(title:)行后直接插入 description:,把 title
的续行变成 dangling indented text,js-yaml 报 "bad indentation of a
mapping entry"。
修:找 insert 位置时也吃缩进/空行续行,与 description 块检测同样处理。
顺手修复 2309 文件被先前 bug 改坏的 frontmatter。
另外 142 / 1545 两个 mdx 是 prebuild escape-angles.mjs 跑出来的产物
(转义 markdown 文本里的 <、>),一起提交进来防止 build 时反复变更。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bing Webmaster Tools 报告 118 个页面 meta description 太短(< 150 字符)。根因是 fumadocs docs 页面直接读 MDX frontmatter description,缺失/空/极短时无代码兜底,且 292 个 MDX 里 198 个内容质量不达标。
本 PR 用三层叠加方案修复,并补齐 32 个 zh-only 页面的英文翻译解决 URL/description 语言不一致的副作用。
5 个 commit 拆分
f83e622feat(seo): add description fallback for docs metadatalib/seo-description.ts+ 4 处 generateMetadata 接入 + tests4ae561bfeat(seo): lint mdx frontmatter description in CIscripts/check-frontmatter-description.mjs+ husky + workflowe5de136feat(seo): backfill 253 mdx descriptions via deepseek3593557feat(seo): translate 32 zh-only docs to en.en.md/.en.mdxe981ff5docs(dev): seo meta description three-layer scheme三层方案是什么
Layer 1(运行时兜底):
ensureSeoDescription()在 generateMetadata 里把短/空/缺失 description 拼接到 ≥ 80 字符(原 description + 主题 + 分区面包屑 + 站点 tagline)。立即消除 Bing 告警,不动 content。Layer 2(CI lint 守门):pre-commit + GH Actions PR 检查新增/修改的 MDX 必须有 description ≥ 60 字符。leetcode/ 与
_translated.md豁免(由 Layer 1 兜底)。阻止再积累低质量 description。Layer 3(存量内容回填):离线脚本调 DeepSeek 给 253 个 description 缺失/空/极短的 MDX 生成精准摘要写回 frontmatter。Surgical edit 只动 description 行,不重格式化 yaml,git diff 干净。$0.05 总成本。
Layer 4(翻译补齐):用 translator agent (claude-sonnet-4-6) 翻译 32 个 zh-only 页面,避免 /en/ URL fumadocs fallback 渲染中文内容 + 中文 description 的 SEO 语言信号不一致。中英对照对数 97 → 129,zh-only 32 → 0。
验证
pnpm typecheck✅pnpm test✅ 34 / 34pnpm check:frontmatter:all✅ 0 violations (324 文件 / 104 豁免 / 220 OK)CICD 行为说明(user 问过)
check:frontmatterlint(拦新增/修改)node scripts/generate-descriptions.mjs --apply.en.md用英文 prompt,其他用中文(默认 fallback)Test plan
pnpm build没崩<meta name="description">验证 ≥ 80 字符Related docs
dev_docs/seo_meta_description.md