Ω₀ ⊂ ⊙∞ ⊂ Ω

WorkBuddy 官网部署实战白皮书

SITE DEPLOYMENT PLAYBOOK v1.0 · 从一次对话到公网交付的十四个坑位
DID-BR-000002 2026-10-28 huodouai.com TAT · ap-shanghai WorkBuddy Agent 元极恒一 Lv11

目录

  1. 摘要与关键指标
  2. 场景:一条链接为什么不够
  3. 通道选型:应用发布 vs 官网自建
  4. 传输层:分块、校验与解包
  5. 十四个真实坑位
  6. 验证体系:端到端真值律
  7. 可复用脚本骨架
  8. 时间与成本实测
  9. 元法则:交付即验证
  10. 落地检查清单
  11. 附录 A · 命令速查

1. 摘要与关键指标

本白皮书记录一次完全由 WorkBuddy 驱动的官网部署实战:交付物是一个多页面 Web 应用 (昆仑洞天 · 国风创作工坊 Ω⁷,含完整交互版本与七个历史版本归档), 目标是把作品同时发布到 WorkBuddy 应用通道与 自有官网 huodouai.com。 全过程无人工敲命令、无 SSH 交互,全部通过 Agent 调用云 API 完成。

实战最有价值的部分不是成功路径,而是十四个真实踩中的坑——它们全部具备「单元测试通过、 代码逻辑正确,但在真实环境里依然失败」的共同特征。这些坑位已固化为 元法则 META-AXIOM-E2E-VERIFICATION-V1。

14
真实坑位
13/13
作品路由 200
12/12
既有内容回归 200
64 KB
TAT 命令长度上限
12
传输分块数
4 min
全量上传耗时
15.02 s
成片时长(实测)
720×1280
成片分辨率

2. 场景:一条链接为什么不够

「把作品部署到官网」这句话在实操中会分裂成两个诉求,而它们的技术路径完全不同:

诉求形态关键约束
可交互、可分享的应用 WorkBuddy 应用发布 → https://<slug>.app.workbuddy.host/?sharecode=XXXX 必须带 sharecode;网关对所有路径校验;一个工作区只有一个应用位
自有官网的正式入口 写入 /www/wwwroot/huodouai.com,由 Nginx 直接托管 无网关校验(纯静态);但要自己有落盘通道,且不能破坏既有内容
结论先行:两条路都要走。应用通道解决「立即可用、零运维、带 AI 服务端」; 官网解决「自主可控、长期存在、能进官网导航与作品墙」。本次两者均已上线并各自可用。

3. 通道选型:应用发布 vs 官网自建

3.1 应用发布通道(一分钟上线)

调用站点部署能力即可完成,产物与应用卡片一一对应:

deploy(directory, language="static|node", startCmd, domainPrefix, appName)
要点实测结论
链接形态https://<slug>.app.workbuddy.host/?sharecode=XXXX(参赛表单要求的就是这种)
应用位数同一工作区仅一个应用位:换一个目录部署会覆盖原应用而非新建
多版本组织不要指望多个链接,改用站内路径:/archive/v1.html … /archive/v7.html
Node 服务端startCmd 直接写 node server.js(跳过 npm 包装,启动更快更稳)
静态资源缓存务必 ?v=N 版本化,并在服务端加 Cache-Control: no-cache

3.2 官网自建通道(TAT 远程执行)

本地无 SSH 配置,官网文件只能通过腾讯云 TAT(远程助手)写入实例:

要素值
Endpointtat.tencentcloudapi.com(API 版本 2020-10-28,写错会返回 InvalidAction)
实例lhins-laotwc5e / ap-shanghai / Username=root
落地路径/www/wwwroot/huodouai.com(Nginx 直接托管该目录)
命令长度上限约 64 KB(Content 为 base64 编码后的脚本)

4. 传输层:分块、校验与解包

整站体积 tar.gz 后约 336 KB,base64 膨胀至 454 KB,远超单命令上限,必须分块:

# 本地:打包 → base64 → 每块 40KB
tar -czf site.tar.gz kunlun projects
base64 -w0 site.tar.gz            # 454 KB

# 远端:逐块追加(顺序敏感,必须串行)
printf '%s' '<40KB chunk>' >> /tmp/site.b64
# ... 共 12 块 ...

# 远端:解码 → 解压 → 落地
base64 -d /tmp/site.b64 | gunzip | tar -xzf - -C /www/wwwroot/huodouai.com
设计要点理由
块大小 40 KBbase64(shell) 二次膨胀后仍低于 64 KB 上限
串行追加并发写同一文件会交错,base64 流损坏
传输后校验base64 -d 的 RC、gzip -t 的 RC、tar -tzf 列表,三步全绿才落地
落地前备份解压会覆盖同名文件,官网既有目录必须先备份

5. 十四个真实坑位

以下每一条都是本次实战真实撞上的,现象、根因与解法均可复现。

PITFALL 01

网关对所有路径校验 sharecode,而 HTTP 状态码仍是 200

现象
用 curl https://host/api/status 校验接口,返回的却是一段 HTML「链接不完整」页面——但状态码是 200。
根因
应用网关在所有路径上校验 sharecode,缺参数时返回拦截页而非 4xx。
解法
校验公网接口一律带上 ?sharecode=;判断「是否拿到真内容」要检查内容特征,不能只看状态码。
PITFALL 02

同一工作区只有一个应用位:部署另一个目录=覆盖原应用

现象
为「历史版本单独出一个链接」而部署 v6 目录,结果返回的仍是主应用链接,主应用被静态版覆盖。
根因
应用归属由工作区决定,与目录名无关;不存在「新建第二个应用」这一动作。
解法
放弃多链接设想,改为单域名 + 站内路径组织:/、/changelog.html、/archive/vN.html。
PITFALL 03

官方 SDK 在默认源与清华源都装不上

现象
pip install tencentcloud-sdk-python 在默认源超时无输出,清华源报 No matching distribution found。
根因
包名在部分镜像未同步;长时间静默等待比失败更危险。
解法
换阿里云源立即成功:pip install -i https://mirrors.aliyun.com/pypi/simple/ tencentcloud-sdk-python。
PITFALL 04

手写 TC3 签名被拒,官方 SDK 用同一密钥却成功

现象
自实现 TC3-HMAC-SHA256 签名,CVM 与 TAT 双服务均返回 AuthFailure.SignatureFailure。
根因
手写签名实现有细微偏差(canonical headers / scope / service 参与方式)。
解法
不要自己造云厂商的签名轮子。同一密钥换官方 SDK 立刻成功 → 说明密钥有效,问题在实现。
PITFALL 05

状态轮询不可靠:请求类字段名与响应结构都不直觉

现象
DescribeInvocationsRequest.__init__() 不接受关键字参数;响应字段是 InvocationSet 而非 Invocations;轮询 100 秒始终空。
根因
该 API 采用「构造后赋值 + 非常规字段名」的老式风格。
解法
放弃状态轮询,改为让命令自己把结果写到公网可读的位置(见 PITFALL 06)。
PITFALL 06

TAT 命令是异步调度:固定 sleep 等待不可靠

现象
12 块传输全部成功、解压命令却「没有执行」,日志里没有任何解压输出。
根因
命令进入调度队列,固定等待 16 秒并不保证已执行。
解法
命令输出统一追加到 $WEBROOT/.../_deploy.log(该路径可被公网 HTTP 读取), 部署完成后用 HTTP 回读日志校验,而不是依赖状态查询。
PITFALL 07

向既有目录投放内容,覆盖了官网原有作品

