WACX Time Estimation(任务时间预估 · 通用)
Overview
通用任务时间管理技能,覆盖两类需求:
- 完成时间预估(ETA):根据「当前推进情况」估算任务 / 项目 / 里程碑的完成时间,输出带置信区间的完成窗口与风险清单。
- 超期即停与归因:监测单个任务的执行时长,一旦实际用时超过预估(默认超支 50%,可配置),立即停止该任务,并给出延迟原因与改进建议。
适用范围:任何由任务列表(TaskList)跟踪的工作——写代码、写文档、设计、调研、运维、家务、学习等,不限于写作。工作单元可为任务数、章节、PR、工单、页面、字数等任意可计数的单元。
本技能不靠拍脑袋:进度来自任务列表(及其时间戳),速度 / 时长由任务列表与用户口述推导,区间与超期判定由确定性脚本计算;归因必须基于真实观察,不编造。
触发语
- 预估类:「还要多久」「预估完成时间」「什么时候能完」「ETA」「这项目几号能做完」。
- 超期类:「超时了」「怎么这么慢」「为什么还没好」「超期归因」「给个改进建议」「这任务卡太久了吧」;或代理在执行某任务且发现实际用时远超预估时主动触发。
Part A — 完成时间预估(ETA)
Step 0 — 加载校准(首加载提示 / 二次起科学化)
每次进入 Part A,先调用校准引擎读取本项目的累积数据。务必带上 --mode 与 --task-type,校准按 (mode, task_type) 分桶存储与读取:
python <skill>/scripts/calibrate.py load \
--workspace "<当前工作区路径>" \
--mode agent \
--task-type "写小说章节(含九维审阅迭代)"
返回字段:
- is_first_run(bool):本项目第一次加载本技能时为 true。
- disclaimer:仅首次为 “预估时间为凭经验判断,可能不准确。”——必须原样向用户提示,不得省略。
- bucket / bucket_active:当前 (mode, task_type) 桶;bucket_active=false 表示该桶尚无实测。
- calibration_factor:该桶历史「实际/预估」比值的中位数;记录实际数据后才会偏离 1.0。
- confidence / uncertainty_band_pct:该桶棘轮值(见下方「棘轮机制」)。
- sample_count:该桶已记录的实际样本数(global_sample_count 为全桶合计)。
首加载(is_first_run=true):用默认 calibration_factor=1.0、宽不确定带出经验预估,并显式提示 disclaimer。
第二次及以后(is_first_run=false):用该桶 calibration_factor 与棘轮不确定带计算——这是基于之前同桶任务实测数据得出的科学化预估;若 bucket_active=false(该桶尚未记录任何实际用时),则如实说明“本类任务尚未积累实际数据,校准未激活,仍用经验初值”,提示任务完成后用 track-stop 回写实际(见 Step 6)。
Step 1 — 界定范围与单元
明确被预估的对象与「工作单元」:
- 单元示例:任务数、章节、PR、工单、文档页数、代码模块、字数等,按实际工作选最自然的计数方式。
- 若是整个项目 / 里程碑,先确认总量(如“共 48 个任务”“10 个页面”)。
若范围模糊,先向用户确认「要预估什么、总量多少」,不要默认假设。
> 强制门禁(范围未界定前不得算):在拿到「总量 + 已完成(或剩余)」之前,不得调用 estimate.py / eta_calc.py。若用户尚未给出,先发一句确认(可复用模板):
> 「为了给你准确的预估,请确认两点:① 这个任务总共多少 [单元]?② 已经完成了多少?」
> 拿到回复后再算。严禁拿臆造的 total / unit 直接跑计算器——那会产出看似精确、实则无依据的假数字。
> 脚本级硬门禁:estimate.py 现在强制要求显式 --unit 且 --total/--done(或 --remaining)有效(total>0、done<total、remaining>0),否则直接报错退出,无法绕过。
Step 2 — 采集进度
按优先级取真实数据(禁止编造,且不读取任何私人文件):
- 任务列表:调用
TaskList获取全部任务,统计completed/in_progress/pending,以及blockedBy依赖。首选进度来源。 - 任务时间戳:若任务带创建 / 完成时间戳,用已完成任务的跨度推算平均节奏(仅用时间戳,不读私人记忆 / 文档)。
- 用户直给:以上不足时,直接询问剩余量、已用时长与速度,不要去读取私人记忆或文档。
记录:总量、已完成、剩余、被阻塞的任务清单。
Step 3 — 推导速度(velocity)
速度 = 每有效工时的产出单元数。来源优先级:
1. 速度预设(agent 任务首选):调用 eta_calc.py --preset "<类型>" 从内置表取速度。agent 模式取「壁钟量级」、human 模式取「有效工时量级」(见下方「执行模式与速度预设」)。这是避免首跑就用错数量级的关键。
类型名必须精确匹配(脚本级硬门禁):estimate.py 默认严格——未知类型直接报错退出(exit 2),必须先 eta_calc.py --list-presets 核对;若确需回落「通用」预设(agent 10 章/工时,量级可能偏差约 1.8×),须显式加 --allow-fallback。直接 eta_calc.py --preset <未知> 同样立即报错。最稳做法:调用前先 --list-presets 挑列表里一字不差的名称。
2. 任务时间戳推算(若任务带创建 / 完成时间,用已完成跨度算平均节奏)。
3. 用户口述(如“我一天能处理 2 个” → 配合每日工时折算)。
4. 显式 --velocity(绕过预设,用你已测得的真实速度)。
5. 若以上都缺 → 显式声明无法预估并请求输入,不得编数、不读私人文件。
确认执行模式与两个参数(缺省取默认):
- 执行模式 --mode:agent=AI 连续执行(报壁钟时长,默认);human=人类日历工时(需显式指定)。代理自己在跑任务时一律用 agent(也即默认)。
- 每日有效工时(默认 2 小时,建议按直觉的 60%~70% 折算)——仅 human 模式使用。
- 每周工作天数(5 / 6 / 7,默认 7)——仅 human 模式使用。
Step 4 — 运行计算器(接入校准)
推荐用一行封装 estimate.py(自动 load 校准 + 算 ETA + 列假设清单,省去多步拼接):
# agent 任务(默认):自动取该桶校准、报壁钟时长、列假设清单
python <skill>/scripts/estimate.py \
--workspace "<当前工作区路径>" \
--task-type "写小说章节(含九维审阅迭代)" \
--total 48 --done 17 --unit 章
若需分步或机器可读,也可手动拼:先用 Step 0 的 calibrate.py load 取得该桶 calibration_factor 与 uncertainty_band_pct,再传给 eta_calc.py。agent 任务必须带 --mode agent --preset "<类型>":
# agent 模式(AI 连续执行):报壁钟时长,不折算日历
python <skill>/scripts/eta_calc.py \
--mode agent --preset "写小说章节(含九维审阅迭代)" \
--total 48 --done 17 --unit 章 \
--calibration-factor <calibration_factor> \
--band-pct <uncertainty_band_pct> --json
# human 模式(人类日历工时):保留原日历折算
python <skill>/scripts/eta_calc.py \
--mode human --preset "写小说章节(含九维审阅迭代)" \
--total 48 --done 17 --unit 章 \
--hours-per-day 2 --workdays-per-week 7 \
--calibration-factor <calibration_factor> \
--band-pct <uncertainty_band_pct>
# --json 结构化输出;不传 --band-pct 时自动回退到 --optimistic-factor/--pessimistic-factor 速度系数法
--mode agent:直接输出「预计连续执行总时长」(壁钟),禁用「每日有效工时 / 工作日」折算。代理执行任务时默认用此模式。--preset:从内置表取速度(agent/human 两套量级),避免首跑就用错数量级;--velocity显式给定时优先于预设。可用eta_calc.py --list-presets查看全部。--calibration-factor:把基准剩余工时按该桶历史偏差整体校准(首次=1.0,无偏)。--band-pct:该桶棘轮不确定带,直接对称覆盖乐观(−带)/悲观(+带)档;传此参数即视为「科学化校准模式」,替代默认速度系数法。- 若未取到校准(首加载且未记录实际),可不传这两项,退化为经验区间并提示 disclaimer。
输出:进度百分比、剩余单元、乐观/基准/悲观三档剩余工时与对应日历完成日(带越窄=越准)。
Step 4.5 — 汇报前假设确认(关键检查点)
在给出最终 ETA 数字之前,先把所有换算假设列出请用户纠偏,避免“自说自话”导致预估偏离实际:
- 速度来源与取值:来自预设 / 任务时间戳 / 用户口述 / 显式
--velocity,及具体数值(如preset=写小说章节(含九维审阅迭代),agent 18 章/工时)。 - 执行模式与单位:明确是
agent(报壁钟「连续执行时长」)还是human(报日历完成日 + 每日有效工时 / 每周工作天数)。agent 模式下不得把速度单位说成"工时/天",必须说"章/小时(壁钟)",防止再次把 AI 速度误当人类日历工时。 - 校准状态:本次是经验初值(首次加载 /
bucket_active=false)还是科学化校准(该桶 factors 与带值的具体数字)。 - 阻塞前置延迟:是否有被
blockedBy卡住、是否需要加--blocked-delay-days。 - 超期阈值(若涉及 Part B):默认
×1.5或--strict ×1.0。
若用户对任一项有异议,先按用户修正后重算再输出;即便用户说“直接给数”跳过确认,上述假设仍须在最终报告中透明列出,不得隐藏。此检查点正是防止技能在缺少纠偏时自主跑偏。
Step 5 — 汇报(含风险)
- 进度百分比与剩余量。
- 完成窗口:乐观 ~ 基准 ~ 悲观 三日期(区间即不确定性)。
- 速度来源与所用假设(便于用户纠偏)。
- 阻塞 / 依赖清单:被
blockedBy卡住的任务单独列出,不计入当前速度。 - 数据不足导致某档不可信时,明确标注“该档依据不足”。
Step 6 — 自动计时回写实际(喂养棘轮)【强制 · 已自动化】
这是棘轮生效的前提,必须执行,不得遗漏。 采用自动计时回路(track-start / track-stop):任务前后各调用一次,无需人工计时——
任务开始前调用 track-start(记录壁钟起点的开放会话):
python <skill>/scripts/calibrate.py track-start \
--workspace "<当前工作区路径>" \
--mode agent --task-type "写小说章节(含九维审阅迭代)" \
--task "写第18-20章" --unit 章 --estimated-hours 0.5
# --estimated-hours 必须是本次 eta_calc 实际报给用户的那个数(同源 mode/type)
任务结束后调用 track-stop(自动用「现在 − 起点」算出壁钟耗时并 record,关闭会话;无需人工计时):
python <skill>/scripts/calibrate.py track-stop \
--workspace "<当前工作区路径>" \
--mode agent --task-type "写小说章节(含九维审阅迭代)" \
--task "写第18-20章"
# 需手动指定实际耗时时加 --actual-hours 0.5;否则自动取壁钟
track-stop 会把 (预估, 实际) 点对写入本项目本地校准文件,重算该桶 calibration_factor(中位数)并棘轮更新 confidence 与 uncertainty_band_pct。样本越多,后续预估越准(带越窄、置信越高),且只进不退。
> 一致性铁律(防双重校正):track-start 的 --estimated-hours 必须来自与本次 track-stop 相同 --mode / --task-type 的 eta_calc 输出。换言之,预估与实测必须同一速度基准,否则校准因子会被错误乘算、把正确量级的预设又压偏。代理用预设速度报 0.5h,就传 0.5h;不要把一个 human 基准的旧估值塞进 agent 桶。
手动回写仍保留:纯预估查询、或需补登历史数据时,仍可用 record(须带 --actual-hours):
python <skill>/scripts/calibrate.py record \
--workspace "<当前工作区路径>" \
--mode agent --task-type "写小说章节(含九维审阅迭代)" \
--task "任务名" --unit 章 \
--estimated-hours 0.5 --actual-hours 0.4
未喂养显式声明:若本次纯预估查询、用户未提供任何实际用时、且无法 track-stop(任务尚未真正执行),则必须显式说明"本次未记录实际,棘轮未喂养,下次预估仍为经验初值 / 历史档",不得默默跳过。
执行模式与速度预设(agent / human)
AI 代理连续执行的速度为壁钟量级(分钟级/章),与人类日历工时(章/有效工时)差一个数量级,故分两种模式与两套速度量级:
agent 模式(默认,代理自执行 / 自检)
- 调用
eta_calc.py --mode agent --preset "<类型>"。 - 直接输出「预计连续执行总时长」(壁钟,如"约 30 分"),不折算日历工作日。
- 速度取自预设的 agent 量级(见
references/velocity_presets.md),首跑即为正确数量级。
human 模式(用于人类节奏、分布多日)
- 调用
eta_calc.py --mode human --preset "<类型>"。 - 保留日历模型:按"每日有效工时 / 工作日"折算完成日。
速度预设表
references/velocity_presets.md 列出常见任务类型的 agent / human 两套速度。预设为起点,真实耗时经 track-stop 回写后由校准因子修匀;预设类型同时作为校准分桶键({mode}:{task_type}),写小说的校准不会污染写代码。
棘轮机制(Ratchet)
本技能用一支校准棘轮把「经验预估」逐步变成「科学化预估」:
- 首次加载:
is_first_run=true,提示 disclaimer,因子=1.0、带=50%(最宽),纯经验。 - 二次及以后:加载即读出历史,用
calibration_factor校准、用棘轮带覆盖区间,得到基于实测的科学化预估。 - 不确定带按经验残差分布(可放宽):样本数 ≥3 时,
uncertainty_band_pct不再单调收缩,而是基于该桶实际残差(actual/estimated 的对数偏差)的 80 分位经验分布计算——样本越聚拢带越窄,越分散带越宽(上限 60%)。这样可避免「围绕错误中心把区间收得过窄」的虚假精度。样本 <3 时仍用随样本量收缩的先验(下限 8%)。 - 置信度随样本量上升但受一致性封顶:
confidence随样本数 n 上升(趋近 1),但当残差散度大时会被经验一致性封顶(最低 0.3),不会在数据很散时还报出高置信。 - 校准因子:取历史「实际/预估」比的中位数,抗单点离群;它反映真实偏差(>1 表示实际总比预估慢),自动修匀后续预估。
Part B — 超期即停与归因
适用场景
- 用户质疑进度慢 / 超时;或代理在执行某任务且其实际用时已逼近或超过预估。
Step 1 — 确定该任务的预估时长
单任务预估时长来源(任一即可):
1. 由 ETA 推算:剩余总工时 ÷ 剩余任务数 得到平均单任务时长;或本任务在 ETA 中的占比。
2. 用户 / 历史直给:该任务原本估了多少小时,或同类任务历史平均时长。
3. 硬约束(不得臆测预估时长 · 脚本级):overrun_check.py 现已强制要求 --estimate-source 显式声明预估来源(calibration / user-stated / prior-eta / preset);若传 manual(臆测)会被硬拦截报错,除非显式 --force-unverified。--estimate-hours 必须来自上述可信来源之一——否则 should_stop 判定本身失真,归因毫无意义。若既无 ETA 也无用户/历史值,必须先向用户确认预估时长,再启用监测;拿不准就先问,不要猜。
Step 2 — 监测实际用时
- 记录任务开始时间(ISO),或在检查点累计实际投入工时。
- 可在自然检查点(完成子步骤、被用户询问、长时间无进展)核对一次。
Step 3 — 运行超期检测
python <skill>/scripts/overrun_check.py \
--task-name "实现登录接口" \
--estimate-hours 3 \
--estimate-source prior-eta \
--elapsed-hours 5.2 \
--overrun-factor 1.5
# 或 --started-at 2026-07-24T09:00 自动按当前时间算已用
# --strict 改为「实际>预估即停」(系数1.0,用于强约束任务)
脚本输出:should_stop 判定、超支比例、以及一张延迟归因工作表(8 类常见原因及改进方向)。
阈值建议:默认 ×1.5(超支 50%)作为“该停手排查”的信号线——小幅超时正常,50% 是项目管理通用的警示线;对强约束 / 关键路径任务可用 --strict(×1.0)更严苛。阈值可在调用时按需调整。
Step 4 — 命中超期即停并归因
若 should_stop 为真:
1. 立即停止当前任务的进一步执行(不再继续推进、不再自动迭代)。
2. 基于真实观察逐项排查工作表中的原因(范围蔓延 / 阻塞依赖 / 估算偏低 / 打断切换 / 返工 / 工具环境 / 信息缺失 / 精力状态),命中者列出具体证据(如“中途加了鉴权需求”“卡在第三方接口未就绪”)。
3. 对每个命中原因给出对应改进建议。
4. 向用户汇报:① 判定已超期 ② 实际耗时 vs 预估 ③ 命中原因(带证据)④ 改进建议 ⑤ 是否调整预估后重启或拆分任务。
若未超期:正常继续,仅在余量不足时提醒。
关键约束
- 禁止虚假预估 / 编造归因:ETA 与超期归因都必须基于真实解析到的数据与实际观察;缺乏依据时显式求输入,不编数、不套空话。
- 超期必须停:
should_stop为真时立即停止并归因,不得继续硬撑或自动绕开。 - 区间如实:不得为显得积极而收窄悲观档;区间宽度反映风险。
- 阻塞单列:被依赖卡住的工作不混入“正常推进中”。
- 假设透明:所有折算(有效工时、工作天数、超期阈值)告知用户,便于纠偏。
- 归因接地:延迟原因须指向具体事实,禁止只罗列工作表模板而不结合实际情况。
Resources
scripts/eta_calc.py— 确定性 ETA 计算器。支持--mode {agent,human}(agent 报壁钟连续时长、human 报日历日)、--preset <类型>(内置速度预设,避免首跑错量级,覆盖写作/代码/数据/调研等 21 类具体任务 + 通用兜底,共 22 类)、--list-presets;预设支持本地覆盖;保留区间、工作日历、阻塞延迟、校准因子、经验残差带、JSON。scripts/estimate.py— 一行封装(推荐入口):自动calibrate.py load+eta_calc.py+ 假设清单(Step 4.5),默认 agent 模式;--unit必填、--allow-fallback控制未知类型回落;--json输出合并原始数据。scripts/calibrate.py— 校准与棘轮引擎。提供track-start/track-stop(自动壁钟计时回路)、校准按(mode, task_type)分桶;首加载判定、disclaimer、calibration_factor、confidence/uncertainty 棘轮、record/load/reset。scripts/overrun_check.py— 超期检测 + 延迟归因工作表生成器;强制--estimate-source声明预估来源(manual 硬拦截),判定即停、原因分类、改进方向、JSON。references/velocity_presets.md— 速度预设表(常见任务类型的 agent 壁钟量级 / human 有效工时量级、取值说明、分桶规则)。references/methodology.md— 公式、速度推导(含预设与双模式)、超期阈值口径、防虚假细则。
隐私与分发
- 本技能不读取、不依赖任何私人文件(如工作区记忆、文档、配置)来获取进度或速度;仅使用任务列表(TaskList)的时间戳与用户口述输入。
- 技能包内不含任何个人数据(姓名、地址、私人项目、路径、外链),可安全公开发布。
- 运行产出(ETA 报告、归因)只基于当次任务列表与用户提供的数据;切勿在汇报中夹带用户的私人项目名、地址或个人信息。
- 本地校准文件:棘轮数据写在
<workspace>/.workbuddy/skills-data/wacx-time-estimation/calibration.json,属本项目运行时产物(仅含任务名与预估/实际工时),可由用户随时删除;它不在技能分发包内,因此上传 SkillHub 时不会夹带任何个人数据。