Repository navigation
refactor(public-safety): decide the compact opaque id body in one owner - #5880
Conversation
The compact opaque id -- 1 to 200 characters of [A-Za-z0-9._:-], fullmatch -- was compiled four times under four names (chat_actions._OPAQUE_ID, chat_action_store._OPAQUE_ID, goal_ref_validation.GOAL_ID, botmux_runtime._SAFE_TOKEN), each with its own field wording, so a bound change had four places to land and three of them would silently keep the old limit. The body now lives in public_safe_text.OPAQUE_ID_PATTERN beside the sibling identifier shapes, which already state that they carry syntax only. Each site binds it under its own name, so error text and field names are unchanged. deletion_service still compiles its own copy and is declared by file and count because loopx-project#5854 restructures that file. Signed-off-by: Hsuehtan <296098438+Hsuehtan@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=xhigh
动机
维护 Chat action、Goal 引用和 BotMux 的贡献者,需要保持同一种标识符格式一致。此前同一个200字符格式在五处重复定义;现在四个入口直接引用公共定义,字段名、拒绝消息和附加权限规则保留。四个实际校验入口的604组输入与基线输出、错误类型及消息一致;源码规则改为集中维护。这次不完成整个语义收敛计划,也不把格式合法当成发布或路径操作授权。删除服务的第五处定义和两个 TypeScript 副本仍独立存在;动态拼接模式的防复制守卫尚不完备。
评审 head e9944906a550f062ed1e31161fbf4852acc5877e,实际共同基线 aa87cc019e1062455e79c934764b5e85688663cd。规范依据 issue #4447,文本revision sha256:6d3b7a43054bf5d8124a8974574b6f8992230fae4134d50125eb23732d960ccb(2026-09-29更新):Track A 要证明修复了具体重复权威并验证调用者行为。此项实现;没有改预算或关闭整项tracker。基线公共owner的“syntax only / consumer retains policy”约束也保留。
改动思路
共享格式归入已有 public_safe_text,调用方保留字段、消息和权限策略;本次无需新增能力或通用框架。四个 Python 调用入口共用不变格式;删除服务、TS副本和动态 census 留在已说明的边界之外。相似但不同长度、首字符或principal前缀的规则没有强行合并。Python这里只复用既有语法owner,没有新增控制面决策源;TS配对不因这次小切片改写。
具体改动
关键代码讲解
OPAQUE_ID_PATTERN(public_safe_text.py:322)增加既有1–200字符格式的共享export,保留原字节及fullmatch调用。chat_actions._opaque与chat_action_store._opaque_id(均:96)原先的强制转换、strip、返回值和逐字段错误消息不变,只改pattern来源;后续operation存储/执行规则不在此处重建。goal_ref_validation.require_goal_id(:10)保留原“不隐式strip”的校验和Goal instance检查;botmux_runtime._validated_private_id(:376)保留自己的strip及label错误,引用同一个语法对象。- 既有
test_compact_identifier_shape_owner扩展为16项:声明位置、四个alias、200/201边界、空值/斜杠/换行/U+2028及独立principal格式。全Python literal census只允许公共owner和声明尚未迁移的deletion_service;它仍是源码字面量扫描。
全部6路径已阅读:5个生产文件、1份现有测试,+88/-4。没有新配置、UI入口、持久化字段、调度或权限概念。
对主干的风险
无阻断发现;一个非阻断P2建议:不要将对象identity描述为独立防复制证明。 在当前Python中,动态拼接后 re.compile 同样格式会从regex缓存返回公共owner的同一对象;实际探针确认,既有identity断言仍通过。literal census又看不到拼接,因此两者结合仍不能覆盖这个已承认的动态逃逸。建议修正文案的证明范围,后续在现有guard中复用AST/import检查,替换字面量census而非另加平行规则。当前四个实际调用方确实引用owner,不受此限制影响。
独立验证:owner16项、公安全/BotMux相关289项通过;不可变实际base/head的604输入×4真实函数结果完全一致(含200/201、None、数值、空白、Unicode和字段消息)。operation/source-session共65项在base/head均63通过、2失败;两项相同node与断言细节均在未改的 goal_instance_scope.py:75 抛出 stopped-Goal 的ValueError,而fixture期待另一异常。它们不是regex变更引入,单独保留测试健康/合并资格缺口,没有降低断言。
原生canary在精确head选择本PR六路径,5项直接检查和10项风险检查通过、无manualhold;全树semantic通过。开发advisory0个受支持新载体只是有界扫描结果,不证明完整语义等价。早先误用不支持的canary参数、归档未完成时的测试定位失败均保留并纠正,不算有效验证。按当前配置没有查询CI。上述测试使用隔离合成state;没有更改活动Goal或运行模型任务。
我的整体评价
APPROVE,head e9944906a550f062ed1e31161fbf4852acc5877e,带上述非阻断P2建议。 它将未来格式维护从四个同步编辑点收敛到已有owner,实际用户入口和错误路径保持一致,对维护效率有正向价值;不声称运行时速度提升。源码单源化本身已交付,剩余第五处、TS以及动态guard完整性如实留出。
未来改造检查已用于删除四处重复知识、保留不同policy的caller边界;更强census可在现有测试owner内有界替换,当前不需要投机框架。实际消费者/负例经验用于选择独立对照,未继承历史裁决或证明记忆因果收益。两项基线测试失败属于独立质量问题,通过评审不等于自动合并授权。
English verdict: APPROVE - e994490: four production callers reuse the existing syntax owner with identical results over604 inputs each;16+289 tests and5direct/10canary checks pass. Two unchanged stopped-Goal fixture failures reproduce on the immutable parent. Nonblocking P2: Python regex caching makes identity alone insufficient to detect dynamically reconstructed duplicate definitions; retain the stated census limit.
* fix(control-plane): use canonical digest matcher Signed-off-by: mika <211269698+mikamikasuki@users.noreply.github.com> * test(control-plane): pin canonical digest consumer Signed-off-by: mika <211269698+mikamikasuki@users.noreply.github.com> * feat(benchmark): allow explicit monitored shared startup margin Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> * feat(benchmark): preserve native ranking with scalar best feedback Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> * fix(benchmark): require native winner for new best signals Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> * refactor(benchmark): use native ranking as sole best feedback rule Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> * refactor(public-safety): decide the opaque id body in one owner (#5880) * test(manager): align exact Todo evidence mock shape (#5961) * fix(benchmark): keep empty native winners silent Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --------- Signed-off-by: mika <211269698+mikamikasuki@users.noreply.github.com> Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Co-authored-by: mika <spacexstarship01@outlook.com> Co-authored-by: huangruiteng <huangrt01@163.com> Co-authored-by: Hsuehtan <haonhsu@gmail.com>
Goal And Delivered Outcome
loopx/public_safe_text.pycarries the comment "Shared identifier shapes stay here with the sibling public-safe text shapes. They
express syntax only: each consuming contract retains its own field names, error text, and any
additional validation policy", and
tests/control_plane/test_compact_identifier_shape_owner.pyis theguard that enforces it for three other bodies. Refs [Task]: Semantic vocabulary convergence follow-ups after RFC PR #4433 / 语义词表收敛后续任务 #4447, Track A; no issue is closed here and [Task]: Semantic vocabulary convergence follow-ups after RFC PR #4433 / 语义词表收敛后续任务 #4447 stays open as the track.
^[A-Za-z0-9._:-]{1,200}$— "a compact, path-safe opaque identifier" —was compiled five times in Python under five different names, each with its own message:
loopx/chat_actions.py:55(_OPAQUE_ID),loopx/chat_action_store.py:57(_OPAQUE_ID),loopx/control_plane/goals/goal_ref_validation.py:6(GOAL_ID),loopx/control_plane/goals/botmux_runtime.py:31(_SAFE_TOKEN) andloopx/control_plane/goals/deletion_service.py:49(_OPAQUE_ID, declared here — see Scope). So the200-character bound had five places to land, and a change to any one of them would have silently left
four behind.
deletion_service's own docstring asserts the property the body is supposed to carry("safe for path segments"), which is exactly the sentence a fifth copy cannot be trusted to keep.
OPAQUE_ID_PATTERNplus five alias bindings; the guard'scensus now fails on any file in
loopx/that compiles that body, in or out of a roster. Proven bythe
unitrow (3 → 16 collected cases in the guard) and byP2/P5in the mutation table, where aone-character bound change and an anchor removal both go red.
Author Declaration
mainataa87cc019.Implemented against
guard already enforces for
PUBLIC_SAFE_REFERENCE_PATTERN,COMPACT_TOKEN_PATTERNandMODULE_QUALIFIED_SURFACE_PATTERN— one compiled owner, per-site names and messages, census over thewhole tree.
loopx/public_safe_text.pyOPAQUE_ID_PATTERNtest_compact_identifier_shapes_are_declared_oncetest_the_opaque_id_contract_is_bounded_safe_characters_onlymust be a compact opaque id,must be 1-200 safe characters,botmux <label> is invalidall unchangedtest_each_contract_holds_the_owners_object_and_reports_its_own_fieldtest_the_opaque_id_body_is_compiled_only_by_the_owner_and_declared_sitesOPEN_OPAQUE_SITESfordeletion_service.pyP3)chat_action_normalization._AUTHORITY_PRINCIPALtest_a_principal_reference_is_a_different_question_and_stays_separate.fullmatchcall site of all five names before touching them,and confirmed there is no
.search/.matchuse, so no anchoring question arises; checked that none ofthe six files is a
project_registry_io_manifest_v1host, so no pinned line anchor moves (verified bycounting the paths in the manifest, not by assuming); ran the twin/budget gates rather than reasoning
about them — the architecture/canary sets are identical to base, which is what proves the TypeScript
pairing was untouched.
Scope And Continuation
whole-tree census, four consumer identity assertions, a bound/class edge table (including
U+2028, whichstr.splitlinestreats as a line break but this class never matches), apositive-control pair that both chat helpers still raise their own message, and the deliberate
non-merge of the principal rule.
loopx/control_plane/goals/deletion_service.py, because fix(goals): fence deletion against canonical writes #5854 isrestructuring that file. It is recorded with a count, and converting it without deleting the entry
fails the census (mutation
P3).chat_action_normalization's principal (family prefix plus an opaquebody — merging it would either widen the opaque id to accept prefixes or narrow a principal to a bare
id), and the three chat rules that share the name
_OPAQUE_ID/GOAL_IDbut not the value(
chat_endpoints.py{1,80},chat_store.py{1,160},multi_subagent/native_child_receipts.pywith a leading alnum requirement). A shared name with different values is not drift under
loopx/semantics/inventory.py's own note, so they keep their own bodies.section. Successor 1: the two TypeScript files that compile the same body,
control_plane/goals/goal_instance_identity.ts:5andoperator_actions.ts:18— a cross-runtime owneris a different decision (it moves the dual-runtime twin pairing), so this slice leaves them and the
census is Python-only, stated rather than hidden. Successor 2: make this census fold AST values the way
the Lark guard does, which is where the surviving mutation below comes from.
Validation
e9944906a(1 commit, 6 files, +88 −4)unitpython -m pytest -q tests/control_plane/test_compact_identifier_shape_owner.py-> 16 passed; the same file collects 3 at the base revision, so the +13 are the census, the four consumer rows, the 10-value edge table and the principal pin.unitpython -m pytest -q tests/control_plane -k "chat or botmux or goal_ref or opaque or deletion"— head 8 failed / 151 passed, the same selection in an unmodified worktree at the base revision 8 failed, failure ids identical in both; the eight are the packaged-Chat HTTP bundle cases that need a gitignored compiled artifact, so they are environment red on both sides, not this diff.integrationpython -m pytest -q tests/architecture tests/canary-> head 2 failed / 1444 passed, base 2 failed / 1444 passed, ids identical (test_top_level_module_budget…= the 148-vs-147 pin reported in #5685, which every main-based PR inherits;test_source_session_registry_denial…). Same interpreter, same qualified Node line, run in one window.staticpython -m ruff check loopx tests/control_plane/test_compact_identifier_shape_owner.pyclean;python -m mypy->Success: no issues found in 19 source files;loopx check --scan-pathover all six changed paths ->errors=0.ruff format --checkis not a gate here and is unchanged: the guard file reports 1 hunk before and 1 after.censuspython examples/semantic-vocabulary-drift-smoke.pymeasured on this head and on an unmodified worktree at the base revision, byte-for-byte the same line: same_runtime_forks=2/2 same_runtime_fork_definitions=5/5 conflicting_values=16/16 conflicting_definitions=54/54 schema_version_same_runtime_forks=0/0 multi_value_twins=8/8 multi_value_forks=2/2 multi_value_forks_semantic=1/1 multi_value_fork_definitions=6/6 same_runtime_forks_semantic=2/2 conflicting_values_semantic=0/0, twins_raw=45, generated_verified=2, independently_maintained=43/43. No registry budget and noBUDGET_ANCHORliteral moves in this PR, and the registry I/O census test inside the compared architecture selection reports the same outcome on both sides.regression_parityfullmatch). One variant survives and is the stated limit: a converted site assembling the body from two literals ("^" + _GOAL_BODY + "$") is not caught, because this census counts the literal string in the file text rather than folding AST values like the Lark guard does; that gap is Successor 2 rather than a claim.distinct object even when the text matches) and by the whole-tree census, so both a silent recopy and
a silent unlinking go red. Gaps named plainly: (a)
deletion_servicekeeps its own compile untilfix(goals): fence deletion against canonical writes #5854 lands, so "one owner" is a program, not a fact; (b) the two TypeScript copies of the same body are
outside this census, and this PR makes no cross-runtime claim; (c) the literal-count census is evaded by
an assembled pattern (surviving mutation above); (d) no site's message or field name changed, so there
is no user-visible behaviour to cover — the edge table is the behavioural evidence.
See validation disclosure guidance.
Frontend / Visual Evidence
Type of Change
fullmatch, asserted over a 10-value edge tableLoopX Area
Technical Direction
Shared-authority RFC fixture impact
N/A for this slice — no
.tsfile, conformance fixture or dual-runtime twin budget is touched. That iswhy the two TypeScript copies of the same body are listed as a successor instead of being folded here: a
cross-runtime owner would be a claim against that programme and needs its own evidence.