diff --git a/README.md b/README.md index 1dcc267..4d44add 100644 --- a/README.md +++ b/README.md @@ -127,9 +127,9 @@ MRR×12仅作为显示单位转换,不改写为公司ARR;公司ARR、估算 平台同步时间、连接过期状态、业务描述的可编辑性和产品/法律主体未去重限制均保留。 覆盖审计页位于 `/docs/other-research/ai-company-research/coverage`,分类链接 `overview?category=` 的筛选数据。 -`python3 scripts/audit-ai-research.py --check` 检查候选池逐条计数与覆盖报告一致性;CI在ces-control运行此检查,未更改触发范围。 +`python3 scripts/audit-ai-research.py --check` 检查候选池逐条计数与来源审计一致性;CI在ces-control运行此检查。 收入快照报告位于 `/docs/other-research/ai-company-research/income-snapshot`,样本名称链接 `overview?company=` 的公司明细。 -`python3 scripts/summarize-ai-income.py --check` 独立复核统计与报告一致性;不触发编译或构建。数据变更后先审查方法,再运行不带参数的命令生成 `.artifacts/reports` 下的候选正文,使用 docs 管理工具显式更新数据库;不再生成受 Git 管理的正文。 +`python3 scripts/summarize-ai-income.py --check` 独立复核统计与参考快照一致性;不触发编译或构建。数据变更后先审查方法,再运行不带参数的命令生成 `.artifacts/reports` 下的候选正文,使用 docs 管理工具显式更新数据库;不再生成受 Git 管理的正文。 默认7日样本14个产品;90日窗口新增Gojiberry的8月历史点,营销样本的均值和CV随之明显变化。 这提示先核查时间与样本构成,不能将高离散度直接解释为造假。两个近名营养应用按不同App Store ID分别建档。 @@ -158,17 +158,18 @@ AI 关键词可能出现在业务背景中,收入、买家和交付状态仍 ## CI/CD 与缓存 -`.gitea/workflows/ci-deploy.yml` 使用已有 ces-control Runner,不修改共享 Runner 配置。 -当前工作流仅在 main 推送或针对 main 的手动运行时执行。工作分支PR完成本地静态核查后, -完整类型、测试、构建与容器检查在用户手动合并后的主线CI运行;报告须区分未运行与已通过。 +文档内容已退出构建输入。若需对照研究数据检查数据库中的报告正文,可先导出当前文档,再给研究脚本传入 `--document-export`;默认 `--check` 只核对研究数据本身的统计和审计不变量,避免把历史迁移快照继续当作日常正文源。 -1. 对实际构建输入计算 SHA-256:前端源码、Markdown、图片、Python 制图源码、依赖锁文件、Dockerfile 和构建脚本。 +`.gitea/workflows/ci-deploy.yml` 使用已有 ces-control Runner,不修改共享 Runner 配置。 +部署工作流仅在 main 推送或针对 main 的手动运行时执行。迁移分支 `codex/database-docs` 由独立的 `docs-database-verify.yml` 在 PR 或手动触发时执行完整验证,使用 PR 隔离缓存,不部署;报告须区分未运行与已通过。 + +1. 对实际构建输入计算 SHA-256:前端源码、图片、Python 制图源码、研究业务快照、依赖锁文件、Dockerfile 和构建脚本。 2. 命中 `verified--<摘要>` 镜像时跳过依赖安装和 Next.js build,只做认证、实际路由与资源冒烟检查。 3. 输入变化时运行 lint、类型检查、制图一致性检查与构建。pnpm store、uv 和 `.next/cache` 使用持久 Docker 卷,main 与每个 PR 独立;额外保留 Next.js SWC 下载缓存。 4. 生产镜像只包含 Next.js standalone 产物;Python 留在检查容器,不进入运行镜像。镜像通过动态码认证、重放/限流、重启持久化、健康、全部文档、JS/CSS、SVG 和 404 检查后才标记为 verified。 5. 部署前检查是否仍为最新 main,使用 `--no-build` 启动,失败恢复上一版镜像。 -根 README、工作流或部署配置等非构建输入变化不会触发 Next.js 重建;Markdown 正文变化会更新静态页面,仍需要一次增量构建。首次构建必须安装依赖并完整生成产物。缓存可能因基础镜像、工具链或锁文件变化而失效;不要清理共享 Docker 缓存或卷。 +根 README、工作流或部署配置等非构建输入变化不会触发 Next.js 重建;数据库中的正文和目录变化直接通过请求读取,不触发任何构建。首次构建必须安装依赖并完整生成产物。缓存可能因基础镜像、工具链或锁文件变化而失效;不要清理共享 Docker 缓存或卷。 默认入口为服务器的 **18135** 端口。容器监听 3000,使用独立 Compose 项目 `endorphin-tabularium-docs`。部署前先检查端口是否空闲(或属于本服务),不会停止其他服务以抢占端口。服务器配置位于 `/etc/endorphin-tabularium-docs/production.env`: diff --git a/scripts/audit-ai-research.py b/scripts/audit-ai-research.py index bd7416e..72bf68d 100644 --- a/scripts/audit-ai-research.py +++ b/scripts/audit-ai-research.py @@ -96,15 +96,16 @@ def render(): def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--check', action='store_true') - parser.add_argument('--document-export', type=Path, default=ROOT / '.artifacts/documents-migration.json') + parser.add_argument('--document-export', type=Path) args = parser.parse_args() content = render() if args.check: - bundle = json.loads(args.document_export.read_text()) - stored = next((d['content'] for d in bundle['documents'] if d['sourceSlug'] == SOURCE_SLUG), None) - if stored != content: - sys.exit('Research coverage report differs; review and regenerate') - print('Research coverage accounting and report are consistent') + if args.document_export is not None: + bundle = json.loads(args.document_export.read_text()) + stored = next((d['content'] for d in bundle['documents'] if d['sourceSlug'] == SOURCE_SLUG), None) + if stored != content: + sys.exit('Research coverage report differs; review and regenerate') + print('Research coverage accounting verified; supplied document export compared when requested') else: TARGET.parent.mkdir(parents=True, exist_ok=True) TARGET.write_text(content) diff --git a/scripts/check-container.sh b/scripts/check-container.sh index 9e6608a..bb82d88 100644 --- a/scripts/check-container.sh +++ b/scripts/check-container.sh @@ -1,7 +1,7 @@ #!/bin/sh set -eu export CI=true -pnpm install --frozen-lockfile --store-dir /pnpm/store +pnpm install --frozen-lockfile --store-dir /pnpm/store --fetch-timeout 300000 uv sync --project tools/figures --locked pnpm run lint pnpm run typecheck diff --git a/scripts/summarize-ai-income.py b/scripts/summarize-ai-income.py index 0475295..f7fc65c 100644 --- a/scripts/summarize-ai-income.py +++ b/scripts/summarize-ai-income.py @@ -138,16 +138,17 @@ def render(): def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--check', action='store_true') - parser.add_argument('--document-export', type=Path, default=ROOT / '.artifacts/documents-migration.json') + parser.add_argument('--document-export', type=Path) args = parser.parse_args() verify() content = render() if args.check: - bundle = json.loads(args.document_export.read_text()) - stored = next((d['content'] for d in bundle['documents'] if d['sourceSlug'] == SOURCE_SLUG), None) - if stored != content: - sys.exit('Income snapshot differs; regenerate after reviewing data changes') - print('Income reference, samples and report are consistent') + if args.document_export is not None: + bundle = json.loads(args.document_export.read_text()) + stored = next((d['content'] for d in bundle['documents'] if d['sourceSlug'] == SOURCE_SLUG), None) + if stored != content: + sys.exit('Income snapshot differs; regenerate after reviewing data changes') + print('Income reference and samples verified; supplied document export compared when requested') else: TARGET.parent.mkdir(parents=True, exist_ok=True) TARGET.write_text(content)