Repository navigation
control_plane/projects: single-source the safe project-id grammar - #8637
huangruiteng merged 1 commit into
Conversation
repository_identity._SAFE_PROJECT_ID is the canonical stable-identifier grammar
(^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$); resolve_project_identity uses it to validate
the loopx:<id> fallback when a checkout has no origin remote. The projects registry
restated the identical pattern as its own _SAFE_ID and used it in _identifier to
reject unsafe project/goal ids. The registry already imports
normalize_repository_identity from repository_identity, so borrowing one more
owner object adds no import edge and cannot cycle. _SAFE_ID is retired and
_identifier now fullmatches against the owner; the sole remaining use of the re
module in this file was that definition, so its import is dropped too.
presentation/static_site.py keeps a same-named _SAFE_ID with a genuinely different
grammar (no colon, 63-character cap) and is left untouched -- it is a neighbour,
not a copy.
The by-name semantic inventory cannot see this: both bindings are private
_-names it does not catalogue, and they carried different names, so a name-keyed
match would not pair them even if it looked. The new guard keys on the compiled
pattern value -- a whole-tree census of re.compile sites, identity for the
consumer, retirement, the distinct static-site neighbour, and behavioural parity
through registry._identifier over the owner's grammar (including the 256/257
length boundary) plus the resolve_project_identity fallback.
Refs loopx-project#4447.
Signed-off-by: psychologister <230141834+psychologister@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 · max
本次评审对应提交 278555ddf396ad6c0a6b08fd9dd9f0d8c120fcad。
动机 / Motivation
影响登记或解析 Project/Goal 的 CLI 使用者,以及没有可用 origin 时读取稳定仓库身份的调用方。Project registry 与无 origin 的仓库身份回退原先各编译一份相同的稳定 ID 正则;只改其中一处会让可登记 ID 与可回退 ID 分叉。新提交复用现有正则对象。真实 CLI 注册与解析、真实 Git 无 origin 回退在基线和新提交都接受相同的 ID,并保留正常 origin 优先级。验证的是源 checkout 与隔离的本地 Project registry/SQLite 初始化及 Git config;未核对托管 CI、已安装版本或生产状态。
改动思路 / Approach
已应用有界重构:移除 registry 的第二份定义,保留现有库边界与调用方错误。候选相邻点 static_site 是独立 ID 契约,继续分开;没有需要随本 PR 移动的状态决策。 旧输入经过同一清理与 fullmatch,再沿原有分支返回。测试守卫查直接编译的相同字面量,单独验证不同的站点语法。
具体改动 / Changes
关键代码讲解
基线 ea67e68972fc78ed9f5c507df12d5ef2d722f44f 与本提交 278555ddf396ad6c0a6b08fd9dd9f0d8c120fcad 的生产差异集中在 loopx/control_plane/projects/registry.py。登记和显式解析仍通过 _identifier 清理首尾空白,再做完整匹配;字段错误和拒绝后的状态行为都在同一调用点。Project ID 和 Goal ID 可以不同。仓库身份侧继续优先读取有效的 Git origin;只有 origin 不可用时才用合法的 Project ID 返回 loopx: 身份。对照在临时真实 Git 仓库与隔离 registry 上运行,包含 256/257 字符边界、内部换行、Unicode、路径穿越和目标字段错误。
依据 docs/development/README.md:single_project_id_grammar_owner、registry_and_git_identity_parity、distinct_site_identity_scope。
对主干的风险 / Risks
长程连续性与 CLI 使用路径保持:同一已登记 Project 仍能解析,失败后既有状态不动。最大风险是让可登记和可回退 ID 再次分叉,或把站点 ID 一并扩大。两版接受、拒绝、错误和读回一致;registry 中直接编译的重复由 1 处降为 0。整树 AST 守卫的覆盖范围是直接传给 compile 的字面量。
语义与 CI 对齐
通过:77 个共同聚焦用例、head 共 113 个用例,标准 premerge 通过。非法 ID 在 CLI 返回 1、无 origin 回退仍抛 ValueError;既有 registry 与状态文件逐字节不变。未查托管 CI。
我的整体评价 / Verdict
批准。已验证重复定义移除,且实际登记、显式解析与 Git 回退行为保持一致。本次评审覆盖现有宿主与 CLI 行为。验证的是源 checkout 与隔离的本地 Project registry/SQLite 初始化及 Git config;未核对托管 CI、已安装版本或生产状态。
English verdict: APPROVE. The project registry now shares the existing ID grammar, with matched CLI, Git fallback, and rejection behavior.
repository_identity.SAFE_PROJECT_ID is the canonical stable-identifier grammar
(^[A-Za-z0-9][A-Za-z0-9.:-]{0,255}$); resolve_project_identity uses it to validate
the loopx: fallback when a checkout has no origin remote. The projects registry
restated the identical pattern as its own _SAFE_ID and used it in _identifier to
reject unsafe project/goal ids. The registry already imports
normalize_repository_identity from repository_identity, so borrowing one more
owner object adds no import edge and cannot cycle. _SAFE_ID is retired and
_identifier now fullmatches against the owner; the sole remaining use of the re
module in this file was that definition, so its import is dropped too.
presentation/static_site.py keeps a same-named _SAFE_ID with a genuinely different
grammar (no colon, 63-character cap) and is left untouched -- it is a neighbour,
not a copy.
The by-name semantic inventory cannot see this: both bindings are private
_-names it does not catalogue, and they carried different names, so a name-keyed
match would not pair them even if it looked. The new guard keys on the compiled
pattern value -- a whole-tree census of re.compile sites, identity for the
consumer, retirement, the distinct static-site neighbour, and behavioural parity
through registry._identifier over the owner's grammar (including the 256/257
length boundary) plus the resolve_project_identity fallback.
Refs #4447.
Signed-off-by: psychologister 230141834+psychologister@users.noreply.github.com