onesvm-browser-server/.dsh/contracts/contract-20260901-browser-impl.md
chii eb972dfa93 feat: 落地 browser-server 控制面并打通 mgr1 海外订阅
单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 15:05:12 +08:00

12 KiB
Raw Blame History

Contract: onesvm-browser-server 控制面首版实现(到「部署 mgr1 测试」就绪)

  • contract_id: contract-20260901-browser-impl
  • run_id: run-20260901-browser-impl
  • 创建: 2026-09-01(Asia/Shanghai)
  • 状态: approved
  • 复杂度: core_framework(触发 Architecture Review)
  • 用户授权: 2026-09-01 用户原话确认「按预设(D7=Go、D8=进程内适配器、D9=灰度、D10=附加 casa-net、D1=L0→L2 渐进、D3=:8640//bs-api)开实现 Contract」——D1–D10 全部按预设锁定,不再询问。

1. Goal

实现 docs 全部设计所定义的控制面三角色 Go 单仓(gateway / scheduler / proxymanager,cmd/browser-server 单二进制 role 分流),到部署 mgr1 测试的就绪态:代码 + 单测全绿 + 本机 docker compose 冒烟通过 + amd64 镜像构建 + stack.yml + 传输/部署脚本。本 Contract 不执行任何对 mgr1 的实际部署/SSH 操作(部署轮另走 🟡 确认)。

2. 权威输入(Read,全部必读)

输入 路径 用途
设计权威 docs/design-arch-20260901.md 机制细节(§2 认证/配额、§3 Dock 五方法/信封、§4 队列/背压、§5 ProxyManager/合规、§7 可观测)
决策权威 docs/plan-final-20260901.md 结论与档位(§2 排队/内存、§3 Dock/输出、§5 评分)
部署预设 docs/deploy-prod-preset-20260901.md 服务清单/端口/资源/灰度步骤(D7/D8/D9/D10 已锁)
MCP 契约 docs/mcp-usage-20260901.md 工具参数/响应形状/错误码对消费者承诺(T1 契约面)
组织规范 onesvm-dev-md/base/development-standards.md §5 urlapi、§6 镜像 tag、§7 东八区
组织规范 onesvm-dev-md/base/deployment-rules.md stack 必备字段/secret/命名
实测凭据 bench/searxng-{cn,global}/settings.yml、bench/{lightpanda,chrome-headless-shell}/compose.yml、bench/trafilatura-http/app.py、bench/site-matrix/cdp_fetch.mjs、bench/proxy/up.sh 引擎配置/CDP 最小调用面/适配器接口形状(复用声明见 §6)

3. 决策锁定(不再开放)

# 决策 值
D3 端口 gateway host :8640;反代前缀 /bs-api;scheduler :8641、proxymanager :8642、mihomo mixed :17890 仅 overlay
D7 技术栈 Go 单仓单二进制多角色(go run ./cmd/browser-server -role=…)
D8 适配器形态 scheduler 进程内 Go 模块(引擎经 overlay HTTP/CDP 调用;Dock 五方法 = 内部 interface)
D9 上线 mgr1 单节点起步,灰度扩展三节点另议
D10 联调网络 stack 附加 vlepontas-casa-net(external,alias browser-server)
D2 国外搜索 Bing-only 姿态
O9/O10 MCP 2025 腿 / 管理面 首版仅 2026 无状态 POST /mcp;管理面 CLI + SQL 先行(首版:CLI 子命令写 SQLite)
依赖 第三方库 禁重型依赖;准许 modernc.org/sqlite(纯 Go 无 CGO)、gopkg.in/yaml.v3;其余 stdlib + 手写(MCP JSON-RPC/CDP WebSocket 自实现,面窄);网络依赖须经 Go proxy 镜像拉取

4. scope(写边界)

in-scope(唯一写区):server/(新建,全部 Go 源码)、stacks/browser-server.yml、scripts/deploy-mgr1.sh、scripts/smoke-local.sh、docs/impl-20260901.md(交付记录)、.dsh/contracts/**、.dsh/artifacts/run-20260901-browser-impl/**。docs/deploy-prod-preset-20260901.md 仅允许追加「镜像 tag 约定(development-standards §6)」小节(O13 落地)。

out-of-scope:docs/ 其余文档、bench/、onesvm-dev-md/(submodule)、casa-commander/(submodule)、.dsh/casa-runtime/、README.md、AGENTS.md、任何 remote/生产操作。本仓不做 git commit(除非用户另行指示)。

5. 逐模块 Acceptance(工程级硬门槛)

A1 公共包(server/internal/)

  • contract/:统一信封/JobEnvelope/RawResult/五方法接口/错误码——与 design-arch §3.2/§3.3、mcp-usage §2/§3 字段一致;时间字段一律 +08:00。
  • store/:SQLite(modernc 纯 Go)open(WAL/busy_timeout=2s/foreign_keys=on)+ migration(schema v1:consumers/api_keys/audit/quota/jobs/dead_letters/rules)+ repository 方法面。SQL 源码内 ? 占位符、行级错误处理、无 SELECT * 糊装。
  • auth/:静态 key 校验 hmac.Equal(constant-time);密钥注入 ${VAR:?required} fail-closed;禁 os.Getenv 默认值兜底。
  • policy/:SSRF fail-closed(协议 80/443、私网/元数据 CIDR、CNAME 银行卡号段不重定向重验——重定向重验按 design §5.4 每跳重验)、域名规则 trie(direct/pool/deny)、robots(普通 key,TTL 缓存 SQLite)。
  • safetyscan/:词表文件 + 编译正则(NFKC 归一)+ PII redact + 注入包裹 delimiter;命中高危 block;wordlist_version 字段。
  • httpx/:共享 HTTP client(大小/类型守卫、超时、重定向重验 hook)。

A2 gateway

  • MCP JSON-RPC 2.0 单 handler(tools/list、tools/call,MCP 头校验/协议版本),HTTP /v1/search /v1/read,/healthz /readyz。
  • 认证 → scope → 429/402/403 → overlay POST scheduler:8641/enqueue(落盘成功才 200,scheduler 不可达 → 503+Retry-After,gateway 零落盘)。
  • 认证头仅 X-Service-Token(401 时响应头提示禁 Bearer);admin 面:X-Service-Token = admin token,POST /admin/keys(签发)、DELETE /admin/keys/{id}(吊销)。
  • 搜索响应走 gateway 进程内短 TTL 缓存(query+region 键,默认 300s,≤50 条 LRU)——消化上游 CAPTCHA(plan-final §2.4 设计结论)。

A3 scheduler

  • 队列(SQLite 单写者 + 进程内 bounded queue):enqueue 落 WAL 才 ACK;ADMIT_MAX=60(running+queued,env 可调);429/503 携带 Retry-After + running/queued 现状。
  • 派发:UPDATE … WHERE id=(SELECT …) RETURNING;租约 lease_until + reaper 收割 + attempts≤2 仅瞬时错误重试 + 死信表。
  • Dock 适配器进程内注册表:searxng-cn / searxng-global / trafilatura / lightpanda / headless-shell 五个,各自实现 contract.DockAdapter 五方法;capabilities 如 §4.4 标签。
  • 能力路由:region/render 标签匹配(region=overseas 强制走 mihomo 出口;shell_active ⇒ panda 停新 互斥,入队侧执行)。
  • 模版层(模版层整合器,S7 归属):RawResult → Size/Type guard → fit markdown(trafilatura 引擎侧已产 markdown,CDP 引擎给 text→go 差分算法转 markdown 或直接 bodyText 作正文)→ safetyscan → 信封封装;score 归一 0–1。
  • 降级链:C 满试 B、B 失败回 A(HTTP+fit),全败 blocked/upstream + warnings,不静默降质。
  • /pressure + /metrics(文本格式,design §7.2 指标面)。
  • headless-shell 按需槽:Swarm API(DOCKER_HOST=tcp://… 或 unix socket 挂载)scale 0→1,空闲 10min 回收(D8 预设;不可用时适配器返回 unhealthy,不阻塞其它通道)。

A4 proxymanager

  • 订阅解析:Clash YAML(复用 bench lib.py 逻辑的 Go 版)→ 剔除占位节点 → vless/hysteria2 分池(hy2 不调度)→ 写 mihomo provider 配置 + mihomo 热载。
  • 探活:https://www.google.com/generate_204(禁 cp.cloudflare.com HEAD);活跃 30s / 全池 5min;连续 2 失败摘除、1 成功回候选;EWMA 延迟按域名分组。
  • 轮换 P2C + sticky session(TTL map);域名路由表(direct/deny/pool)与 gateway policy 联动(共享 SQLite rules 表 + 热载)。
  • HTTP API(仅 overlay):/healthz、/api/proxies(探活状态)、/api/exit?domain=(sticky 选出口)。
  • PROXY_SUB_URLS 多订阅容灾;订阅 URL 不落盘不入 git(内存传递给 mihomo config 生成)。

A5 部署产物

  • stacks/browser-server.yml:9 服务(gateway/scheduler/proxymanager/mihomo + searxng-cn/global + trafilatura + lightpanda + backup sidecar)+ shell 按需(replicas=0,Swarm 拉起);deployment-rules §1.3 必备字段全(TZ/placement/healthcheck/limits);镜像 digest/tag 锁定;vlepontas-casa-net external 附加 alias browser-server;SQLite named volume 钉 mgr1。
  • Dockerfile 多阶段(builder golang:1.27-alpine → distroless/base 或 alpine);Makefile(build/test/lint/fmt/cross-amd64/image);scripts/deploy-mgr1.sh(save|load + stack deploy --resolve-image never + prune dangling 尾步骤)与 scripts/smoke-local.sh(compose 冒烟:起本地 compose,签发 key,curl 全链路断言)。
  • 镜像 tag 约定落地:onesvm/browser-server:dev 日常复用(O13)。

A6 质量门槛(verify/reverify 共用)

  1. go build ./...、go vet ./...、gofmt -l 空、go test ./... 全绿;关键路径单测覆盖:auth(比对常数时间/过期/吊销)、SSRF 私网判定、队列抢单原子性、词表命中、信封字段与 mcp-usage 一致性(golden test)、路由标签匹配、探活摘挂状态机。
  2. 行数:server/ 与脚本每文件 ≤600 行硬上限(组织 600 行纪律);>600 须拆分后再验收。
  3. T 系复核:T1 契约(mock 形状=真实响应形状:searxng json/trafilatura/CDP 均以 bench 实测样本为准)、T2 fail-closed(SSRF/密钥/订阅缺省)、T3 密钥(${VAR:?} fail-closed + hmac 比对 + 无默认值)、T6(租约 reaper 退避)、T7 入参边界(Pydantic→Go 等价物:入参长度/范围校验)。
  4. 本机冒烟(smoke-local.sh,可选依赖 Docker 在线):gateway/scheduler 起 + stub 引擎 → 签发 key → /v1/search /v1/read MCP+HTTP 全链路 200 + 错误路径(401/403/429/503)断言。
  5. amd64 交叉构建成功(GOOS=linux GOARCH=amd64 go build),镜像 ≤60MB 目标(distroless)。

6. 复用声明(组织纪律:能复用须标明)

| 复用物 | 来源 | 去向 | |---|---|--- A2 | | searxng 引擎配置(cn 四引擎 / global Bing-only 姿态) | bench/searxng-{cn,global}/settings.yml | stack 内嵌同参数 settings(按 Swarm 语法适配) | | trafilatura 服务(POST /v1/read、SSRF 守卫、semaphore=8) | bench/trafilatura-http/app.py(镜像已构建 bench-s3b-trafilatura:local) | stack 的 trafilatura 服务 = 同一代码构建,镜像 tag onesvm/trafilatura-http:dev | | CDP 最小调用面(json/version → ws → Target.create/attach → Page/Runtime/Network enable → navigate → evaluate 提取) | bench/site-matrix/cdp_fetch.mjs | lightpanda/headless-shell 适配器 CDP 客户端(Go 重写,面窄) | | Clash 订阅解析/占位节点剔除/区域归类逻辑 | bench/proxy/lib.py | proxymanager 订阅解析(Go 移植) | | 反爬特征检测正则(cloudflare/waf/captcha 判定) | bench/site-matrix/cdp_fetch.mjs detectVendor | 模版层 blocked 判定 | | compose 参数(镜像 digest pin、shm、proxy env) | bench/*/compose.yml | stack yml 引擎服务 |

7. 工件流(artifact_io)

Worker 交付物一律落 .dsh/artifacts/run-20260901-browser-impl/:

产物 路径
实现回执(builder 自验收) impl-receipt.md
verify(首轮独立验收) verify.md
reverify(复核 + 迭代修复记录) reverify.md
架构审查(core_framework 强制) arch-review.md
冒烟原始输出 smoke/
行数检查输出 wc.txt

7bis. 通信纪律(CASA 铁律)

  • Worker 之间/Worker→指挥官:只传产物路径 + diff 摘要,禁「如上所述」传话。
  • Worker 不得最终自评 PASS——builder ≠ judge;verify/reverify 由独立只读 Worker 执行。
  • 指挥官主会话禁写业务文件(server/、stacks/、scripts/);仅契约/工件/收口文档。

8. 失败与迭代

任一 acceptance 不满足 → verify Worker 出 fail-*.md(列证据 file:line)→ 指挥官派迭代 Worker 只注入 fail artifact + 本 Contract 修复;最多 3 轮(policy.max_iterations=3),仍败则升级用户。

9. 部署边界(红线)

本轮不 SSH mgr1、不 stack deploy、不 push remote。scripts/deploy-mgr1.sh 只写脚本不执行。部署轮另走 🟡 前置确认(mgr1 free -g / ss -tln / 影响面报告)。

10. 时间与语言

  • 全部时间字段 Asia/Shanghai +08:00(development-standards §7);容器 TZ=Asia/Shanghai。
  • 代码注释/交付文档简体中文,标识符英文。