
很感谢老师们在我每次对接时的及时回应、以及可爱的同学们在每个阶段任务中的积极配合
一、管理者身份
在学习了"项目管理"课程中的"学习型组织"概念后,结合我对 Harness 开发范式的理解,我毛遂自荐想担任组长一职,也很荣幸能被大家选上
下面我从人力分配 以及仓库管理两个维度介绍我作为管理者的工作
1、宏观规划
首先我作为组长,不仅要做好老师们、同学们的沟通工作,同时要时时刻刻对项目的进展进行宏观把握
1.1、人员调度

考虑到咱们项目场景是异地多人协同开发,我直接选择利用 Github 作为协作基建,节省前期基建的时间
在开发范式上我采用 Google Chunk 小粒度主干协作:首先我会将 PRD 作为宏任务进行拆解,每个阶段又可以划分很多微任务,按照拓扑排序确保每个 issue 的前序工作都已经完成,每位同学认领任务后,从 main 拉出短生命周期分支或 fork 分支开发,通过小 PR、CR、质量闸门、维护者确认和 squash merge 回到 main。仓库不采用 Git Flow、GitHub Flow 或 GitLab Flow 作为主流程,详细原因可以查看决策记录贴 discussions/70
接着每个同学在认领到任务后在他们自己的 fork 仓库进行开发,并在开发后往主仓库发起 PR ,非 PR 作者的 CR 人员在 CR 以及下面 2.1 会介绍的 ceilf6/repo-guard CR通过后才能合入。过程中为了同大家明确 CR 标准,沉淀了文档 Code Review 说明
考虑到如何提高同学们的积极性,我会根据任务的工作量给 issue 打上 score label 分数标签,并利用 CICD 工作流 workflows 进行维护管理,具体可以查看仓库中的 progress.md 和 progress.json 文件;同时我也会为每个 issue 打上 stack 技术栈标签,确保能够兼顾到每位同学他们擅长的以及他们想做的,否则如果有同学认领到了他不想做的任务会导致交付质量和同学积极性都很低
以上所有工作流程我都已经沉淀在文档规范工作流流程方便大家随时查阅
1.2、敏捷开发

在同老师们确认了项目时间周期只有 2 周后,我决策进行敏捷开发,即分阶段批次发派任务,并在每个阶段结束后立即发包、及时同 PM 等各位老师进行确认产品是否偏离,从而明确项目走向是否正确
接着我进行了技术模块的分析,构写了技术模块拆解,并根据模块拆解文档进行了初步的时间规划,撰写了时间规划(这些文档都沉淀到了项目的 docs/ 目录下,方便需要时给予 Agent 完整上下文)
最终明确了一条主链路:竞品信息调研 -> 技术方案敲定、模块拆分 -> 录制链路 -> 回放链路 -> 加分项
在我看来,软件工程敏捷开发的本质就是从实现 MVP 后不断进行矫正、完善成为一个真正的产品,这一点可以从咱们的发包进程看出:https://github.com/ceilf6/code-tape/releases
确保了在新增功能出现异常后能够及时回滚到上一个稳定版本
1.3、FrontAgent + Skills

同时为了方便团队同步进度和风向,我将我的个人代理 FrontAtAgent 接入了飞书开放者平台后导入群聊中,作为群助手辅助大家工作,并用 ceilf6-skills/skill-lifecycle 创建了工作进度汇报技能 progress-reporter (前面链接的项目都是我之前日常开发、维护的,没有占用工训营过程中的时间,开箱即用了)
那么每天早上 10 点群助手 FrontAgent 就会执行 /progress-reporter cron 定时任务向老师和同学们同步当前项目进展、假如有预警也能及时提醒
1.4、技术选型与敲定方案
在有技术模块拆解后,如果没有确定模块间的边界与字段交互那么大家开发起来仍然是云里雾里
于是在第一阶段也就是竞品信息收集、产出了文档竞品分析之后,我利用仓库的 discussions(详情可以查看 附录 B)同大家进行了技术栈的选型与最终技术方案的敲定,确保了决策信息的可回溯、沉淀进入项目的知识库(这一点会在下面 Harness 工程中提到)

