mirror of
https://github.com/tradecatlabs/vibe-coding-cn.git
synced 2026-08-23 07:48:06 +00:00
chore: govern metadata redirects
This commit is contained in:
@@ -8,6 +8,8 @@
|
|||||||
- 历史路径仍需被 AI 或外部说明理解时,维护 `redirects.yml`。
|
- 历史路径仍需被 AI 或外部说明理解时,维护 `redirects.yml`。
|
||||||
- 术语口径变化时,同步 `glossary.yml`。
|
- 术语口径变化时,同步 `glossary.yml`。
|
||||||
- 不确定的映射不要猜;先查当前文件和锚点,再修改。
|
- 不确定的映射不要猜;先查当前文件和锚点,再修改。
|
||||||
|
- `redirects.yml` 只记录已经不存在的历史路径到当前入口的映射;禁止添加指向自身的自映射。
|
||||||
|
- `redirects.yml` 的 `from` 必须唯一,且不能仍然存在于仓库中。
|
||||||
|
|
||||||
## 验证
|
## 验证
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
- `taxonomy.yml`:知识库分类、阅读路径和关键文档入口。
|
- `taxonomy.yml`:知识库分类、阅读路径和关键文档入口。
|
||||||
- `glossary.yml`:项目术语表。
|
- `glossary.yml`:项目术语表。
|
||||||
- `redirects.yml`:历史路径到当前入口的映射,供维护和 AI 上下文使用。
|
- `redirects.yml`:已经不存在的历史路径到当前入口的映射,供维护和 AI 上下文使用。
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
|
|||||||
+13
-8
@@ -1,4 +1,5 @@
|
|||||||
redirects:
|
redirects:
|
||||||
|
# Legacy directory moves.
|
||||||
- from: docs/guides/getting-started/
|
- from: docs/guides/getting-started/
|
||||||
to: docs/getting-started/
|
to: docs/getting-started/
|
||||||
- from: docs/principles/fundamentals/
|
- from: docs/principles/fundamentals/
|
||||||
@@ -7,6 +8,8 @@ redirects:
|
|||||||
to: docs/philosophy/
|
to: docs/philosophy/
|
||||||
- from: docs/concepts/philosophy/
|
- from: docs/concepts/philosophy/
|
||||||
to: docs/philosophy/
|
to: docs/philosophy/
|
||||||
|
|
||||||
|
# Merged concept documents.
|
||||||
- from: docs/concepts/思维模型.md
|
- from: docs/concepts/思维模型.md
|
||||||
to: docs/philosophy/README.md#philosophy-thinking-models
|
to: docs/philosophy/README.md#philosophy-thinking-models
|
||||||
- from: docs/concepts/编程之道.md
|
- from: docs/concepts/编程之道.md
|
||||||
@@ -33,6 +36,8 @@ redirects:
|
|||||||
to: docs/philosophy/README.md#philosophy-methodology-toolbox
|
to: docs/philosophy/README.md#philosophy-methodology-toolbox
|
||||||
- from: docs/philosophy/理解世界、描述变化、整理知识的一套较小框架.md
|
- from: docs/philosophy/理解世界、描述变化、整理知识的一套较小框架.md
|
||||||
to: docs/philosophy/README.md#philosophy-compositional-description-model
|
to: docs/philosophy/README.md#philosophy-compositional-description-model
|
||||||
|
|
||||||
|
# Removed playbook directories and documents.
|
||||||
- from: docs/guides/playbook/
|
- from: docs/guides/playbook/
|
||||||
to: docs/README.md
|
to: docs/README.md
|
||||||
- from: docs/playbooks/
|
- from: docs/playbooks/
|
||||||
@@ -45,6 +50,8 @@ redirects:
|
|||||||
to: docs/README.md
|
to: docs/README.md
|
||||||
- from: docs/playbooks/tradecat-sheets-api-usage.md
|
- from: docs/playbooks/tradecat-sheets-api-usage.md
|
||||||
to: docs/README.md
|
to: docs/README.md
|
||||||
|
|
||||||
|
# Merged getting-started documents.
|
||||||
- from: docs/getting-started/Codex-CLI配置.md
|
- from: docs/getting-started/Codex-CLI配置.md
|
||||||
to: docs/getting-started/README.md
|
to: docs/getting-started/README.md
|
||||||
- from: docs/getting-started/学习地图.md
|
- from: docs/getting-started/学习地图.md
|
||||||
@@ -57,6 +64,8 @@ redirects:
|
|||||||
to: docs/getting-started/README.md
|
to: docs/getting-started/README.md
|
||||||
- from: docs/getting-started/开发环境搭建.md
|
- from: docs/getting-started/开发环境搭建.md
|
||||||
to: docs/getting-started/README.md
|
to: docs/getting-started/README.md
|
||||||
|
|
||||||
|
# Merged reference documents.
|
||||||
- from: docs/references/通用项目架构模板.md
|
- from: docs/references/通用项目架构模板.md
|
||||||
to: docs/references/README.md#reference-engineering-practice
|
to: docs/references/README.md#reference-engineering-practice
|
||||||
- from: docs/references/数据集导向数据服务模板.md
|
- from: docs/references/数据集导向数据服务模板.md
|
||||||
@@ -77,12 +86,8 @@ redirects:
|
|||||||
to: docs/references/README.md#reference-engineering-practice
|
to: docs/references/README.md#reference-engineering-practice
|
||||||
- from: docs/references/底层程序逻辑设计与工程优化项.md
|
- from: docs/references/底层程序逻辑设计与工程优化项.md
|
||||||
to: docs/references/README.md#reference-engineering-practice
|
to: docs/references/README.md#reference-engineering-practice
|
||||||
- from: skills/
|
|
||||||
to: skills/
|
# Moved top-level resource directories.
|
||||||
- from: prompts/
|
|
||||||
to: prompts/
|
|
||||||
- from: tools/external/
|
|
||||||
to: tools/external/
|
|
||||||
- from: assets/documents/
|
- from: assets/documents/
|
||||||
to: docs/
|
to: docs/
|
||||||
- from: assets/skills/
|
- from: assets/skills/
|
||||||
@@ -93,8 +98,8 @@ redirects:
|
|||||||
to: tools/external/
|
to: tools/external/
|
||||||
- from: assets/config/
|
- from: assets/config/
|
||||||
to: tools/config/
|
to: tools/config/
|
||||||
- from: tools/config/
|
|
||||||
to: tools/config/
|
# Stable legacy per-topic entry points.
|
||||||
- from: docs/concepts/问题求解.md
|
- from: docs/concepts/问题求解.md
|
||||||
to: docs/concepts/README.md#concept-problem-solving
|
to: docs/concepts/README.md#concept-problem-solving
|
||||||
- from: docs/concepts/拼好码.md
|
- from: docs/concepts/拼好码.md
|
||||||
|
|||||||
@@ -82,6 +82,47 @@ def metadata_targets(path: Path) -> list[tuple[int, str]]:
|
|||||||
return targets
|
return targets
|
||||||
|
|
||||||
|
|
||||||
|
def redirect_pairs(path: Path) -> list[tuple[int, str, str]]:
|
||||||
|
pairs: list[tuple[int, str, str]] = []
|
||||||
|
current_from: tuple[int, str] | None = None
|
||||||
|
|
||||||
|
for lineno, line in enumerate(path.read_text(encoding="utf-8", errors="ignore").splitlines(), start=1):
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped.startswith("- from:"):
|
||||||
|
_, value = stripped.split(":", 1)
|
||||||
|
current_from = (lineno, value.strip().strip("\"'"))
|
||||||
|
continue
|
||||||
|
if stripped.startswith("to:") and current_from:
|
||||||
|
_, value = stripped.split(":", 1)
|
||||||
|
pairs.append((current_from[0], current_from[1], value.strip().strip("\"'")))
|
||||||
|
current_from = None
|
||||||
|
|
||||||
|
return pairs
|
||||||
|
|
||||||
|
|
||||||
|
def validate_redirects(path: Path) -> list[str]:
|
||||||
|
errors: list[str] = []
|
||||||
|
seen_from: dict[str, int] = {}
|
||||||
|
|
||||||
|
for lineno, source, target in redirect_pairs(path):
|
||||||
|
normalized_source = source.rstrip("/")
|
||||||
|
normalized_target = target.split("#", 1)[0].rstrip("/")
|
||||||
|
|
||||||
|
if normalized_source == normalized_target:
|
||||||
|
errors.append(f"{path}:{lineno}: no-op redirect maps '{source}' to itself")
|
||||||
|
|
||||||
|
if source in seen_from:
|
||||||
|
errors.append(f"{path}:{lineno}: duplicate redirect source '{source}', first seen at line {seen_from[source]}")
|
||||||
|
else:
|
||||||
|
seen_from[source] = lineno
|
||||||
|
|
||||||
|
source_path = ROOT / source
|
||||||
|
if source_path.exists():
|
||||||
|
errors.append(f"{path}:{lineno}: redirect source still exists in repository: {source}")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
def validate_target(source: Path, lineno: int, raw: str, anchor_cache: dict[Path, set[str]]) -> str | None:
|
def validate_target(source: Path, lineno: int, raw: str, anchor_cache: dict[Path, set[str]]) -> str | None:
|
||||||
if not raw or raw.startswith(("http://", "https://", "mailto:", "tel:")):
|
if not raw or raw.startswith(("http://", "https://", "mailto:", "tel:")):
|
||||||
return None
|
return None
|
||||||
@@ -122,6 +163,8 @@ def main() -> int:
|
|||||||
error = validate_target(rel_path, lineno, target, anchor_cache)
|
error = validate_target(rel_path, lineno, target, anchor_cache)
|
||||||
if error:
|
if error:
|
||||||
errors.append(error)
|
errors.append(error)
|
||||||
|
if rel_path == Path("metadata/redirects.yml"):
|
||||||
|
errors.extend(validate_redirects(rel_path))
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
print("METADATA_ERRORS")
|
print("METADATA_ERRORS")
|
||||||
|
|||||||
Reference in New Issue
Block a user