现象
解压后官网 /kunlun/ 的 index.html 变成了新作品,而该目录原本是另一套 workbench 演示的首页。
根因
投放前未查看目标目录现状;tar 解压默认覆盖同名文件。
解法
① 投放前先 ls 目标目录;② 优先使用新路径(本次改为 /workshop/kunlun-cave-heaven/); ③ 已覆盖则用 *.bak-* 备份恢复;④ 清理本次新增的残留文件。
PITFALL 08

浏览器缓存让「已部署的修复」看起来毫无效果

现象
服务端确认已更新、修复代码已上线,浏览器里行为却仍是旧的。
根因
静态资源被浏览器/中间层缓存;仅改文件内容不改 URL 不会被重新拉取。
解法
双保险:URL 加 ?v=N 版本号 + 服务端返回 Cache-Control: no-cache, must-revalidate。
PITFALL 09

DOM 契约错位:六个版本的「首屏 Demo」从未真正生效

现象
HTML 写的是 class="examples",JS 取的是 getElementById("examples") → 抛 Cannot set properties of null → 初始化中断,页面结果区空白。
根因
同一批单元测试全绿,因为它们只验证函数逻辑,从不验证 DOM 契约。
解法
① 加静态契约检查:脚本正则抽取所有 getElementById 与 HTML 的 id 求差集,缺失即失败; ② 启动路径改为同步 boot + 多重兜底,不依赖 DOMContentLoaded 与定时器。
PITFALL 10

手写 MP4 封装:音轨时间基单位错配,15 秒变 5 分 13 秒

现象
MP4 真实产出 12 MB、浏览器能解码能播,但 duration=312.89s——而设计值是 15 秒。
根因
音轨 stts 的 delta 必须是采样数(timescale=48000), 而编码器给的是微秒时间戳;直接差分填入导致单位错配 1000 倍。
解法
aDelta = round(Δμs × sampleRate / 1e6);修复后实测 duration=15.02s / 720×1280 / 11,295,572B。 关键认知:文件「能生成、能播放」不等于「文件是对的」。
PITFALL 11

超长单引号参数在远程执行环节被截断

现象
把 20 KB 的 base64 文本塞进 printf '%s' '…' 传给远端执行器:传输字节数核对正确、 base64 -d 退出码为 0,但解出来的文件「不是 gzip 格式」,解压直接失败。
根因
超长单参数在远程执行链路中被截断/变形;数据"看起来"完整(长度对得上)但内容已损坏, 属于静默数据损坏——最危险的一类。
解法
小文件改用 heredoc 直写(cat > file <<'EOF'),绕开单参数长度; 大文件仍用分块追加,但每块追加后立刻做长度与哈希校验,绝不等到最后才验证。 本次实测:heredoc 直写 26 KB 文件 → 落地字节数与本地完全一致(26308 = 26307 + 1 换行)。
PITFALL 12

服务端 coreutils 的 base64 对多行输入,行为与本地不一致

现象
分块 base64 传输后,服务端 base64 -d 退出码为 0、文件字节数与本地完全一致(83807 = 83804 + 3 个换行), 但解出来的不是 gzip(gzip: stdin: not in gzip format)。本地同样的数据解码完全正常。
根因
目标机的 base64 -d 对多行输入的处理与本地 GNU coreutils 不同(疑似只按单行处理后静默截断)。
解法
解码步骤一律不依赖目标机工具链,改用确定性的 Python: python3 -c "import base64;open('x','wb').write(base64.b64decode(open('y').read()))"。 修复后服务端解出 62852 字节,与本地 gzip 大小逐字节一致。
PITFALL 13

对上游响应的结构做「硬下标」假设

现象
代理返回 {"error":"0"},异常信息只有一个字符「0」,完全看不出问题在哪。
根因
代码写成 j.get("choices") and j[0].get(...)——把 j(dict)当序列取下标。 上游返回标准 OpenAI 结构时,j.get("choices") 是非空 list(truthy)→ 执行 j[0] → KeyError: 0。 而当上游返回不含 choices 的错误体时短路成功,反而「看起来是 200 但内容为空」。
解法
① 绝不假设上游结构:写类型安全的提取函数(_extract_reply / _extract_image),兼容 list / dict / 缺字段; ② 异常必须带 traceback 落盘——{"error":"0"} 这种「信息量为零的错误」是排查效率杀手, 加上 traceback 后 1 次定位到根因;③ 失败必须把上游原始响应体写进日志(chat empty raw=…)。
PITFALL 14

