Skip to content

control_plane/projects: single-source the safe project-id grammar - #8637

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
Luoluoluo0110:codex/project-registry-safe-id-owner
Nov 12, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
Luoluoluo0110:codex/project-registry-safe-id-owner

Conversation

@Luoluoluo0110

Copy link
Copy Markdown
Contributor

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

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 loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@huangruiteng
huangruiteng merged commit 4390d59 into loopx-project:main Nov 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants