Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions assets/demo/storyboard/catalog.zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"status": "owner-review",
"next_gate": "在 GitHub 实际渲染中审阅 74 秒首页 GIF 与中文故事;通过后重导完整母版。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["cli-and-lifecycle", "harness-capture", "viewer-surface", "timeline-navigation", "request-context", "tools", "protocol-and-raw", "translation-theme", "privacy-data"]
},
"story": {
Expand Down Expand Up @@ -63,6 +64,7 @@
"status": "owner-review",
"next_gate": "审阅中文故事和协议边界,再决定是否进入正式配音与成片。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["cli-and-lifecycle", "harness-capture", "viewer-surface", "request-context", "tools", "protocol-and-raw", "translation-theme", "privacy-data"]
},
"story": {
Expand Down Expand Up @@ -108,6 +110,7 @@
"status": "owner-review",
"next_gate": "审阅中文排错故事与发布会式 v0.2 收束页;通过后重导母版,再决定是否进入配音。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "request-context", "tools", "protocol-and-raw", "privacy-data"]
},
"story": {
Expand Down Expand Up @@ -153,6 +156,7 @@
"status": "owner-review",
"next_gate": "审阅中文翻译故事和原文兜底边界,再决定是否进入正式配音与成片。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["viewer-surface", "request-context", "protocol-and-raw", "translation-theme", "privacy-data"]
},
"story": {
Expand Down Expand Up @@ -198,6 +202,7 @@
"status": "owner-review",
"next_gate": "审阅中文故事;通过后导出 v0.3 新母版,并决定正式发布前是否用当前 Claude Code 重录同一最小任务。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "timeline-navigation", "request-context", "tools", "protocol-and-raw", "translation-theme"]
},
"story": {
Expand Down Expand Up @@ -243,6 +248,7 @@
"status": "owner-review",
"next_gate": "审阅中文故事和术语边界,再决定是否进入正式配音与成片。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "timeline-navigation", "request-context", "tools", "skills", "protocol-and-raw", "translation-theme"]
},
"story": {
Expand Down Expand Up @@ -288,6 +294,7 @@
"status": "owner-review",
"next_gate": "审阅异步回流的叙述是否清楚,再决定是否进入正式配音与成片。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "timeline-navigation", "request-context", "tools", "subagents", "protocol-and-raw", "translation-theme"]
},
"story": {
Expand Down Expand Up @@ -333,6 +340,7 @@
"status": "owner-review",
"next_gate": "审阅压缩前后证据是否足以支撑结论,再决定是否进入正式配音与成片。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "timeline-navigation", "request-context", "context-lifecycle", "protocol-and-raw", "translation-theme"]
},
"story": {
Expand Down Expand Up @@ -378,6 +386,7 @@
"status": "owner-review",
"next_gate": "审阅 Codex 与 Claude Code 的差异和发布会式 v0.2 收束页;通过后重导母版,再决定是否进入配音。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "timeline-navigation", "request-context", "context-lifecycle", "protocol-and-raw", "translation-theme"]
},
"story": {
Expand Down Expand Up @@ -423,6 +432,7 @@
"status": "owner-review",
"next_gate": "审阅七次主线 Request 的叙述节奏,再决定是否进入正式配音与成片。",
"freshness": {
"verified_product_sha": "f263104403db2090bda2a1a2f354d40bf167e0ce",
"product_impact_ids": ["harness-capture", "viewer-surface", "timeline-navigation", "request-context", "tools", "agent-planning", "protocol-and-raw", "translation-theme"]
},
"story": {
Expand Down
4 changes: 2 additions & 2 deletions docs/demo-chapter-production.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ node scripts/capture-storyboard-review-frames.mjs claude-planning \
- `subtitles=0` 用于干净画面母版:只隐藏网页字幕层,不改变镜头、标注、点击波纹或转场;带字幕内部预览必须显式选择,不能覆盖干净母版;
- 未来可增加局部放大,但默认保持完整三栏,只有证据在全屏尺寸仍无法阅读时才启用。

统一章节清单保存在 `assets/demo/storyboard/catalog.zh-CN.json`。每项必须声明 `timeline`、`guide`、`guide_section` 与 `review`;`review` 固定包含问题、观众、Source 边界、发布状态、下一道确认门、可执行的 `story` 叙事合同、产品新鲜度边界,以及旁白、字幕、manifest、1920 联系表和 1024 联系表。文档映射只能指向纳入审计的中文公开文档和其中真实存在的标题,审阅资料必须真实存在且可进入 Git。新增、删除或重命名章节时必须同步清单;生产审计要求 catalog 与所有同时具有 manifest 和时间线的可发布章节完全一致。
统一章节清单保存在 `assets/demo/storyboard/catalog.zh-CN.json`。每项必须声明 `timeline`、`guide`、`guide_section` 与 `review`;`review` 固定包含问题、观众、Source 边界、发布状态、下一道确认门、可执行的 `story` 叙事合同、产品新鲜度边界,以及旁白、字幕、manifest、1920 联系表和 1024 联系表。`review.freshness.verified_product_sha` 指向已经完成真实产品复核的共享 `main` 提交;manifest 仍保留原始采集提交,两者不能互相覆盖。文档映射只能指向纳入审计的中文公开文档和其中真实存在的标题,审阅资料必须真实存在且可进入 Git。新增、删除或重命名章节时必须同步清单;生产审计要求 catalog 与所有同时具有 manifest 和时间线的可发布章节完全一致。

`story` 不是自动评价文案“好不好听”,而是防止已经确认的叙事骨架在后续改版中静默丢失。每章必须声明:30 秒内结束的开场镜头及其旁白 / 字幕关键短语、60 秒内明确 PMA 价值的镜头、至少两个来自真实 Viewer 画面的证据镜头,以及最后一幕的可复述结论。`demo-production-audit.mjs` 会把这些引用与当前时间线逐项核对,同时检查 manifest 仍有观众、问题、结论和不讲范围;人工故事审阅仍是发布门,关键短语门禁不能替代人的理解。

Expand Down Expand Up @@ -278,6 +278,6 @@ node scripts/demo-freshness-audit.mjs --target HEAD
node scripts/demo-freshness-audit.mjs --target HEAD --chapter quickstart --json
```

报告分别回答三个问题:manifest 记录的产品证据 SHA 之后,本章关注的运行时代码是否变化;确定性 Source 生成脚本更新后,Source 图片与 manifest 是否重建;共享播放器、时间线或 Source 图片更新后,已提交双尺寸复核帧是否重生成。第一项要求重新检查真实 Harness / Viewer,第二项要求用非敏感场景重建 Source,第三项只要求重渲染;任何一项都不能代替另外两项。完成对应更新和逐帧审视后,再以 `--strict` 验证选中的章节。
报告分别回答三个问题:catalog 的共享产品复核检查点之后,本章关注的运行时代码是否变化;确定性 Source 生成脚本更新后,Source 图片与 manifest 是否重建;共享播放器、时间线或 Source 图片更新后,已提交双尺寸复核帧是否重生成。原始 manifest 采集 SHA 会同时出现在报告中用于 provenance,但 squash merge 后的新鲜度比较不能依赖只存在于功能分支的提交。第一项要求重新检查真实 Harness / Viewer,第二项要求用非敏感场景重建 Source,第三项只要求重渲染;任何一项都不能代替另外两项。完成对应更新和逐帧审视后,把复核后的共享 `main` SHA 写入 catalog,再以 `--strict` 验证选中的章节。

产品所有者主工作区的 heartbeat 会在 `origin/main` 变化后生成携带精确 SHA、受影响章节、产品证据状态、Source 生成脚本状态和复核帧状态的文档任务;它不能跳过真实页面复核,也不能自动发布未经审视的截图。共享 GitHub 工作流继续只生成只读 Job Summary,不会因克隆仓库而自动创建本地调度。
4 changes: 2 additions & 2 deletions docs/documentation-maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
- `scripts/demo-production-audit.mjs` 跨章节核对 manifest、旁白、时间线、SRT、Source 图片、双尺寸审阅帧的真实像素、Git 可追踪性、媒体体积预算、章节审阅合同与常见隐私哨兵;catalog 中的叙事合同还要求开场在 30 秒内完成、PMA 价值在 60 秒内讲明、至少两个 Viewer 证据镜头真实存在、结尾能回到可复述结论;带 `review_points` 的章节可用 `--strict` 要求两档帧与稳定时点逐一对应;`smoke:governance` 会调用这项生产审计;
- `scripts/documentation-consistency-audit.mjs` 核对中英文 README、快速开始、用户手册首页与十个任务章节的本地链接和章节锚点;同时检查 Node.js 要求、九条核心 CLI 事实、英文首页的支持协议/主 GIF/中文深读入口,以及十个演示章节到真实中文标题和审阅合同的映射;它已经由 `smoke:governance` 调用;
- 同一脚本的 `--base` / `--changed-file` 模式会把功能变更映射成受影响文档与演示素材;JSON 同时包含精确目标 SHA、解析后的 base SHA、工作区状态、去重后的必查文档、必查演示和具体章节 id、验证命令与隐私限制,可以直接作为文档 Agent 的任务载荷;
- `scripts/demo-freshness-audit.mjs` 把“演示可能过时”拆成三类可验证结论:manifest 中的精确产品证据 SHA 之后,当前章节关注的运行时代码是否变化;章节的 Source 生成脚本更新后,Source 图片与 manifest 是否重建;以及共享播放器、当前时间线或 Source 图片更新后,已提交双尺寸复核帧是否重生成。默认模式只报告而不阻断;只有完成真实 Viewer 复核并准备交接时才使用 `--strict`;
- `scripts/demo-freshness-audit.mjs` 把“演示可能过时”拆成三类可验证结论:catalog 中已经在共享 `main` 完成产品复核的检查点之后,当前章节关注的运行时代码是否变化;章节的 Source 生成脚本更新后,Source 图片与 manifest 是否重建;以及共享播放器、当前时间线或 Source 图片更新后,已提交双尺寸复核帧是否重生成。报告同时保留 manifest 的原始采集 SHA 作为 provenance,但不要求 squash merge 后的分支提交永久可达。默认模式只报告而不阻断;只有完成真实 Viewer 复核并准备交接时才使用 `--strict`;
- `.github/workflows/release-check.yml` 已在每个 PR 增加只读 `Documentation impact` job:它检出精确 head SHA,以 PR base SHA 到 head SHA 的 merge-base 范围生成 JSON,再把受影响文档、演示 Source、验证命令和隐私限制写入 GitHub Job Summary;job 只有 `contents: read`,不会评论 PR、创建 issue、读取 secrets 或发布素材;
- `scripts/documentation-impact-summary.mjs` 负责校验 JSON 中的 head/base SHA 并生成防 Markdown 注入的摘要;路径很多时完整变更列表折叠显示,必查文档和演示保持在首屏;
- 产品所有者的主文档工作区已启用名为 `peekMyAgent documentation and demo drift monitor` 的 Codex heartbeat:每天本地时间 10:00 轻量轮询一次 `origin/main`,用 Git 忽略的 `tmp/documentation-main-monitor.json` 保存最后扫描 SHA,并复用同一 JSON 影响映射唤醒当前长期文档任务;没有新 SHA 或没有映射边界时不通知、不截图、不运行大检查;
Expand Down Expand Up @@ -82,7 +82,7 @@
--json
```

`product_evidence.status: review-required` 表示 manifest 的产品证据之后,章节关注的 CLI、Capture、Viewer、工具、协议等运行时边界发生了变化,需要重新操作真实产品并判断 Source 是否失效;`source_recipe.status: regeneration-required` 表示该章的确定性生成脚本比 Source 图片与 manifest 更新;`tracked_review_frames.status: regeneration-required` 表示网页播放器、该章时间线或 Source 图比已提交复核帧更新,需要重新生成两档复核帧。三者互不替代:只改标注样式可能只要求重渲染,生成脚本变化要求重建 Source,产品功能变化则要求先复核真实产品;
`product_evidence.status: review-required` 表示 catalog 的 `verified_product_sha` 之后,章节关注的 CLI、Capture、Viewer、工具、协议等运行时边界发生了变化,需要重新操作真实产品并判断 Source 是否失效;`capture_sha` 仍指向 manifest 的原始采集证据,不作为 squash 后的可达性前提。`source_recipe.status: regeneration-required` 表示该章的确定性生成脚本比 Source 图片与 manifest 更新;`tracked_review_frames.status: regeneration-required` 表示网页播放器、该章时间线或 Source 图比已提交复核帧更新,需要重新生成两档复核帧。三者互不替代:只改标注样式可能只要求重渲染,生成脚本变化要求重建 Source,产品功能变化则要求先复核真实产品;
4. 运行确定性 `--verify` 和现有文档检查;
5. PR job 把匹配结果写入只读 Job Summary;功能贡献者更新对应文档/manifest,或记录公开行为未变化的具体证据;
6. 主工作区 heartbeat 在发现新 SHA 后生成同结构 JSON,按 `target SHA + impact_ids` 去重;存在映射边界时对 `required_demo_chapters` 运行新鲜度检查并唤醒当前长期文档任务,没有映射时只更新检查点;
Expand Down
18 changes: 17 additions & 1 deletion scripts/demo-freshness-audit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ function auditChapter({ chapter, targetSha }) {
const timelinePath = repoPathFromAssetHref(chapter.timeline, `${chapter.id} timeline`);
const manifest = JSON.parse(readRepoFile(manifestPath));
const timeline = JSON.parse(readRepoFile(timelinePath));
const evidence = resolveEvidenceCommit(manifest, chapter.id);
const captureEvidence = resolveEvidenceCommit(manifest, chapter.id);
const evidence = resolveFreshnessCheckpoint(chapter, captureEvidence);
resolveRevision(evidence.sha);

const watchedImpactIds = chapter.review?.freshness?.product_impact_ids;
Expand Down Expand Up @@ -118,6 +119,8 @@ function auditChapter({ chapter, targetSha }) {
status: productStatus,
evidence_sha: evidence.sha,
evidence_field: evidence.field,
capture_sha: captureEvidence.sha,
capture_field: captureEvidence.field,
watched_impact_ids: watchedImpactIds,
matched_impact_ids: matchedImpacts.map((impact) => impact.id),
changed_files: productChangedFiles,
Expand All @@ -139,6 +142,19 @@ function auditChapter({ chapter, targetSha }) {
};
}

function resolveFreshnessCheckpoint(chapter, captureEvidence) {
const verifiedProductSha = chapter.review?.freshness?.verified_product_sha;
if (verifiedProductSha === undefined) return captureEvidence;
assert.equal(typeof verifiedProductSha, "string",
`${chapter.id} freshness.verified_product_sha must be a string`);
assert.match(verifiedProductSha, shaPattern,
`${chapter.id} freshness.verified_product_sha must be a full lowercase SHA`);
return {
field: "catalog.review.freshness.verified_product_sha",
sha: verifiedProductSha,
};
}

function resolveEvidenceCommit(manifest, chapterId) {
const candidates = [
["source.product_baseline_sha", manifest.source?.product_baseline_sha],
Expand Down
3 changes: 3 additions & 0 deletions scripts/documentation-consistency-audit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ export function runDocumentationConsistencyAudit({ log = true } = {}) {
assert.equal(typeof chapter.review?.next_gate, "string",
`storyboard chapter ${chapter.id} needs a next review gate`);
const productImpactIds = chapter.review?.freshness?.product_impact_ids;
const verifiedProductSha = chapter.review?.freshness?.verified_product_sha;
assert.match(verifiedProductSha || "", /^[0-9a-f]{40}$/,
`storyboard chapter ${chapter.id} needs freshness.verified_product_sha`);
assert(Array.isArray(productImpactIds) && productImpactIds.length > 0,
`storyboard chapter ${chapter.id} needs freshness.product_impact_ids`);
assert.equal(new Set(productImpactIds).size, productImpactIds.length,
Expand Down
4 changes: 4 additions & 0 deletions scripts/governance-smoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,15 @@ assert.equal(
);
assert(freshnessSummary.chapters.every((chapter) => (
/^[0-9a-f]{40}$/.test(chapter.product_evidence.evidence_sha)
&& /^[0-9a-f]{40}$/.test(chapter.product_evidence.capture_sha)
&& /^[0-9a-f]{40}$/.test(chapter.source_recipe.generator_commit)
&& /^[0-9a-f]{40}$/.test(chapter.source_recipe.source_commit)
&& /^[0-9a-f]{40}$/.test(chapter.tracked_review_frames.dependency_commit)
&& /^[0-9a-f]{40}$/.test(chapter.tracked_review_frames.review_commit)
)), "every chapter must name exact evidence and render commits");
assert(freshnessSummary.chapters.every((chapter) => (
chapter.product_evidence.evidence_field === "catalog.review.freshness.verified_product_sha"
)), "every chapter must use a shared main freshness checkpoint");

const storyboardCatalog = JSON.parse(fs.readFileSync("assets/demo/storyboard/catalog.zh-CN.json", "utf8"));
assert.equal(storyboardCatalog.schema_version, 5);
Expand Down
Loading