refactor(coordination): unify local provider routing for File, SQLite, and PostgreSQL - #4317
Conversation
huangruiteng
left a comment
There was a problem hiding this comment.
English verdict: REQUEST_CHANGES — the provider seam is a good consolidation, but PostgreSQL selector loss can silently fall back to File and the factory contract does not enforce tenant/goal binding.
动机
本次 review 针对精确 head 00afdcf9cfa050765d83e62f72136edaeabff4be(base codex/todo-decision-scope-update)进行。PR 的目标是把 File、SQLite 与 service-owned PostgreSQL 的本地 provider opening 收敛到统一 typed seam,消除 command 级别的重复构造,并让 source_authority 不再依赖 instanceof 猜测。这个方向与现有 AuthorityStore/runtime 边界一致,File 默认和 SQLite opt-in 也有较完整的正向验证。
但 provider selection 一旦成为 authority lineage fence,必须同时保证“已选 provider 不会悄悄换成另一个 provider”以及“service factory 返回的 store 仍绑定 selector 的 scope”。当前实现的两个缺口会直接破坏这两个承诺:PostgreSQL marker 丢失时可以新建 File authority;factory 可以返回同一数据库 identity 但属于另一个 tenant/goal 的 store。前者可能 fork 后续写入和 receipt,后者可能把读写路由到别的 tenant/goal,因此本次结论为 REQUEST_CHANGES。
改动思路
新的主路径是 local_authority_runtime.ts 的 openRuntimeStore,进入 local_authority_provider.ts 的 openLocalAuthorityStoreHandle。该函数读取 provider marker:无 marker 且不存在 SQLite state 时使用 File 默认;SQLite marker 要求 exact-key schema、existing database 与 expected identity;PostgreSQL marker 则解码 goal_id、tenant_id、store_identity,交给 service-owned factory,再检查返回 store 的 providerKind 与 storeIdentity。这是合适的 decision owner:runtime 负责编排,provider module 负责 selection/opening,具体 store 负责持久化事务和 receipt。
正向流程的 ownership 清晰,且不把 credentials 写进 marker。不过 authoritative input 目前只覆盖 marker 和 store identity,没有覆盖“marker 曾经选中过外部 PostgreSQL 之后被删除”的状态,也没有把 factory 返回值的 tenant/goal binding 纳入 AuthorityStore typed contract。于是 ENOENT 被错误地解释为一个全新的未初始化 File goal;而 scope 则停留在 factory 调用方的信任假设中。这个边界需要在同一个 provider opening owner 内补全,而不是由各个 command caller 分别防守。
具体改动
关键代码讲解
LocalPostgreSqlAuthoritySelection(local_authority_provider.ts:38-44)定义了严格的 schema、provider、goal、tenant 和 store identity,避免凭据进入持久化 marker。LocalPostgreSqlAuthorityFactory(local_authority_provider.ts:46-48)新增 service-owned PostgreSQL 构造 seam,但返回类型仍是裸AuthorityStore,没有可验证的 scope metadata。openSelectedPostgreSql(local_authority_provider.ts:143-190)正确拒绝缺失 factory、错误 provider 和 identity drift;然而只检查providerKind/storeIdentity,没有检查返回 store 的tenant_id/goal_id。openLocalAuthorityStoreHandle(local_authority_provider.ts:192-233)统一处理 marker 和 provider 分支。其 selector ENOENT 分支(199-214)只stat本地 SQLite;当 SQLite 不存在时直接构造FileAuthorityStore,因此无法识别“外部 PostgreSQL 已经被选中过”的情况。openRuntimeStore将 monitor、mutation、Todo、read、promotion 等 provider-first caller 收敛到同一 opening seam;authorityStoreSourceAuthority则使用providerKind输出file_v0/sqlite_v0/postgresql_v0。这两处是值得保留的最小共享边界。
对主干的风险
P1 — PostgreSQL selector 丢失会静默回退到 File。
触发:goal 已有合法 PostgreSQL marker,随后 marker 被删除或清理导致 readFile 返回 ENOENT,同时本地没有 SQLite database。路径:openLocalAuthorityStoreHandle:199-214 → SQLite stat 也 ENOENT → new FileAuthorityStore(...)。实际结果是 provider=file、sourceAuthority=file_v0,后续 mutation/receipt 会落到新的 File lineage,而不是失败并等待恢复。这与文档中“selected provider never falls back”相矛盾,也可能造成 authority fork。
最小修复:保存 durable last-known non-file selection/tombstone,或在 selector 缺失时执行 service-owned PostgreSQL existence probe;无法确认原 provider 时必须返回 typed non-file failure,绝不能构造 File。请加入回归测试:先选择 PostgreSQL,再只删除 marker,重新打开应得到 LocalAuthorityProviderOpenError(或等价 unavailable result),并断言没有 File store/write;另测 marker 不可读的恢复语义。
P1 — PostgreSQL factory 没有强制 tenant/goal scope binding。
触发:openPostgresqlStore(selection) 收到 tenant-a/goal-a,却返回一个 providerKind=postgresql、storeIdentity 相同、内部 scope 为 tenant-b/goal-b 的 store。openSelectedPostgreSql:165-189 会接受它。PostgreSqlAuthorityStore 的 tenantId/goalId(414-428)实际参与所有 SQL key,因此运行时会读写另一个 scope,而调用方仍投影请求的 goal。当前测试只证明 factory 收到 selector,以及 provider/identity 检查通过,不能证明返回值绑定正确。
最小修复:把 factory 返回类型提升为带可验证 tenant_id/goal_id 的 scoped PostgreSQL handle,或给 AuthorityStore 增加等价的 binding method,并在 opening boundary 比较 selector 与返回值。加入负向 factory 测试(同 identity、不同 tenant/goal 必须得到 typed scope-mismatch failure),并在可用的隔离 PostgreSQL 服务上增加 tenant/goal read/commit binding 集成测试。
验证结果:focused provider/runtime/conformance Node suite 为 66 passed;npm run typecheck:control-plane passed;远端精确 head 有 28 个成功 checks 且 mergeable/CLEAN。PostgreSQL integration 为 4 passed、1 skipped,因 review 环境未设置 LOOPX_TEST_POSTGRES_URL,所以真实服务 scope 仍需补证。上述两个 P1 均来自实现路径/独立复现,不是环境噪声。
我的整体评价
统一 opening seam、严格 selector schema、provider identity metadata 和 runtime caller 收敛是有价值且范围合适的改动;File 默认与有效 SQLite 兼容性也保持良好。可是当前 observable_semantics 在关键故障状态上发生 unintended drift:marker loss 会观察到 file_v0 而不是 typed failure,scope mismatch 也没有可观察的 rejection。请先补齐 non-file selection recovery 与 tenant/goal binding,再以新的 exact head 重跑 focused、negative 和真实隔离 PostgreSQL 验证;在此之前不能批准。
huangruiteng
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
English verdict: REQUEST_CHANGES — the provider seam is a good consolidation, but PostgreSQL selector loss can silently fall back to File and the factory contract does not enforce tenant/goal binding.
动机
本次 review 针对精确 head 00afdcf9cfa050765d83e62f72136edaeabff4be(base codex/todo-decision-scope-update)进行。PR 的目标是把 File、SQLite 与 service-owned PostgreSQL 的本地 provider opening 收敛到统一 typed seam,消除 command 级别的重复构造,并让 source_authority 不再依赖 instanceof 猜测。这个方向与现有 AuthorityStore/runtime 边界一致,File 默认和 SQLite opt-in 也有较完整的正向验证。
但 provider selection 一旦成为 authority lineage fence,必须同时保证“已选 provider 不会悄悄换成另一个 provider”以及“service factory 返回的 store 仍绑定 selector 的 scope”。当前实现的两个缺口会直接破坏这两个承诺:PostgreSQL marker 丢失时可以新建 File authority;factory 可以返回同一数据库 identity 但属于另一个 tenant/goal 的 store。前者可能 fork 后续写入和 receipt,后者可能把读写路由到别的 tenant/goal,因此本次结论为 REQUEST_CHANGES。
改动思路
新的主路径是 local_authority_runtime.ts 的 openRuntimeStore,进入 local_authority_provider.ts 的 openLocalAuthorityStoreHandle。该函数读取 provider marker:无 marker 且不存在 SQLite state 时使用 File 默认;SQLite marker 要求 exact-key schema、existing database 与 expected identity;PostgreSQL marker 则解码 goal_id、tenant_id、store_identity,交给 service-owned factory,再检查返回 store 的 providerKind 与 storeIdentity。这是合适的 decision owner:runtime 负责编排,provider module 负责 selection/opening,具体 store 负责持久化事务和 receipt。
正向流程的 ownership 清晰,且不把 credentials 写进 marker。不过 authoritative input 目前只覆盖 marker 和 store identity,没有覆盖“marker 曾经选中过外部 PostgreSQL 之后被删除”的状态,也没有把 factory 返回值的 tenant/goal binding 纳入 AuthorityStore typed contract。于是 ENOENT 被错误地解释为一个全新的未初始化 File goal;而 scope 则停留在 factory 调用方的信任假设中。这个边界需要在同一个 provider opening owner 内补全,而不是由各个 command caller 分别防守。
具体改动
关键代码讲解
LocalPostgreSqlAuthoritySelection(local_authority_provider.ts:38-44)定义了严格的 schema、provider、goal、tenant 和 store identity,避免凭据进入持久化 marker。LocalPostgreSqlAuthorityFactory(local_authority_provider.ts:46-48)新增 service-owned PostgreSQL 构造 seam,但返回类型仍是裸AuthorityStore,没有可验证的 scope metadata。openSelectedPostgreSql(local_authority_provider.ts:143-190)正确拒绝缺失 factory、错误 provider 和 identity drift;然而只检查providerKind/storeIdentity,没有检查返回 store 的tenant_id/goal_id。openLocalAuthorityStoreHandle(local_authority_provider.ts:192-233)统一处理 marker 和 provider 分支。其 selector ENOENT 分支(199-214)只stat本地 SQLite;当 SQLite 不存在时直接构造FileAuthorityStore,因此无法识别“外部 PostgreSQL 已经被选中过”的情况。openRuntimeStore将 monitor、mutation、Todo、read、promotion 等 provider-first caller 收敛到同一 opening seam;authorityStoreSourceAuthority则使用providerKind输出file_v0/sqlite_v0/postgresql_v0。这两处是值得保留的最小共享边界。
对主干的风险
P1 — PostgreSQL selector 丢失会静默回退到 File。
触发:goal 已有合法 PostgreSQL marker,随后 marker 被删除或清理导致 readFile 返回 ENOENT,同时本地没有 SQLite database。路径:openLocalAuthorityStoreHandle:199-214 → SQLite stat 也 ENOENT → new FileAuthorityStore(...)。实际结果是 provider=file、sourceAuthority=file_v0,后续 mutation/receipt 会落到新的 File lineage,而不是失败并等待恢复。这与文档中“selected provider never falls back”相矛盾,也可能造成 authority fork。
最小修复:保存 durable last-known non-file selection/tombstone,或在 selector 缺失时执行 service-owned PostgreSQL existence probe;无法确认原 provider 时必须返回 typed non-file failure,绝不能构造 File。请加入回归测试:先选择 PostgreSQL,再只删除 marker,重新打开应得到 LocalAuthorityProviderOpenError(或等价 unavailable result),并断言没有 File store/write;另测 marker 不可读的恢复语义。
P1 — PostgreSQL factory 没有强制 tenant/goal scope binding。
触发:openPostgresqlStore(selection) 收到 tenant-a/goal-a,却返回一个 providerKind=postgresql、storeIdentity 相同、内部 scope 为 tenant-b/goal-b 的 store。openSelectedPostgreSql:165-189 会接受它。PostgreSqlAuthorityStore 的 tenantId/goalId(414-428)实际参与所有 SQL key,因此运行时会读写另一个 scope,而调用方仍投影请求的 goal。当前测试只证明 factory 收到 selector,以及 provider/identity 检查通过,不能证明返回值绑定正确。
最小修复:把 factory 返回类型提升为带可验证 tenant_id/goal_id 的 scoped PostgreSQL handle,或给 AuthorityStore 增加等价的 binding method,并在 opening boundary 比较 selector 与返回值。加入负向 factory 测试(同 identity、不同 tenant/goal 必须得到 typed scope-mismatch failure),并在可用的隔离 PostgreSQL 服务上增加 tenant/goal read/commit binding 集成测试。
验证结果:focused provider/runtime/conformance Node suite 为 66 passed;npm run typecheck:control-plane passed;远端精确 head 有 28 个成功 checks 且 mergeable/CLEAN。PostgreSQL integration 为 4 passed、1 skipped,因 review 环境未设置 LOOPX_TEST_POSTGRES_URL,所以真实服务 scope 仍需补证。上述两个 P1 均来自实现路径/独立复现,不是环境噪声。
我的整体评价
统一 opening seam、严格 selector schema、provider identity metadata 和 runtime caller 收敛是有价值且范围合适的改动;File 默认与有效 SQLite 兼容性也保持良好。可是当前 observable_semantics 在关键故障状态上发生 unintended drift:marker loss 会观察到 file_v0 而不是 typed failure,scope mismatch 也没有可观察的 rejection。请先补齐 non-file selection recovery 与 tenant/goal binding,再以新的 exact head 重跑 focused、negative 和真实隔离 PostgreSQL 验证;在此之前不能批准。
790ec4b to
97c6770
Compare
00afdcf to
7253b69
Compare
|
Rebased/refined and locally re-qualified on the exact pushed head Changed surfaces: typed provider identity and selector decoding, one Checks run:
The only expected skip is the PostgreSQL integration test when running the general TypeScript package command without a connection string; the real PostgreSQL suite was run separately and passed. The unbounded full Python suite was not selected as a merge gate. No private snapshots, credentials, local paths, registry state, Todo, lease, or receipt were written. Self-repair: the original dirty/conflicting stacked branch was rebuilt from current |
7253b69 to
2fbb128
Compare
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机
4317 解决的是 provider routing 的实际分叉:旧实现让多个 local command 各自组合 createStore/openLocalAuthorityStore,source authority 又依赖 SQLite instanceof。这样 File 默认虽能工作,却无法证明所有 caller 在 provider 切换时选择同一后端;未来 PostgreSQL 还会有 credential、tenant 和 fallback 边界风险。现在无 selector 明确得到 File/file_v0,SQLite 只在显式 marker 下打开,PostgreSQL 只接受 service-owned factory 和 identity binding。
改动思路
以现有 AuthorityStore 为 durable state owner,在 coordination provider boundary 增加 typed providerKind、source authority helper、严格 selector decoder 和 LocalAuthorityStoreHandle;在 runtime 增加唯一 openRuntimeStore,所有 monitor、promotion、todo、read/list 和 mutation caller 都复用它。selector 只保存 public binding facts,credential/client 留在 service-owned factory;selected provider 不可用、provider/identity 不匹配时 typed fail closed,禁止静默 fallback。File/SQLite backend 继续保留各自不可约的资源语义。
具体改动
新增 File/SQLite/PostgreSQL/Nokv provider metadata 与 file_v0/sqlite_v0/postgresql_v0 source projection;local_authority_provider.ts 统一默认 File、SQLite identity fencing、PostgreSQL factory seam、exact-key decoding 和 legacy wrapper。local_authority_runtime.ts 删除重复的 per-command opening 分支,并让 sourceAuthorityFor 读取 typed metadata。RFC/docs 明确 default-off、credential privacy、no authority/cutover grant 和 rollback。fixture 增加 provider matrix;测试覆盖正向 handle、错误 provider/identity、credential-shaped field、无 fallback,并用 disposable PostgreSQL 做 tenant commit/readback。
关键代码讲解
openLocalAuthorityStoreHandle(local_authority_provider.ts:192)是选择与 fail-closed 的唯一 owner:缺 selector -> File,显式 provider -> strict decode/identity check,失败不回退。openRuntimeStore(local_authority_runtime.ts:154)是所有 local command 的共享入口,消除了十余处重复 provider construction。authorityStoreSourceAuthority(authority_store.ts:184)从providerKind派生稳定 source label,替代instanceof知识。- PostgreSQL integration test 通过真实 disposable tenant 验证 factory、provider identity、commit 和独立 readback,而不是只验证 mock 构造。
对主干的风险
负向路径覆盖缺失/非法 selector、错误 provider/identity、credential-shaped key 和 selected provider unavailable,均验证 typed rejection 且无 File fallback。full TypeScript 1539 passed/0 failed/1 expected skip,provider-focused 134 passed,real PostgreSQL 103 passed;typecheck、mypy、ruff、coverage 88.53%、canary 和 loopx-meta isolated rehearsal 均通过。最大剩余风险是跨进程长时压力及真实 credential rotation 未覆盖,且这些属于后续 service provider delivery,不是本 PR 的隐式承诺。28 项远程 checks 已全部成功。
我的整体评价
APPROVE。exact head 2fbb128508bec57e37bebf0f25453e3fc0e4cfe8 已完成 rebase 和 freshness readback;这是与现有 RFC 方向一致、范围可控的 runtime ownership refactor。它保留 File/SQLite 旧语义,显式披露 File metadata 变化,并为 PostgreSQL 提供不越权的中期切换 seam。没有发现 P0/P1 或其它阻塞 finding。
English verdict: APPROVE — exact head reviewed; no blocking findings. All 28 remote checks and the local real-provider validation passed. The PR is ready for merge-readiness evaluation; the author-owned limitation is GitHub’s formal self-approval rule.
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
2fbb128 to
9d30498
Compare
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机
4317 解决的是 provider routing 的实际分叉:旧实现让多个 local command 各自组合 createStore/openLocalAuthorityStore,source authority 又依赖 SQLite instanceof。这样 File 默认虽能工作,却无法证明所有 caller 在 provider 切换时选择同一后端;未来 PostgreSQL 还会有 credential、tenant 和 fallback 边界风险。现在无 selector 明确得到 File/file_v0,SQLite 只在显式 marker 下打开,PostgreSQL 只接受 service-owned factory 和 identity binding。
改动思路
以现有 AuthorityStore 为 durable state owner,在 coordination provider boundary 增加 typed providerKind、source authority helper、严格 selector decoder 和 LocalAuthorityStoreHandle;在 runtime 增加唯一 openRuntimeStore,所有 monitor、promotion、todo、read/list 和 mutation caller 都复用它。selector 只保存 public binding facts,credential/client 留在 service-owned factory;selected provider 不可用、provider/identity 不匹配时 typed fail closed,禁止静默 fallback。File/SQLite backend 继续保留各自不可约的资源语义。
具体改动
新增 File/SQLite/PostgreSQL/Nokv provider metadata 与 file_v0/sqlite_v0/postgresql_v0 source projection;local_authority_provider.ts 统一默认 File、SQLite identity fencing、PostgreSQL factory seam、exact-key decoding 和 legacy wrapper。local_authority_runtime.ts 删除重复的 per-command opening 分支,并让 sourceAuthorityFor 读取 typed metadata。RFC/docs 明确 default-off、credential privacy、no authority/cutover grant 和 rollback。fixture 增加 provider matrix;测试覆盖正向 handle、错误 provider/identity、credential-shaped field、无 fallback,并用 disposable PostgreSQL 做 tenant commit/readback。
关键代码讲解
openLocalAuthorityStoreHandle(local_authority_provider.ts:192)是选择与 fail-closed 的唯一 owner:缺 selector -> File,显式 provider -> strict decode/identity check,失败不回退。openRuntimeStore(local_authority_runtime.ts:154)是所有 local command 的共享入口,消除了十余处重复 provider construction。authorityStoreSourceAuthority(authority_store.ts:184)从providerKind派生稳定 source label,替代instanceof知识。- PostgreSQL integration test 通过真实 disposable tenant 验证 factory、provider identity、commit 和独立 readback,而不是只验证 mock 构造。
对主干的风险
负向路径覆盖缺失/非法 selector、错误 provider/identity、credential-shaped key 和 selected provider unavailable,均验证 typed rejection 且无 File fallback。full TypeScript 1539 passed/0 failed/1 expected skip,provider-focused 134 passed,real PostgreSQL 103 passed;typecheck、mypy、ruff、coverage 88.53%、canary 和 loopx-meta isolated rehearsal 均通过。最大剩余风险是跨进程长时压力及真实 credential rotation 未覆盖,且这些属于后续 service provider delivery,不是本 PR 的隐式承诺。28 项远程 checks 已全部成功。
我的整体评价
APPROVE。exact head 9d30498271ad5e5797790bb91ac53c298104ca07 已完成再次 rebase 和 freshness readback;这是与现有 RFC 方向一致、范围可控的 runtime ownership refactor。它保留 File/SQLite 旧语义,显式披露 File metadata 变化,并为 PostgreSQL 提供不越权的中期切换 seam。没有发现 P0/P1 或其它阻塞 finding。
English verdict: APPROVE — exact head 9d30498 reviewed; no blocking findings. All 28 remote checks and the local real-provider validation passed. The author-owned limitation is GitHub’s formal self-approval rule; merge-readiness is checked separately.
Summary
This PR is a clean rebase of the provider/runtime slice onto the current
main. It establishes one typed local authority opening boundary for the File default, opt-in SQLite profile, and medium-term switchable PostgreSQL profile. The branch intentionally contains only the three provider commits plus one compatibility refine; the unrelated stacked history from #4292 has been removed from this PR's diff.Semantic changes and fixes
file_v0). An initialized SQLite database with a missing selector fails closed; there is no silent File or Markdown fallback.postgresql_v0.goal_id,tenant_id, andstore_identity; credentials, URLs, and database clients cannot be persisted in the marker.AuthorityStore, and is identity-fenced before commands execute. Missing factories, wrong providers, identity drift, and open failures are typed and never fall back.openRuntimeStoreseam. The source-compatibleopenLocalAuthorityStorefacade remains, while duplicated provider construction and implementation-based source inference are removed.Promotion, writer-fence, D2 soak/retention, and D3 whole-Goal cutover holds are unchanged. This PR does not promote SQLite, migrate a whole Goal, or claim an authenticated PostgreSQL service.
Scope and migration economics
18 files, 556 additions and 64 deletions: runtime/API changes, provider-switching fixture/conformance coverage, and bilingual RFC/reference documentation. The existing coordination/Todo owner is sufficient; no new capability or extension is introduced. The typed
AuthorityStoreremains the semantic boundary; provider-specific stores only implement persistence primitives.The key consolidation is one runtime opening path plus explicit provider metadata. The remaining facade is retained only for source compatibility; its exit trigger is migration of external callers to the typed handle. PostgreSQL credentials remain service-owned and are not part of local state.
Validation
npm run typecheck:control-plane— passed.22.22.3/ SQLite3.51.3:npm run test:control-plane— 1,511 passed, 0 failed, 1 expected PostgreSQL-unconfigured skip; coverage run passed with the same counts and 88.39% statements.python -m mypy— passed for the configured 22 source files.tests,loopx/canary,loopx/control_plane,loopx/domain_packs, andloopx/presentation— passed.authority-three-arm-rehearsal.pyagainst the localloopx-metasnapshot — passed with exact provider heads/receipts, exact legacy semantics/order, andsource_unchanged=true; all mutations were disposable.loopx canary premerge --from-git-diff --git-diff-base origin/main --goal-id loopx-meta— 17 selected/executed checks, zero failures, zero manual holds; public-boundary scan clean for all 18 changed files.loopx-metadiagnose/status/history/quota checks completed; no registry, Todo, lease, goal state, or receipt was written.The unbounded full Python repository suite is not used as a merge gate. The changed-surface static checks, full TypeScript suite, real File/SQLite and PostgreSQL paths, synthetic fixture, and repository canary are the selected evidence for this provider seam.
Self-repair / review hygiene
The original PR was
DIRTY/CONFLICTINGbecause its base was stale and it carried a long unrelated stacked history. I rebuilt the branch from currentmain, cherry-picked only the provider/runtime commits, resolved the RFC checkpoint conflict by retaining both manager and provider-boundary sections, and added a bounded refine after typecheck caught a compatibility regression:sourceAuthorityForremains exported for existing handoff callers. Every commit has a DCO sign-off.This PR advances the File/SQLite default direction and PostgreSQL switchability without changing defaults or authority promotion. It remains independent of whole-Goal cutover and the separate terminal/archive/presentation work.