单线程 HTTP 服务扛不住并发长请求

现象
页面首屏会并发发出 1 个文本 + 5 个图像请求(每个耗时 12–20 秒),代理用标准库的 HTTPServer(单线程)→ 请求排队 → nginx 判定上游不可达 → 前端静默降级为本地规则, 界面显示「云端通道已托管」但实际生成来源是 local-rule。
根因
「通道检测」是轻量 GET,能通过;真正的生成是长耗时并发 POST,全部超时。
解法
① 改用 ThreadingHTTPServer(daemon_threads=True); ② 对上游调用加串行锁 + 429/5xx 退避重试,避免触发免费通道并发限流; ③ 验收必须看真实字段:不只看「通道状态提示」,而要断言 source=llm:… 与关键帧来源为云端。

6. 验证体系:端到端真值律

本次采用三层验证,每层都用真实环境而非推断:

层手段判据
L1 路由探针HTTP 逐条打点(含 sharecode)作品路由 13/13 = 200;既有内容回归 12/12 = 200
L2 浏览器真实打开真实 Chromium 加载公网地址首屏 Demo 真实产出:src=local-rule shots=5 frames=5
L3 产物回读<video> 解码 + 字节数读取时长 / 分辨率 / 字节数三项与设计值一致
判定标准要写死:「返回 200」不算通过,「文件能打开」不算通过, 「状态文案正常」也不算通过。必须回读到具体数值并与设计值逐项比对。

回归清单(本次实际执行)