最终得到了文档技术方案,他是项目的开发基准,我在仓库基建 - 工程提示词中是这么强调的
plain
# 文档
1. docs/PRD.md 文档的权威性是最高的
2. 提交的代码不准背离 docs/技术方案.md 。若认为技术方案有任何错误,应通过 discussion 及时上报仓库维护者
2、仓库 Harness 工程
在学习了 https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents、https://openai.com/index/harness-engineering/、https://ghuntley.com/loop/ 等文章后,我认为,过往像 skill, MCP 等基本都是对模型前序输入进行控制,而现在 Harness 本质是带上了对模型输出的管控,并再次反馈给输入,从而形成一个良性循环
这点在 Claude Code 源码的工程化中也有所体现,我也曾对此做过博客分享 https://blog.csdn.net/2301_78856868/article/details/159995844
2.1、repo-guard
这是我之前闲来无事时开发的,没想到在这次项目中起到了这么大的作用,在咱们百余个 PR 中发表评论 300+ ,采纳率超 95%


同时我用我的 github pro 账号和 gpt plus 账号为仓库开启了 copilot 和 codex 的 CR,这三重保障、对抗式 CR 确保每一份合入代码的高质量
同时我在工程提示词中强调
markdown
# 工作
1. 每次开始任务前必须运行 `npm run quality:predev`
2. 在改代码前必须先运行 `npm run agent:bootstrap`
3. 创建分支以 feature/ , fix/ 或 chore/ 开头
4. 使用 Karpathy Guidelines 技能确保代码改动的高质量、精确性
5. 前端 UI 设计使用 frontend-design 技能
6. 启动本地 web dev server 必须用 `npm run dev`
7. 在改动后必须阅读 GitNexus 的建议
8. 发起 PR ,然后等待 GitHub Actions 运行(不用理会"需要CR通过"的错误,这是正常的)、repo-guard 和 codex 以及 Copilot 的评论后进行审查
这样能确保代理不是说在完成任务之后就直接结束,而是会等待 repo-guard、codex、copilot 等评审的意见并继续完善、然后继续等待下一次评审这样的循环
像 Agent 循环的中断条件是 LLM 不再 tool_call ,咱们 PR + CR 良性循环的中断条件就是所有评审对本次任务关联 issue 以及每次更新 diff 和整个 PR 完整上下文不再有 bug comment
其中 repo-guard 的 CR 技能使用的是我之前开发的 ++ceilf6-skills/code-reviewer++
2.2、知识库
我对项目 Harness Wiki 知识库构建初次选定了 GitNexus 和 OpenViking 两个工具。前者反馈每次代码改动的级联反应、辅助 CICD 把控整体质量;后者为开发代理提供仓库的渐进式上下文和持久化记忆
但是由于 OpenViking 需要挂载服务,还需要和组员们沟通使用方式,考虑到人员和时间的因素,不适合本项目快速交付的需要故而取消其候选资格
于是目前仓库中接入了 GitNexus ,其通过启动 MCP server 为开发 Agent 暴露了一系列的工具进行探测当前代码开发改动是否会影响项目的整体性,具体可以查看沉淀文档知识库
2.3、Git hooks
在我进行仓库工程基建时,沉淀了很多确保质量的脚本

其中就包括 .githooks/ 目录下的 pre-commit 和 pre-push ,他们分别是在代码的提交和代码的推送前要求大模型执行的
-
npm run quality:precommit覆盖了仓库测试、Web lint、Web 单测和构建 -
npm run quality:local要求刷新 GitNexus 索引并执行完整本地质量闸门
2.4、SDD
这部分和前面文档沉淀有所重叠,因为规范驱动开发的本质就是通过规范让大模型能在预期范围进行预期的改动,所以主要就是体现在通过 PRD 和技术方案等基建知识为大模型活动确定了规范
同时开发中还使用 /using-superpowers 等 spec Skills 配合 OpenSpec-cli 工具确保模型的执行是真正考虑到了方方面面(头脑风暴等技能)、同时也是符合开发者意愿的(收尾等技能)
2.5、TDD
本仓库中已经沉淀有几百个测试文件,就是 Agents 在开发过程中通过不断 红灯->绿灯->重构 并配合 Karpathy-Guidelines 技能确保了代码改动的高质量、精确性
这些测试文件还会在上面提到的 githooks 中运行,保证了当前的改动不会影响之前的功能(敏捷开发的增量性)
二、开发者身份
无论是从 progress.md 还是仓库的 Insignts 都可以看出,我作为一名工程师、开发者自从项目的基建到业务迭代、产品功能拓展我都是极其深度的参与了
1、P0 MVP 基础功能
效果演示:
P0 阶段我最核心的目标不是做一个普通代码编辑器,而是验证 PRD 中"代码讲解可以被结构化录制并交互回放"这条主链路。根据技术方案,我将 P0 收敛为"事件流优先、音视频辅助、iframe 沙箱展示、本地录制包优先"的实现路径,优先保证 Demo 可以完整展示:录制者写代码、运行代码、讲解、开关摄像头与麦克风,结束后生成录制包;观看者再通过播放器按时间轴还原代码变化、鼠标轨迹、光标选区、快捷键、运行结果和摄像头画面。
1.1、编辑器与运行沙箱
我首先完成了 Monaco Editor 的基础集成,使项目从静态 scaffold 进入真正可编辑、可录制的代码工作台。编辑器支持 JS / TS 语法高亮、基础补全、语言切换、字号与主题等基础设置,并为后续内容变更、选区、快捷键等事件采集提供稳定入口。
代码运行没有选择高风险的后端容器沙箱,而是按 PRD "前端代码页面展示"路线,采用 iframe sandbox + postMessage 的前端运行方案。这样既能满足 P0 展示运行结果的要求,也避免在两周周期内把主链路拖入 Docker 隔离、多语言执行、npm 依赖等复杂问题。
其中像 HTML, CSS, JS/TS 语言分别对应了 iframe 的 <body>, <style>, <script>
对应落地:
-
#55 Monaco CodeEditor 基础集成
-
#56 RuntimeProducer 实装:运行事件写入事件流
1.2、结构化录制链路
P0 最关键的技术点是:录制的不是视频,而是带时间戳的事件流。因此我围绕 RecordingClock、EventBus、RecordingController 和 PackageBuilder 搭建了录制事实源,把编辑器内容、光标选区、滚动、鼠标轨迹、快捷键、运行结果、媒体状态统一写入录制事件。
录制总控支持开始、暂停、继续、停止,并在录制过程中显示时长。媒体部分通过浏览器 MediaStream / MediaRecorder 采集麦克风和摄像头,并提供摄像头悬浮预览、开关与权限提示。录制结束后,系统会生成包含 meta、events、snapshots、media、manifest 的本地录制包,并优先保存到 IndexedDB,同时提供导入导出和 quota 兜底能力,保证 Demo 现场即使存储失败也有降级路径。
对应落地:
-
#57 RecorderControls 录制控制条 UI
-
#60 CameraPreview 悬浮预览 UI
-
#65 editorProducer:内容/选区/滚动/语言事件采集
-
#66 pointerProducer + shortcutProducer
-
#67 mediaProducer:媒体开关、权限告警与摄像头位置事件
-
#77 录制保存 quota 预检与 ZIP 兜底提示
1.3、交互式回放链路
回放部分围绕 ReplayScheduler 和 ReplayReducer 实现。播放器不重新执行历史代码,而是读取录制包中的事件、快照和历史运行结果,通过统一时间轴恢复任意时间点的稳定状态。
最终回放页支持播放、暂停、继续、倍速、进度条 seek、音量调节和静音;画面上可以同步还原编辑器内容变化、鼠标激光笔、光标选区、快捷键浮层、运行输出和摄像头视频。这个结果正好对应 PRD 中"像看直播回放一样还原讲解者完整操作过程"的核心体验。
对应落地:
-
#58 ReplayControls 播放控制条基础交互
-
#59 RecordingLibraryPage 列表 UI 与导入导出入口
-
#76 ReplayScheduler 接入媒体主时钟与 buffering 状态
-
#79 回放缺失媒体降级提示与纯事件流体验
1.4、端到端验收与质量保障
为了避免 P0 只是模块可用、但主链路不可演示,我补齐了录制到回放的 Playwright e2e,用真实浏览器路径验证"开始录制 -> 写代码 -> 运行 -> 停止 -> 保存 -> 进入回放 -> 播放/seek"的闭环。同时,仓库中围绕 editorProducer、pointerProducer、shortcutProducer、mediaProducer、packageBuilder、recordingStore、ReplayScheduler、ReplayControls 等核心模块建立了单测和集成测试,确保事件流、录制包、回放调度这些高风险部分不是靠手测维持。
对应落地:
-
#78 录制到回放主链路 Playwright e2e
-
apps/web 下已有 62 个测试文件,其中包括 3 个 e2e spec
P0 阶段的结果是:项目已经从"方案和组件集合"推进到"可展示的代码讲解录制回放 Demo"。这条链路也为后续 P1 云端回放中心、P1+ WebRTC 实时面试和 AI 字幕留下了扩展点。
2、云端
总控 issue: #92
效果演示:
在 P0 主链路完成后,我开始推进 P1 云端回放中心。PRD 对云端的要求是:录制完成后可上传至后端,支持列表查看、在线播放、删除和重命名;技术方案进一步明确云端不重新定义录制格式,而是以本地 RecordingPackageV1 为事实源,服务端只负责上传、校验、存储、索引、播放描述、分享和删除生命周期。
因此我在云端部分坚持一个边界:云端不是另起一套播放器,也不是重新执行用户历史代码,而是复用 P0 已经验证过的事件流、快照、运行结果和回放调度器。这样可以保证本地回放和云端回放在同一时间点恢复出的编辑器状态一致。
2.1、身份认证
当前 Demo 阶段没有引入完整企业登录体系,而是采用 x-owner-token 做"我的录制"隔离。这个 token 会在前端本地持久化,创建上传会话、查询列表、重命名、删除和生成分享链接时都会携带它;服务端按 owner token 过滤录制,非 owner 访问会返回 404,避免暴露其他人的录制存在性。
这部分后续可以替换为企业登录或账号体系,但我没有把登录前置为云端主链路依赖,原因是 P1 的核心验收是云端回放中心,而不是完整账号权限平台。
2.2、云端上传与状态机
云端上传采用 upload session 模型:前端先把本地录制包拆成 manifest、meta、events、snapshots、indexes、media 等资产,逐个计算 sha256,再创建上传会话并上传到对象存储。上传完成后调用 complete,服务端进入 processing 状态,由 validation worker 校验 schema、duration、checksum、媒体大小和事件数量,校验通过后录制进入 ready 状态。
本地包 manifest 和服务端 validation worker 都按共享 schema 的 sha256Blob 算法计算,确保"前端声明的录制资产"和"服务端实际收到的录制资产"可以被稳定比对。
这套设计解决了两个问题:
-
上传大媒体文件时,API 进程不需要直接吞吐完整 Blob,后续可以自然演进到 S3 兼容对象存储和 multipart 上传。
-
云端不会接收损坏包或超预算包,checksum mismatch、schema 错误、媒体超限都会进入 failed,不会污染用户的云端列表。
对应落地:
-
#94 Upload Session complete HTTP API
-
#96 本地开发对象存储 HTTP 适配层
-
#97 云端录制包预算校验与缺媒体降级
-
#117 CloudRecordingRepository 上传与状态轮询
2.3、云端列表、播放、分享与删除
云端列表支持查看 ready 录制,展示标题、时长、创建时间、语言、音视频能力等信息。播放时前端通过 playback descriptor 获取 events、snapshots、media、indexes 等资产 URL,再交给 CloudPackageLoader 加载,最终仍然复用本地 ReplayScheduler 播放。因此云端播放页可以继续支持播放、暂停、倍速、seek、音量和静音。
在此基础上,我继续补齐了重命名、软删除和时间点分享链接:
-
重命名只更新云端 metadata,不重写对象存储中的录制包资产,避免大对象无意义改写。
-
删除采用 soft delete,删除后列表不可见、播放不可访问、分享链接失效,后续再由清理任务删除对象资产。
-
分享链接支持
?t=时间点定位,适合把讲解中的关键片段直接发给别人复盘。
对应落地:
-
#95 云端录制状态与列表 API
-
#118 云端播放描述 API
-
#119 云端录制重命名与软删除 API
-
#147 CloudPackageLoader 云端录制包加载
-
#158 云端播放页接入
-
#166 云端回放中心页面入口与本地上传
-
#169 时间点分享链接 API 与播放入口
2.4、部署服务器
在 https://render.com/ 中新建了 Web Service,连接 GitHub 仓库 ceilf6/code-tape,然后配置构建和开始命令以及 Node 版本为 20 ,最后进行部署


