Repository navigation
feat(goals): 每日维护自动复核内部目标与可能重复补判(G 线,G-C1) - #142
Merged
Merged
Conversation
- G1:学习产生的内部普通目标按明确依据自动完成或放弃;新提示词 goal_review_auto_v1(chat 用途), 代码核对依据在材料内、晚于创建、来自涉及的人或“我”、类型可用,修订号不变才关闭; 指纹(目标修订号+材料内最新消息 ID)去重,失败下次再试,自动关闭可重开。 - G2:可能重复对用与创建时复核共用的 dedup_review_material 和 D6 提示词补判,每对 60 秒; same 合并到较早一条(管理员目标不合并,撤销标记),different 撤销标记,uncertain 保留并记指纹。 - 迁移 039:goal_auto_reviews、goal_duplicate_judgments、goals.auto_review_after_message_id。 - 开关 goal_auto_review_enabled、goal_duplicate_auto_judge_enabled 默认关闭。 - 目标页、维护报告、设置页界面与构建产物;evals/goal_review_eval 确定性计分。
- G1 目标自己的来源(含合并继承的)不算依据,记 evidence_only_sources;提示词来源表述改为与时间无关。
- G2 按宿主目标的令牌范围组材料与合并;跨范围的一对不调用模型、不合并,撤销标记(host_scope_not_merged)。
- G1/G2 调用前检查用途暂停与每日 token 上限,达到即停止本轮、不记指纹。
- _merge 让存续目标取双方较大的重开水位。
- 维护计数与游标同事务写入,中断续跑累加;超出调用上限记 budget_exhausted。
- 候选固定保留最新 10 条合格消息,指纹用合格的最新消息 ID。
- 自动合并可撤销(POST /admin/api/goal-duplicate-judgments/{id}/undo),存续目标合并后被改则 409;撤销后该对驳回。
- 关闭依据消息写入 goal_auto_review_evidence,memory_ops.message_references 据此保护其不被消息清理删除。
- 界面:撤销合并、预算用尽、操作记录中文名;构建产物。
- G1 候选与指纹中“我”的消息只取目标所在入口和涉及的人发过言的入口;按最久未复核优先处理,上限截断的目标下次排前。 - G2 只拦宿主目标被并入其令牌范围外的目标:不调用模型、不合并,保留标记(kept/host_scope_not_merged);内部目标并入宿主目标照创建时规则判断。 - 撤销自动合并只取消因合并带来的字段而发布的待取提醒,存续目标自己的提醒保留。 - 本次维护里 G2 刚合并的存续目标,G1 留到下一次维护(merged_this_run)。 - 依据保护只保护逐条通过核对的合格依据;管理员重开时解除这次关闭的保护。
- G2 范围拦截检查较晚一方及所有已并入它的宿主目标;只修 G2,创建时复核未共用该判断。 - 撤销合并:等于被并入目标自身截止时间的提醒改回其名下并按其正文更新;属于存续目标的保留;其余待取提醒取消。 - G1 中“涉及的人发过言的入口”只算目标创建之后。 - 迁移 039 增加 messages(sender_subject_id,entry_id,id) 索引;test_media_retention 的 039 撤销同步删除该索引。
- 已取走的提醒保持原样;存续目标一侧规则不变。 - 截止时间等于被并入目标自身截止时间、或合并前原属被并入目标的待取提醒:取消该记录;被并入目标按自身提前量的临近时刻已过则新建一条立即可取的提醒(新 ID),未到则由其新计划按时发出。
- 已有提醒记录不改挂、不改正文、不恢复,已取走的不动。 - 取消存续目标与被并入目标名下全部待取提醒,两边按还原后的字段重排;临近时刻已过且未到截止补一条临近提醒,已过截止按过期提醒设置补一条,未到不补。 - 删除恢复为待取与按分支补发的代码,更新测试并补 probe_undo_round5、probe_undo_dup、probe_round3 场景。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
全自动阶段 G 线(规格 G,DECISIONS 2026-11-10「全自动阶段计划」与 2026-11-11 条目;设计 15.3—15.5):
goal_auto_review_enabled、goal_duplicate_auto_judge_enabled默认关闭,新库和旧库都不开。evals/goal_review_eval/。本 PR 不调用真实模型,不改 D6 提示词、冻结语料、设计文档和 DECISIONS.md。第二轮按规划者审查意见修改,见文末“第二轮修改”。
实现
迁移 039(
039_goal_auto_review.sql)新增:goal_auto_reviews:G1 判断记录,带指纹唯一约束。goal_auto_review_evidence:自动关闭所依据的候选消息,供消息清理保护。goal_duplicate_judgments:G2 判断记录,带指纹;自动合并另存merge_record_json,以及undone_at、undone_by。goals.auto_review_after_message_id:重开时记录的消息水位。迁移不写设置,也不改任何现有数据。
G1:
goal_review_auto_v1.md(SHA-256318545babb070ce20e8dc3a8d264050383ac1ac65525e6160e7e3e8812405c04),走chat用途,purpose 为goal_auto_review,用json_chat,含一次 JSON 修正。goals.auto_review_material、_review_check、apply_goal_review。核对失败时保持未结束并记固定原因:decision_open、invalid_output、content_rejection、evidence_empty、evidence_outside_material、evidence_only_sources、evidence_missing、evidence_not_after_creation、evidence_sender_not_involved、evidence_kind_not_allowed。auto_review,原因auto_completed或auto_abandoned),操作记录的 actor 为maintenance。G2:
Goals.review中的材料组装抽成dedup_review_material,判断和陈旧检查抽成dedup_review_judge、dedup_review_decision、dedup_review_stale。创建时复核和维护 G2 都调用这几个函数,因此goal_dedup_probe在 60 秒预算下测到的就是维护路径的判断。dedup_review_material,G2 发给模型的内容等于它的输出,系统提示是 D6。goal_dedup_judge用途。维护:目标阶段的确定性项目做完后,依次执行 G2 和 G1。
settings_json.goal_auto),执行时当前设置也必须开启。管理接口:
POST /admin/api/goals/{id}/reopen:重开每日维护自动关闭的目标。POST /admin/api/goal-duplicate-judgments/{id}/undo:撤销自动合并。GET /admin/api/goal-auto-actions:分页列出自动处理记录。auto_review和auto_closed,列表增加auto_closed,都只在管理端。宿主/api/v1的字段不变,有测试锁定。界面:
Operations.tsx补了新操作的中文名。构建产物已提交。第二轮修改(规划者审查 4393c10)
goal_sources(包括合并时继承来的)一律不算,即使晚于创建时间,这种情况记evidence_only_sources。提示词里来源的表述改为“目标的出处,不是完成或放弃的依据,与时间无关”。test_sources_inherited_by_a_merge_are_not_evidence_even_when_later(拦截+通过)、test_own_source_is_never_evidence_but_a_later_candidate_alongside_it_is。test_code_checks_reject_early_and_uninvolved_evidence_even_in_a_crafted_material。host_scope_json处理。一对中有宿主目标、而另一方所在入口不在该令牌范围内时,不调用模型、不合并,撤销标记并记host_scope_not_merged。test_host_goal_is_never_merged_outside_its_token_scope走审查给的自然流程:I2 并入 I 后产生 (I,H),验证 H 不会被并入范围外的 I。test_host_goal_merges_when_the_partner_is_inside_its_scope。health.check('chat','learning')。G2 调用前检查goal_dedup_judge用途,这个用途本身就受上限约束。test_daily_token_limit_stops_g1_without_requests_or_fingerprints、test_daily_token_limit_also_stops_g2,都覆盖上限用尽和未用尽两种情况。_merge让存续目标取双方auto_review_after_message_id的较大值。test_merge_keeps_the_reopen_watermark:G1 关闭 X,管理员重开 X,G2 把 X 并入 Y,同一次维护里 G1 不能用旧依据关闭 Y。另以没有水位的情况作对照。progress_json.goal_auto,与每项结果同事务提交;续跑从游标继续并累加,报告里不显示游标。test_report_counts_accumulate_across_an_interrupted_run。test_newest_qualified_messages_are_kept_when_priority_messages_fill_the_material:高优先级消息已满 30 条时,另一入口、不含关键词的“还没弄完”仍进入材料,新的合格消息会触发重判。test_priority_order_still_fills_beyond_the_newest_ten。对规划者决定的落实:
budget_exhausted,界面显示为“预算用尽”。测试test_call_cap_reports_budget_exhausted_and_the_rest_waits。merge_record_json中记下存续目标的截止时间、提前量和重开水位,以及来源、涉及人、承诺记忆、依据标注、重定向、可能重复关系和待取提醒的 ID,不存正文。admin_operations(goal_merge_undo)和目标快照(merge_undo)。test_undo_restores_both_goals_and_never_merges_the_pair_again、test_undo_refuses_when_the_survivor_changed_after_the_merge、test_only_automatic_merges_can_be_undone、test_undo_returns_moved_reminders_to_the_restored_goal、test_undo_removes_relations_the_merge_copied_and_restores_watermarks。test_undo_auto_merge_endpoint_lists_state_and_requires_csrf。memory_ops.message_references新增一处检查:goal_auto_review_evidence中关闭依据的候选消息不被 30 天消息清理删除,依据记录存在且目标存在时一直保护。这是memory_ops.py中唯一的改动。只读模型给出的、未用于关闭的引用不受保护。测试test_closure_evidence_is_protected_from_message_retention,用真实的消息清理验证一条被保护、一条被清理。Operations.tsx补了新操作名的中文显示,只改标签映射。第三轮修改(规划者复审 0085ea8)
test_role_messages_in_unrelated_entries_do_not_cause_daily_rejudgment:按 probe_rejudge 的场景每天只在无关入口加一条 self_output,不再重判;在本入口回复就会重判。test_role_messages_count_where_the_goal_people_speak:涉及的人发过言的群里,我的回复算候选;无关入口的不算。test_call_cap_leftover_goal_is_first_in_line_next_time:三个目标、上限 2,第三个在下一次维护中被复核,之后按最久未复核轮换。kept/host_scope_not_merged,按指纹不再重复处理。内部目标并进宿主目标照创建时规则调用模型。test_internal_goal_merges_into_an_earlier_scoped_host_goal_as_at_creation:按 probe_scope_block 的场景,正常判断并合并进宿主目标。test_host_goal_is_never_merged_outside_its_token_scope:反方向被拦,标记保留,第二次维护不再处理。test_undo_keeps_the_survivors_own_reminders_and_cancels_merged_ones:按 probe_undo_reminder,存续目标自己的临近提醒撤销后仍待取;因被并入目标的截止时间而发布的提醒被取消。merged_this_run,下一次维护再复核。test_goal_merged_into_this_run_is_reviewed_next_run。test_merge_keeps_the_reopen_watermark相应改为在第二次维护中验证。test_reopen_releases_evidence_and_unqualified_co_citations_are_never_protected:一同引用的 event 消息不受保护;重开后依据消息被真实的消息清理删除,目标来源仍按原规则保留。本轮没有改迁移和提示词,前端只补了报告标签。
第四轮修改(规划者复审 d1e08b4)
宿主范围拦截算上已被吸收的宿主目标:较晚一方本身,以及 merged_into 链最终指向它的任一宿主目标,只要有一个的令牌范围不允许写对方入口,就按“被拦”处理:保留标记,记
kept/host_scope_not_merged,不调用模型。_merge里核对写权限,没有检查已被吸收进待判目标的宿主目标。新目标在创建复核完成前就吸收别的目标的情况很少见,但理论上仍有这个问题,见已知限制。test_absorbed_host_goal_blocks_a_merge_out_of_its_scope(probe_scope_redirect 的场景):H 并入 S 后,S 不会被并进范围外的 P;宿主访问 H 时得到 GoalMerged,指向 S,并能在范围内更新 S。test_absorbed_host_goal_allows_a_merge_inside_its_scope。撤销合并时被并入目标的提醒还回去:合并期间在存续目标名下发布的提醒按截止时间分三种处理:
两边截止时间相同时,提醒留在存续目标,被并入目标按自己的计划重排,不补发已过的时点。
test_undo_returns_reminders_of_the_merged_goals_own_deadline(probe_round3 末段):A 无截止、B 有截止,合并后在 A 名下发出的临近提醒撤销后回到 B,仍待取;不属于任何一方的提醒被取消;B 只重排剩余的到期计划。test_undo_keeps_reminders_on_the_survivor_when_both_deadlines_match。test_undo_keeps_the_survivors_own_reminders_and_cancels_merged_ones改为断言因被并入目标截止时间发出的提醒回到被并入目标。“涉及的人发过言的入口”只算目标创建之后:仍受本次维护的消息上界限制。
test_people_speaking_in_a_group_only_before_creation_do_not_widen_the_conversation:只在创建前于群里发过言时,群里我的发言不进候选、不改变指纹;涉及的人在创建后到群里发言,群里我的发言才算候选。性能:加了
messages(sender_subject_id, entry_id, id)索引(写在迁移 039 中),tests/test_media_retention.py的 039 撤销步骤相应删除这个索引。EXPLAIN QUERY PLAN看,候选查询和入口子查询都是SEARCH m USING INTEGER PRIMARY KEY (rowid>? AND rowid<?),等于逐条扫描本次范围内的全部消息。messages_sender_entry (sender_subject_id=?);(sender_subject_id=? AND entry_id=? AND id>? AND id<?);(sender_subject_id=?);goal_sources用覆盖索引。第五轮修改(规划者复审 080b618)
撤销自动合并时,不再改动任何已有提醒记录的 goal_id 或正文,以免宿主游标已越过的记录被改挂后再也拉不到:
test_undo_never_rewrites_existing_reminders_and_b_gets_exactly_one_on_time[未取走/已取走],即 probe_undo_dup 的两个场景。未取走时原记录保持在存续目标名下并取消,B 在自己的临近时刻得到唯一一条待取提醒;已取走时那条记录的 goal_id、正文和状态都不变。test_undo_reissues_immediately_when_bs_own_warning_time_has_passed:B 的临近时刻已过时,撤销即新建一条。第六轮修改(规划者复审 9f90290)
第五轮的逐例修补仍有两个边界会丢提醒:合并时保留的提醒被宿主取走后撤销,A 的同阶段提醒被恢复而 B 丢了提醒;两边截止时间相同时 B 丢了临近提醒(probe_undo_round5)。撤销时的提醒处理因此改为一条简单规则,宁可多发一次,不丢:
test_undo_round5_after_the_kept_reminder_was_taken_both_goals_get_their_stage(同时验证宿主游标之后能拉到两个目标的新提醒)、test_undo_round5_equal_deadlines_merged_before_the_warning;test_undo_never_rewrites_existing_reminders_and_b_gets_exactly_one_on_time[未取走/已取走]、test_undo_reissues_immediately_when_bs_own_warning_time_has_passed;test_undo_round3_reminder_fired_under_a_for_bs_deadline;test_undo_reissues_the_current_stage_for_both_goals_of_each_merge、test_undo_with_equal_deadlines_reissues_for_both、test_undo_past_the_deadline_issues_one_overdue_reminder_unless_turned_off、test_undo_past_the_deadline_respects_turned_off_overdue_reminders(过期提醒关闭时补“已到期”提醒、不排次日计划),以及test_undo_round6_survivor_past_its_deadline_gets_its_stage_either_way[关闭/开启](probe_undo_round6 两种设置)。评测工具
uv run python evals/goal_review_eval/run.py --corpus <JSON> --out <仓库外目录>,默认语料为冻结的goal_review_v1.json。expected、reason、category在写入前剔除,有测试锁定,也检查请求中不出现标注文字。gates。call_counts统计超时、429、截断、无效调用和执行错误,报告给出valid。出现超时、429 或复核失败时停止,整次无效。--fake用 MockTransport,不读模型配置,不访问网络。goal_dedup_probe --method D6(默认预算 60 秒)。保守选择与偏离
same_ambiguous)。now之前的消息。tests/test_media_retention.py:补了撤销 039 的一步,规划者已接受。goals分区多两个键,相应更新了三个设置测试的期望值。已知限制
测试(head d5f3f0c)
test_persona_streaming.py::test_future_deadline_closes_stream_worker_and_preserves_shared_client(它在未改动的 origin/main 上同样失败,与本 PR 无关,规划者另行处理)。uv run --locked --isolated --python 3.12 pytest):5951 个通过,失败的只有同一个用例。npm test(478 个)和 build 结果仍然有效。uv build:通过。33c66256c0b9b060545e3f6b036580b187f7699bf683c99e7849cb6174e131e9。提示词的 SHA-256:318545babb070ce20e8dc3a8d264050383ac1ac65525e6160e7e3e8812405c04。这两轮都没有改动。各轮修改对应的新测试见上面各轮的修改说明。
本 PR 不调用真实模型。真实评测和隐藏集由规划者安排。