类别条目结果
作品路由首页 / index / changelog / archive v1–v7 / 2 张截图 / 介绍页13/13 · 200
官网回归/ /product-hub /whitepaper /capabilities /achievements /developer /kunlun/* /gallery/* /projects/*12/12 · 200
应用通道首页 / changelog / archive v1–v7 / 接口 /api/agnes/status9/9 · 200
产物MP4 导出 → 解码回读15.02s · 720×1280 · 11.3MB

7. 可复用脚本骨架

7.1 一条命令的执行与回读

def fire(name, script, timeout=120):
    req = models.CreateCommandRequest()
    req.CommandName = name
    req.CommandType = "SHELL"
    req.Content = base64.b64encode(script.encode()).decode()
    req.Timeout = timeout
    cid = client.CreateCommand(req).CommandId

    inv = models.InvokeCommandRequest()
    inv.CommandId = cid
    inv.InstanceIds = [INSTANCE]
    inv.Username = "root"
    iid = client.InvokeCommand(inv).InvocationId
    return iid   # 不轮询状态,改由 HTTP 回读日志校验

7.2 分块传输与落地

def deploy(tar_path, remote_root, log_path, chunk=40000):
    b64 = base64.b64encode(open(tar_path, "rb").read()).decode()
    fire("init", f"rm -f /tmp/site.b64; : > {log_path}")
    for i in range(0, len(b64), chunk):
        fire(f"c{i}", f"printf '%s' '{b64[i:i+chunk]}' >> /tmp/site.b64")
    fire("extract",
         f"base64 -d /tmp/site.b64 | gunzip | tar -xzf - -C {remote_root}; "
         f"echo EXTRACT_RC=$? >> {log_path}")

7.3 用 HTTP 回读校验

curl -s "https://<host>/<path>/_deploy.log"   # 远端命令的真实输出

要点:让远端命令把结论写进公网可读的文件,是绕过「无状态轮询」与「异步调度不确定性」的最省事解法, 且校验路径与用户实际访问路径完全一致。

7.4 小文件直写:heredoc 优于超长单参数

# 单个 ≤ ~30KB 的文件:一条命令搞定,绕开单参数长度与 base64 二次膨胀
cat > /www/wwwroot/huodouai.com/whitepaper/report.html <<'EOF_DOC'
<!DOCTYPE html> ... </html>
EOF_DOC
wc -c < /www/wwwroot/huodouai.com/whitepaper/report.html

注意 heredoc 定界符要用带引号的形式(<<'EOF'),否则内容里的 $、反引号会被 shell 展开。

8. 时间与成本实测

阶段耗时说明
打包 + 分块< 1 s336 KB gzip → 454 KB base64 → 12 块
12 块传输≈ 3 min每块一次创建+调度,串行 16 s 间隔
解包落地≈ 20 s解码 + gunzip + tar + 校验
导航注入 + 路径纠正≈ 1 minsed 插入口 + 迁移到独立目录 + 恢复既有首页
回归验证≈ 3 min25 条 HTTP 探针 + 真实浏览器首屏校验
合计≈ 8 min全链路无人值守

可复用资产:site.tar.gz(全站快照)、deploy_to_huodouai.py(分块部署)、e2e/(可复跑的端到端脚本集)。

9. 元法则:交付即验证

本次十个坑位共同指向一条规则,已固化为最高位阶元法则并写入本体:

META-AXIOM-E2E-VERIFICATION-V1

交付物必须经真实端到端验证

公理
任何作品/应用/服务在交付前,必须在真实运行环境(真实浏览器 + 真实网络 + 真实凭据)完成端到端验证并留下可复现证据;单元测试、逻辑自检、mock 桩一律不可替代。
约束
功能只有形而无实者(出图不达风格标准、导出无音轨、密钥明文硬编码、界面与文档版本号不一致、首屏不可用)视同半成品,半成品视同未交付。
锚点指纹
e85bf6689fb8c1e96a930a96
执行细则
按钮是否 enabled、产物字节数是否非零、状态文案是否正常、时长/分辨率是否等于设计值——四者都必须真机点击确认。

该法则同时被写入核心公理集(新增第 9 组 E2E-VERIFICATION)与哈希账本,使其可被审计与复算。

10. 落地检查清单

  1. 投放前:目标目录 ls 一遍,确认不覆盖既有内容;优先选择全新路径。
  2. 传输前:确认云 SDK 可用(换镜像源);优先官方 SDK,不自造签名。
  3. 传输中:分块 ≤ 40 KB,串行追加,每块留日志。
  4. 落地时:解码 / gzip / tar 三步校验全绿再落地;先备份再覆盖。
  5. 落地后:① 作品路由逐条探针;② 既有页面全量回归;③ 真实浏览器打开首屏;④ 产物回读数值。
  6. 缓存:静态资源加版本号 + no-cache,否则「已修复」无法被验证。
  7. 导航:在官网首页与相关列表页加入口,并回读确认链接真实可达。
  8. 留痕:锁档事件写本体、哈希入账本、成果同步云端活版本。

附录 A · 命令速查

# 一、应用通道部署(Node 服务端)
deploy(directory=..., language="node", startCmd="node server.js",
      domainPrefix="<slug>", appName="...")      # → https://<slug>.app.workbuddy.host/?sharecode=XXXX

# 二、官网落盘(TAT)
base64 -w0 site.tar.gz | split -b 40000 -           # 本地分块
# 远端逐块:
printf '%s' '<chunk>' >> /tmp/site.b64
# 远端落地:
base64 -d /tmp/site.b64 | gunzip | tar -xzf - -C /www/wwwroot/huodouai.com

# 三、校验
curl -s "https://<host>/<path>?sharecode=XXXX" | head -c 200   # 判定内容而非状态码
curl -s "https://<host>/<path>/_deploy.log"                  # 回读远端命令结论

# 四、回归
for p in / /a.html /b.html; do curl -s -o /dev/null -w "%{http_code} $p\n" "https://<host>$p"; done