docs(catalog): add IP-037 a retired setting is not an absent setting - #5043
huangruiteng merged 1 commit into
Conversation
Signed-off-by: NIU-123370 <191000457+NIU-123370@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Review of exact head a270a55bd550ef5138ef32be6099472871d369ce for #5043. No blocking finding; one wording refinement below is non-blocking. This review is not merge-readiness or CI approval.
动机
#5042 要求给交互模式目录增加一个可复用的“能力退役后,旧设置仍须可辨认”正反例。现有操作文档与测试已经实现了旧观察器的退役语义,但概念目录没有说明“已配置但退役”为什么既不是“未配置”,也不是“仍可写”。不增加这条时,后来清理设置或做迁移的人容易把保留的历史记录当作可重启的采集配置。本 PR 完成了所指的单条目录条目,而不借文档 PR 改运行时。
改动思路
目录只是给现有契约命名和导航,决策权仍在 runtime_shadow.py 的配置校验、旧 RPC 的类型化拒绝、state_migration.py 的非写入结果,以及原有恢复/来源边界。正向阅读路径是看到旧配置、读到 configured=true/status=retired/enabled=false,再根据意图选择显式清除或单独配置并 bootstrap 新采集;反向路径是旧客户端尝试 enable 或迁移尝试重建旧观察器,必须拒绝或返回 attempted=false/outcome=retired。IP-030、032、033、036 处理的决策、归档和丢失响应都没有覆盖“退役设置仍须可读”这个概念,因此新增一条比改写既有条目更清楚。
具体改动
关键内容讲解
唯一改动文件 docs/concepts/interaction-pattern-catalog.md 新增 IP-037 的家族/风险映射、State And Boundary 列表行,以及含触发信号、四条规则、流程图、好坏对照、bad smell 和验证来源的正文。正文引用的本地实现与测试已逐一对照:旧配置摘要确实保留 retired/invalid,旧 enable 在注册表写入前拒绝;清除旧键不自动 bootstrap,新采集必须单独配置;迁移保留响应字段但不 seed 旧观察器。#5011 已合并,新增条目没有重复其操作手册或扩大到新迁移能力。
一处非阻断的精度建议:列表行写“carry its reason in the projection”,但当前旧配置摘要实际给出的是 status=retired 与 replacement,没有独立的 reason 或 reason_code 字段;原因码出现在拒绝和迁移结果中。下次编辑时可改为“carry its retired status and replacement in the projection”,避免读者误以为摘要已有独立原因字段。这不改变该条目所需的可辨认/不可写结论。
对主干的风险
这是单文件 +141/-1 的公开概念文档,未改 CLI、Lark、前端、持久化或权限规则;主要风险是把已退役行为写错、以后被误当成更宽的承诺。我从目标 head 对照了被引实现与操作文档,并在最新主干 789ec692 上复核了唯一相关变动文件 runtime_shadow.py 的退役摘要/拒绝规则,仍与条目一致。独立运行目录 smoke、相关 Python 28/28、TypeScript 3/3 和差异空白检查,均通过。loopx check --scan-path 的公开边界扫描为 1 文件 clean;它还报告两个其他 Goal 已存在的 state_projection_gap,未触及本 PR 文档,不作为本 PR 的 change request。目录 smoke 不保证家族矩阵这一行永不被删,本次矩阵登记由人工核对;也没有按能力配置等待远端 CI。当前 PR 对主干显示需要更新,合并准备状态由维护者另行处理。
我的整体评价
未发现阻断项。对长程维护,本条目把已存在的退役状态与失败路径压成可复用的模式,减少未来误删、误启用或重建旧来源的风险;对当前用户路径,它提供可读的选择规则而不增加新操作或隐性门槛。条目规模与相邻模式接近,没有新的兼容分支、第二本账或未验证的运行时承诺。上述投影“reason”措辞值得后续收紧,但不妨碍本次范围内的 APPROVE;它不等于已满足主干更新或发布门槛。
English verdict: APPROVE - a270a55; the docs match the retired-setting runtime contract, with one non-blocking projection-wording suggestion and unrelated check warnings separated from merge readiness.
|
那条非阻断措辞我接受,而且按你说的改:索引表那一格改成 “carry its retired status and replacement in the projection”。 复述一下依据,确认我理解的和实现一致:配置摘要只给 我没有动 |
Goal And Delivered Outcome
public-safe good/bad case. The catalog says a great deal about what stays
authoritative after a state change (IP-030 revision-guarded machine
configuration, IP-032 durable decisions across an archive, IP-033 a recorded
rejection, IP-036 a commit nobody was told about) and nothing about what stays
legible after a capability is retired. A Goal that still names a setting
whose implementation is gone can be read as off, as never configured, or as
still writable — three different operational futures, and the shipped code
already picks one of them without the concept catalog saying why.
caller facing a retired key has no catalog rule, so the cheap moves are to
delete the field, to read "clear this" as "turn on the replacement", to let a
migration re-seed the retired store because the response field is still
parsed, or to retry a typed rejection as a transient storage error. After,
IP-037 A Retired Setting Is Not An Absent Setting states four rules, each
pinned to shipped code and tests on
main: keep the retired setting in theprojection (
loopx/control_plane/coordination/runtime_shadow.py:53-63,configured: true/enabled: false/status: "retired", with malformedreading as
invalid), reject re-enabling before any write and by code(
:103-115and the typedlocal_authority_shadow_retiredatloopx/control_plane/coordination/local_authority_shadow.ts:57), treatclearing as neither enable nor bootstrap (
:117-131,tests/control_plane/test_local_authority_shadow_config.py:58), and reportthe retirement instead of seeding it
(
loopx/state_migration.py:236-241, rendered at:460). The same rule holdswhere retirement is a lifecycle state rather than a deletion
(
loopx/capabilities/reward_memory/registry.py:156-157), which is why this iswritten as an interaction and not as one migration's note.
main.Scope And Continuation
one new pattern, registered in all three places the catalog keeps (index row,
State And Boundary family matrix, detail section), with its own trigger, user
channel, agent channel, state contract, bad smell, visual model and validation
reference. Deliberately not done here:
#5011already owns the operatortransition and rollback wording in
docs/reference/authority-observation-retirement.md, so this entry points atthat document instead of restating it, and it adds no runtime behavior, no
second settings source, and no new canary profile.
the next owner who retires a capability reads the pattern rather than
redeciding it. If a future canary wants to sample "retired setting projection"
it should extend a State And Boundary profile, not allocate an IP for the
canary.
Validation
a270a55bdstaticpassedpython3 examples/interaction-pattern-catalog-smoke.py→interaction-pattern-catalog-smoke: okon the head revision.staticpassedloopx check --scan-path docs/concepts/interaction-pattern-catalog.md→public boundary scan clean: 1 files. Two warnings in the same run (registry file does not exist: .loopx/registry.json,registry boundary unavailable) are this scratch worktree having no local registry, not a finding about the diff.regression_paritypassedAssertionError: pattern rows without a detail heading: ['IP-037']. ListingIP-037under a second family →AssertionError: pattern ids listed under more than one family. Renumbering only the index row →pattern rows without a detail heading: ['IP-038']. Not caught, and why: deletingIP-037from the State And Boundary family-matrix row leaves the smoke green — matrix registration is curated, not gated, so the third mutation above is the only mechanical guard on the three surfaces. Disclosed rather than counted as evidence.manualpassedmainatcc1d46dd8(the base of this branch) rather than from a PR description; thelegacy_observation/runtime_shadowcandidate stamping cited atlocal_authority_shadow_adapter.py:784/:805was confirmed in that file.executable gate over it is the catalog smoke, which pins the row/heading
pairing and the one-family rule — exactly the three drift modes this entry
could introduce. Runtime rows are
not_applicable: no CLI, dashboard, Lark,provider or state-write code changed, so no pytest, TypeScript, or
provider-conformance selection can fail or pass differently because of this
diff. Gap named plainly: the smoke does not verify the factual claims in the
entry (that retired activation rejects before a registry write, that clearing
preserves runtime configuration, that migration reports
attempted: false);those are verified by the tests the entry cites, which are pre-existing and
were not re-run here — a reviewer checking this entry should read the cited
file:line pairs, not the smoke output. Interpreter note: checks were run with
a repository-relative command against a locally installed Python 3.12
environment (an editable install from another worktree on this machine), not
uv sync --extra test; the smoke script inserts its own repository root onsys.path, so it evaluated this worktree's catalog file.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
incubator — GH-C37 catalog curation. No roadmap S/G/R id claimed.
Shared-authority RFC fixture impact
describes the shared-authority retirement boundary that
#5011landed, butchanges no production-scale coordination fixture, generator, or dimension.
documentation change.
runtime-routing, or compatibility-projection behavior is changed here.
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).none.Signed-off-bytrailer (git commit -s).