最后得到线上部署地址 https://code-tape.onrender.com/
验证请求:
plain
curl -i https://code-tape.onrender.com/api/recordings \
-H 'x-owner-token: demo-owner'
响应:
yaml
HTTP/2 200
date: Sat, 30 May 2026 08:32:09 GMT
content-type: application/json
cf-cache-status: DYNAMIC
rndr-id: 9036d191-f083-4412
server: cloudflare
vary: Accept-Encoding
x-render-origin-server: Render
x-request-id: 18252308-b0a2-4cfc-be26-7110df9da65a
cf-ray: a03c62fab9d294fc-LHR
alt-svc: h3=":443"; ma=86400
{"items":[],"nextCursor":null}
3、AI 本地字幕
效果演示:
我自学过神经网络、机器学习相关内容,之前也进行过前端侧专业知识模型微调 https://hf.co/collections/ceilf6/frontagent-frontend-engineering-agent
所以对这部分还是比较熟悉的,我初步拟定流程:音频 Blob -> @huggingface/transformers -> 下载 Whisper/ONNX 模型 -> 浏览器本地 WASM/ONNX runtime 推理(其中微调 LLM 做 ASR 后处理,不替代 Whisper 转写)
这部分我认为的技术难点主要在于模型输出的稳定性以及性能
3.1、LLM 微调
考虑到信息的安全,AI 在本地也就是用户浏览器上运行,但是发现由于浏览器环境限制,导致 LLM 的参数不能很大,所以我就想着能不能通过用大模型进行蒸馏、配合前端语料进微调提高模型对咱们项目场景的适配度、从而提高输出质量
其中蒸馏数据生成器从 seed 样本调用 teacher API,产出 SFT JSONL
在自测过程中发现"字幕生成"部分用的 https://huggingface.co/onnx-community/whisper-tiny ASR 模型准确率可以达到 90%
但后续"纠错并生成章节"这一步用到的 LLM,我按照预想的用 gpt-5.5 蒸馏、并结合前端相关语料进行微调训练拿到了适配咱们项目的 ONNX 模型
https://hf.co/collections/ceilf6/code-tape
不过我跑了一晚上的语料生成和训练优化,早上测试后发现,"纠错并生成章节"的实际效果还是不太理想,尤其是在
-
章节划分和语义纠错的稳定性
-
加载模型权重需要很长时间(我试过直接把模型直接打入 JS bundle 发现首屏响应时间长的离谱捂脸)
-
现在 LLM 已经放进 Web Worker,但 WASM/WebGPU 仍会吃 CPU/GPU/内存带宽,会和视频解码、浏览器渲染抢资源
于是我想到问题可能不出在微调训练语料上,可能还在 schema 约定上。我排查了一轮后发现输入和输出都叫 segments,但输入段带 startMs/endMs/text,输出段只能是 id/text。小模型容易直接复制输入 schema,所以会出现缺 text、带 startMs/endMs 的坏 JSON。所以我后面把训练和运行时的输入字段改成 inputSegments,让输出专用 segments,得到新的一版 v6 在同一组 30 个真实生成探针上达到了 30/30 可解析 JSON,而前一版 v5 只有 24/30
3.2、LLM 增量支持
在本地 LLM 能跑通后,我又遇到了一个很现实的问题:ASR 字幕生成比较稳定,但是"纠错 + 章节生成"这一步很容易因为浏览器本地模型太小、token 预算太紧、WASM/WebGPU 抢资源而超时或输出坏 JSON。
所以我没有直接推翻本地模型路线,而是做了一个增量方案:外部大模型优先,本地微调模型兜底。
如果用户没有配置外部大模型,就继续走本地模型;如果配置了 OpenAI 兼容接口或 Anthropic,就优先请求外部模型,用更强的提示词完成术语纠错和章节生成;如果外部请求失败、超时、返回非法 JSON,或者接口不支持浏览器跨域,就自动回退本地模型,保证字幕和回放不会被中断。
因为模型请求里带了 Authorization、x-api-key、content-type: application/json 这类非简单请求头,所以浏览器命中了 CORS 同源策略,会先发预请求 preflight,只有目标接口允许跨域,页面才能拿到结果。所以我在页面中强调了需要 "填支持浏览器跨域(CORS)的请求地址"
目前我把 Key 只保存在用户本机 localStorage,不写进仓库、不打进 bundle、不发给 code-tape 后端;HTTP 错误也不读取响应体,避免错误配置的网关把 Key 或字幕上下文回显出来。
对应落地:
-
#227 字幕 LLM 后处理:支持外部大模型接入 + 本地模型兜底
-
SubtitleLlmConfigButton:配置 OpenAI 兼容 / Anthropic、Base URL、API Key、Model -
externalLlmSubtitlePostProcessor:按 provider 生成请求,统一输出segments / chaptersJSON -
fallbackSubtitlePostProcessor:外部请求非取消类失败时自动回退本地模型
3.3、ASR 输出语言
ASR 调用 onnx-community/whisper-tiny 时,如果不显式指定语言,模型很容易把中文讲解识别成英文或拼音,尤其是中英混合的代码术语场景。
所以我后面把 ASR 参数固定为 task: "transcribe" 和 language: "chinese",先让 Whisper 明确按照中文讲解去转写;React、TypeScript、useState 这类代码术语,再交给后面的 LLM 后处理修正。这样分工会更稳定:ASR 负责带时间戳的原始字幕,LLM 负责术语纠错和章节。



3.4、模型托管
在让朋友测试时又发现一个问题:不是每个人的网络都能稳定访问 Hugging Face(需要🪜),模型权重拉不下来,字幕功能就直接卡在加载阶段。
于是我把默认 ASR / LLM 模型资产通过 npm run subtitle:vendor 拉到 apps/web/public/ 下,让线上页面优先从同源静态资源加载。这样一方面绕开了 huggingface.co 网络不稳定的问题,另一方面同源加载也不会再被浏览器 CORS 卡住。构建前还有 verify-vendored-assets 检查,避免模型文件缺失时直接发版。
对应落地:
-
#226 AI 字幕生成报错:huggingface.co 模型下载连接超时
-
scripts/subtitle-llm/vendor-models.mjs:把模型资产 vendor 到前端 public 目录
3.5、产品体验优化

感谢 PM 喻宙老师的建议,这里我把字幕能力从"多个技术按钮"收敛成了一个主按钮:用户只需要点击一次,系统先跑 ASR,并且马上把原始字幕展示出来;随后后台继续跑 LLM 纠错和章节生成,成功后自动二刷字幕和章节。
这样即使 LLM 慢或者失败,用户至少已经有可看的字幕;而且字幕行和章节都可以点击 seek,最终还是回到项目最核心的交互式回放体验上。
对应落地:

4、前端沙箱隔离
PRD 里代码执行给了两条路线:后端沙箱执行,或者前端页面展示。考虑到两周周期和 Demo 风险,我选择了 iframe sandbox 前端展示路线,而不是一开始就做 Docker / V8 isolate 这种重型后端沙箱。
这里的边界我认为必须讲清楚:P0 的 iframe sandbox 是教学 Demo 级运行预览,不是完整的不可信代码安全沙箱。所以我做的是"尽可能隔离 + 明确兜底":
-
iframe 只开
allow-scripts,不加allow-same-origin,避免用户代码拿到宿主同源能力 -
每次运行都创建新的 iframe 和随机
runId,旧 runtime 必须销毁 -
子 iframe 虽然只能
postMessage(..., "*"),但父页面必须校验event.source、runId和消息 schema -
console 输出、error message、previewHtml 都做长度限制,避免运行结果把页面撑爆
-
运行超时后销毁 iframe,写入
run-error,回放时只展示历史结果,不默认重新执行用户代码
其中 DoS 是前端沙箱最难完全解决的问题:如果用户代码是同步死循环,可能会卡住同一个渲染进程,父页面的 3s timeout 也不一定能及时执行。所以我没有把它包装成"安全沙箱",而是在技术方案里明确 P0 依赖刷新恢复,后续如果要产品化,再考虑 Worker、独立 origin iframe 或后端容器隔离。
对应落地:
5、WebRTC 实时面试
总控 issue #120
效果演示:
WebRTC 这部分我没有把它做成"多人协同编辑",而是严格收敛成 PRD 里的实时面试模式:候选人是唯一写入者,面试官只是实时只读观察者。这样就不需要引入 CRDT / OT,也不会把项目复杂度拉到协同 IDE。
整体链路是:候选人创建面试房间,后端用 WebSocket 做信令,双方交换 SDP / ICE 后建立 WebRTC;音视频走 WebRTC media track,编辑器事件走 RTCDataChannel。WebSocket 在这里不是承载持续代码事件的主通道,而是负责建连、房间状态和控制消息。
为了复用 P0 主链路,我让候选人端继续使用原来的 RecordingController、EventBus 和 PackageBuilder。InterviewSyncPublisher 只订阅已经产生的录制事件并转发给面试官,不自己改时间戳、不改 seq;面试官端则复用 ReplayReducer / ReplayStableState 渲染只读工作台,确保"实时看到的状态"和"回放看到的状态"用的是同一套解释逻辑。
网络抖动这块我做了一个小型的 `RemoteTimelineBuffer`:面试官端不按本地到达时间直接渲染,而是按候选人事件的 `seq` 和 `timestampMs` 做小延迟播放;如果发现 seq 缺口、hash 不一致,就请求候选人发送最新 snapshot,再从 snapshot 之后继续重放事件。这个设计的核心就是:单写者 seq + 小延迟缓冲 + 周期快照 + hash 校验。
对应落地:
-
#126 面试房间与 WebSocket 信令
-
#139 RTCDataChannel 实时事件同步核心
-
#141 面试官只读工作台状态核心
-
#146 双向音视频通话基础核心
-
#202 抖动缓冲、快照重同步与 hash 校验端到端接线
附录 A:周会文档
附录 B:决策记录文档
| ADR | 决策 | 对本次周会的意义 |
|---|---|---|
| ADR-001 | P0 代码执行路线采用 iframe sandbox 前端展示 | 支撑"不做后端沙箱"的解释 |
| ADR-002 | P0 TypeScript 必达编辑回放,简单运行作为可选 PoC | 支撑"TS 执行不作为主验收" |
| ADR-003 | P0 录制包使用 IndexedDB,本地文件导出兜底 | 支撑本地保存闭环 |
| ADR-004 | P0 音视频使用单 WebM 轨,录制前选择设备 | 支撑媒体同步降复杂度 |
| ADR-005 | Python 仅作为 P0 可选加分,不阻塞主链路 | 支撑加分项优先级 |
| ADR-006 | 前端框架采用 Vite + React + TypeScript | 支撑工程技术栈 |
| ADR-007 | 编辑器采用 Monaco Editor | 支撑编辑器选型 |
| ADR-008 | 状态管理优先 React hooks 与 reducer | 支撑不引入重型状态库 |
| ADR-009 | UI 采用工具型工作台,P0 默认深色 | 支撑 Demo 视觉方向 |
| ADR-010 | P0 内容变更事件保存完整代码快照 | 支撑 seek 简化 |
| ADR-011 | seek 采用 inclusive 快照加增量事件静默重放 | 支撑回放核心策略 |
| ADR-012 | 测试栈采用 Vitest、Testing Library 与 Playwright | 支撑质量策略 |
| ADR-013 | 回放展示历史运行结果,不默认重新执行代码 | 支撑回放确定性和安全 |
| ADR-014 | WebContainers 延后到 P1 PoC | 支撑 P0 不做完整浏览器 IDE |
| ADR-015 | 后端 Docker 沙箱延后 | 支撑 P0 不做后端执行 |
| ADR-016 | 终端录制延后 | 支撑 P0 聚焦编辑器事件 |
| ADR-017 | 多文件工程运行延后 | 支撑单文件/简单前端展示 |
| ADR-018 | WebRTC 实时面试延后到 P1+ | 支撑加分项延后 |
| ADR-019 | AI 字幕延后到 P1+ 并分级实现 | 支撑字幕不抢 P0 |
| ADR-020 | 账号权限与云端分享延后到 P1 | 支撑本地 Demo |
| ADR-021 | 录制包必须包含 manifest、checksum、校验和迁移入口 | 支撑录制包可靠性 |
| ADR-022 | P0 暂停期间锁定影响回放状态的输入 | 支撑暂停/继续语义 |
| ADR-023 | 回放媒体通过 MediaClockAdapter 映射到事实时间轴 | 支撑音视频同步 |
| ADR-024 | iframe runtime 必须校验 source、runId、消息 schema 并设置超时 | 支撑运行安全边界 |
| ADR-025 | P0 主演示环境锁定桌面 Chrome/Edge latest 并设量化预算 | 支撑 Demo 可控性 |