Skip to content

docs(catalog): add IP-037 a retired setting is not an absent setting - #5043

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
NIU-123370:codex/ip-037-retired-setting-not-absent
Sep 25, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
NIU-123370:codex/ip-037-retired-setting-not-absent

Conversation

@NIU-123370

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

  • Goal/source and gap: GH-C37 asks the interaction pattern catalog for one new
    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.
  • Observable before → after, with the validation row that proves it: before, a
    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 the
    projection (loopx/control_plane/coordination/runtime_shadow.py:53-63,
    configured: true / enabled: false / status: "retired", with malformed
    reading as invalid), reject re-enabling before any write and by code
    (:103-115 and the typed local_authority_shadow_retired at
    loopx/control_plane/coordination/local_authority_shadow.ts:57), treat
    clearing as neither enable nor bootstrap (:117-131,
    tests/control_plane/test_local_authority_shadow_config.py:58), and report
    the retirement instead of seeding it
    (loopx/state_migration.py:236-241, rendered at :460). The same rule holds
    where retirement is a lifecycle state rather than a deletion
    (loopx/capabilities/reward_memory/registry.py:156-157), which is why this is
    written as an interaction and not as one migration's note.
  • Issue/task and intended base: Closes [Task]: GH-C37 add IP-037 a retired setting is not an absent setting #5042. Base main.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope for GH-C37 —
    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: #5011 already owns the operator
    transition and rollback wording in
    docs/reference/authority-observation-retirement.md, so this entry points at
    that document instead of restating it, and it adds no runtime behavior, no
    second settings source, and no new canary profile.
  • Slice boundary / successor: N/A. The catalog is the consumer of this entry;
    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

Public-safe summaries only.

  • Tested revision: a270a55bd
  • Run state: finished
  • Input classes: none
Check kind Result Public-safe evidence / limitation
static passed python3 examples/interaction-pattern-catalog-smoke.py → interaction-pattern-catalog-smoke: ok on the head revision.
static passed loopx 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_parity passed Four structural mutations against the shipped smoke. Removing the detail section → AssertionError: pattern rows without a detail heading: ['IP-037']. Listing IP-037 under 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: deleting IP-037 from 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.
manual passed Every file:line pair cited in the entry was read from main at cc1d46dd8 (the base of this branch) rather than from a PR description; the legacy_observation / runtime_shadow candidate stamping cited at local_authority_shadow_adapter.py:784/:805 was confirmed in that file.
  • Coverage and gaps: the changed path is one markdown file, and the only
    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 on
    sys.path, so it evaluated this worktree's catalog file.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (no functional changes)
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)
  • Benchmark boundary (adapters, runners, verifiers, scoring, evidence)
  • Capability or extension (providers, adapters, skills)
  • Public docs or presentation surface (README, protocols, dashboard)
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: Architecture and research
    incubator — GH-C37 catalog curation. No roadmap S/G/R id claimed.

Shared-authority RFC fixture impact

  • Production-scale fixture schema: N/A — no fixture or envelope changed.
  • Semantic dimensions changed, or reviewed no-impact rationale: N/A. The entry
    describes the shared-authority retirement boundary that #5011 landed, but
    changes no production-scale coordination fixture, generator, or dimension.
  • Provider conformance arms run: N/A — no provider arm is affected by a
    documentation change.
  • Read-only legacy/file/PostgreSQL three-arm rehearsal: N/A — no promotion,
    runtime-routing, or compatibility-projection behavior is changed here.

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Signed-off-by: NIU-123370 <191000457+NIU-123370@users.noreply.github.com>

@huangruiteng huangruiteng 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.

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.

@huangruiteng
huangruiteng merged commit bea36ae into loopx-project:main Sep 25, 2026
19 checks passed
@NIU-123370

Copy link
Copy Markdown
Contributor Author

那条非阻断措辞我接受,而且按你说的改:索引表那一格改成 “carry its retired status and replacement in the projection”。

复述一下依据,确认我理解的和实现一致:配置摘要只给 status=retired(或畸形时 invalid)与 replacement(loopx/control_plane/coordination/runtime_shadow.py:53-63),独立原因码只出现在拒绝消息与迁移结果里(:72、loopx/state_migration.py:236-241)。现在的 “carry its reason” 会让人以为摘要里有个 reason 字段,属于我写过头。

我没有动 a270a55bd 这个 head,免得把已经 APPROVE 的 revision 弄脏:你按现在这个 head 合就行,合并之后我单独开一条一行 PR 把那格改掉;如果你希望这条 PR 内就带上,说一声我立刻推一个一行 commit。

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.

[Task]: GH-C37 add IP-037 a retired setting is not an absent setting

2 participants