Skip to content

Commit a54739e

Browse files
authored
Compact File authority history with recognized, backed-up format upgrades (#5102)
* Compact File authority history and migrate formats through verified upgrade backups Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> * Qualify backed-up upgrades, retained history and provider interchange Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> * Identify storage artifacts before migration and guard update recovery Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> * Retain completed migration results when later store discovery fails Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> * test(authority): qualify all-known upgrade discovery scope Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> --------- Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com> Co-authored-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
1 parent 59734fd commit a54739e

22 files changed

Lines changed: 1298 additions & 98 deletions

‎docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-24-default-cutover-reconciliation.md‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
- Baseline: `41ba6f4d9` on `main`, 2026-09-25; open PR states are a snapshot, not merge promises.
44
- Owners: overall roadmap #4574 R5/G2; shared authority L2–L9/D1–D3; TS migration T1–T4.
55
- Delivered #5040: current registration admission, complete saved migration intent and truthful fence recovery.
6-
- Current increment: long-history closeout reuse and TS-owned monitor evidence; the migration packages below remain open.
6+
- Current increment: File retained-state compaction stacked on #5063; the migration packages below remain open. #5063 has now merged; rebased onto main `eaa0c0fd0`.
77
- This checkpoint supersedes numerical remaining-PR estimates in earlier delivery entries.
88

99
## Correct the accounting
@@ -32,6 +32,27 @@ transaction, complete-source and source-witness owners. The latest formal #4224
3232
(801.81 ms versus 250 ms). #4931 has not supplied a formal exact-head rerun.
3333
Reaching the planned ten-day soak end date is not a passing report.
3434

35+
## File history cost: delivered slice, separate acceptance
36+
37+
A detached long-history snapshot exposed File's repeated full-projection write
38+
cost. #5063 bounds RPC waits and retains verified read views; it does not remove
39+
that physical duplication. This stack reuses the SQLite-owned shared TS state-log
40+
codec for File checkpoints/deltas, preserving logical revisions, receipts and
41+
full scan results. See [format, upgrade and limits](../../../../reference/file-authority-state-log.md).
42+
Normal reads/writes accept only v1. Explicit upgrade automatically backs up and
43+
verifies File/SQLite before physical migration, and installation invokes it before
44+
activation. Cross-provider movement reuses logical archive recovery. Older binaries
45+
cannot read v1. Conversion, cold verification,
46+
steady writes and warm reads require separate evidence; cache limits are unchanged.
47+
48+
Before this slice, the audited implementation plan therefore contains **four
49+
named packages**: this evidenced File cost repair plus the three below. After
50+
this slice it contains those **three planned packages**, not a new unchanged
51+
“5–8 PRs” estimate. #5063, #5054 and #4931 are existing PRs, not three new tasks.
52+
D1–D3 and an exact total PR count remain unqualified. This storage repair retires
53+
no Python business owner; bounded Python deletion belongs to actual caller
54+
migration in the packages below.
55+
3556
## Three concrete next code boundaries
3657

3758
This delivery repairs integrated migration admission: stale registry snapshots
@@ -41,7 +62,7 @@ not implement another store or close the whole migration package or D2 gate.
4162
| Proposed PR | Observable result and owner | Exit |
4263
| --- | --- | --- |
4364
| 1. External-effect execution fencing | Lease/effect owners protect the actual execution interval, takeover, timeout, exit and uncertain completion. Reuse merged #4994/#4995. | Stale executors cannot continue or settle; real executor and receipt recovery matrix passes. A point-in-time proof check is insufficient. |
44-
| 2. Event-writer binding and whole-Goal migration/rollback | Bind event writer locks/atomic publication to existing outbox; integrate Markdown/event/lease capture, drain, saved cutover, consumers and fenced export/rollback; delete Python decisions replaced by TS. | Reuse #5003. Retain `event_log_writer_not_bound` until binding passes; close D1, command inventory and D3 cohort. One Goal without an event overlay does not prove this package. |
65+
| 2. Whole-Goal migration/rollback and retained source closure | Reconcile open #5054, which retires the legacy Todo event path and isolates supervisor logging; do not build another capture writer for a retired source. Integrate remaining supported sources, drain, saved cutover, consumers and fenced export/rollback; delete Python decisions replaced by TS. | Prove the supported command/source inventory after #5054, D1 and the D3 cohort; reject retired input explicitly. One Goal without a legacy event overlay does not prove every retained caller or rollback path. |
4566
| 3. Default entrypoints and bounded Python retirement | New Goals, settings, installation and packaged frontend/Lark/CLI select a qualified profile consistently; existing Goals have explicit migration/disable flows. | 1/2 and applicable D1–D3 pass; user entrypoints work; delete business writers only after their last callers migrate. Retain rendering, host IO and lawful import/export. |
4667

4768
**Plan three named future implementation PRs, plus existing #4931 and outstanding

‎docs/architecture/rfcs/ledger/shared-goal-authority-state-provider-v0/2026-09-24-default-cutover-reconciliation.zh-CN.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@
66
- 当前增量:长历史 closeout 读取复用与 TS monitor 回执归一;没有完成下列迁移工作包。
77
- 本检查点取代此前交付记录中的剩余 PR 数量估算。
88

9+
## File 历史编码与自动升级增量
10+
11+
本次最初 stack 在 #5063 上;#5063 合入后已接到 main `eaa0c0fd0`。
12+
#5063 解决读取缓存和 RPC 预算,File 每次写入仍复制全历史完整投影。本次复用
13+
SQLite 已有 TS checkpoint/delta 编码,保留原始版本、回执和完整扫描结果。
14+
正常读写只接受新格式;安装/更新通过统一命令先自动备份、验证再迁移,旧解析
15+
只留在迁移工具。跨 provider 则复用逻辑归档,不新增两两转换器。
16+
[格式、备份迁移及成本边界](../../../../reference/file-authority-state-log.md)。
17+
18+
当前增量前是四个具名开发包:本次有实际证据的 File 成本/升级修复,加下文三个
19+
业务边界;完成本次后仍剩三个规划包,不是继续复述“5–8 PR”。#5063、#5054、
20+
#4931 是已有 PR,不能重复计为新任务。D1–D3 的未通过证据另列,不能保证总 PR 数。
21+
本次没有删除 Python 业务 owner,只有升级命令的薄适配。
22+
23+
整 Goal 来源闭环须按 #5054 当前方向核对:它退役旧 Todo event 路径并分离 supervisor
24+
日志,不应为已经退役的来源重建捕获 writer。剩余支持来源、consumer、回退与 cohort
25+
仍需完整验证。
26+
927
## 先纠正统计口径
1028

1129
此前“5–8”“6–8”“7–9”把宽泛工作包写成剩余 PR 数,部分实现合入、额外前置项

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ bounded Python retirement. #4931 and outstanding D2 evidence are tracked
3434
separately. Three is a delivery plan, not a guaranteed total PR count.
3535
[Current inventory and exits](ledger/shared-goal-authority-state-provider-v0/2026-09-24-default-cutover-reconciliation.md).
3636

37+
File retained-state storage now reuses the existing TS checkpoint/delta codec,
38+
stacked on #5063's verified read cache and RPC budgets. Original revisions,
39+
receipts and full historical projections survive the physical format upgrade.
40+
Normal reads/writes require v1. Installation runs explicit, verified backup and
41+
format migration; legacy decoding exists only in the migration owner. File and
42+
SQLite reuse logical archives for cross-provider isolated recovery.
43+
This adds no provider/default promotion and retires no Python business owner.
44+
[Automatic backup/migration, cold costs and qualification limits](../../reference/file-authority-state-log.md).
45+
46+
3747
## Persistence route for steward scale (2026-09-16)
3848

3949
[Roadmap](loopx-overall-roadmap-v0.md) R5 reuses D1 projection, D2 real-backend/capacity/applicable ten-day soak and D3 fenced cutover. R6 connects the selected shared profile to authenticated local/cloud execution. R1–R3 can advance on supported profiles without waiting for PostgreSQL or whole-Goal default promotion.

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.zh-CN.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828
默认启用与最后一批有界 Python 退役。#4931 与 D2 的剩余资格证据单列;三个是
2929
可命名的开发批次,不是保证总 PR 数。[唯一当前清单与退出条件](ledger/shared-goal-authority-state-provider-v0/2026-09-24-default-cutover-reconciliation.zh-CN.md)。
3030

31+
File 历史存储在 #5063 的读取缓存和 RPC 预算之上,复用现有 TS checkpoint/delta
32+
编码;物理格式升级保留原版本、回执和每条完整历史投影。正常读写只接受 v1,
33+
安装入口调用显式升级流程,先自动备份、验证再迁移;旧解析器仅用于迁移。File/
34+
SQLite 跨 provider 恢复复用逻辑归档。这不晋升 provider/默认值,也不算删除 Python
35+
业务 owner。[自动备份迁移、冷读成本与验收边界](../../reference/file-authority-state-log.md)。
36+
37+
3138
## 旧观测退役检查点(2026-09-24)
3239

3340
[当前交付清单](ledger/shared-goal-authority-state-provider-v0/2026-09-24-observation-retirement.zh-CN.md)
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Authority format upgrade and File retained state
2+
3+
The File provider retains its `AuthorityStore` contract and `file_v0` routing
4+
identity. The physical document changes from `loopx_file_authority_store_v0` to
5+
`loopx_file_authority_store_v1`. This does not promote a Goal or select a provider.
6+
7+
## Storage and semantics
8+
9+
| | Old File document | Current File document |
10+
| --- | --- | --- |
11+
| Each committed row | Complete projection | Checkpoint at cursors 1, 65, 129, …; exact delta otherwise |
12+
| Events, operation ID, original receipts | Retained | Retained without rewriting |
13+
| Cursor and provider revision | Logical transaction identity | Identical after physical upgrade |
14+
| Historical reads | Full stored projection | Reconstruct the same projection from nearest checkpoint |
15+
| Runtime acceptance | Migration input only | Normal reads and writes |
16+
17+
File reuses the TypeScript state-delta codec already used by SQLite. Object-key
18+
changes and array splices preserve all JSON data, including empty and `__proto__`
19+
keys. Writers prove reconstruction. Revisions still hash the logical full
20+
transaction, previous revision and store identity. The ledger remains logically
21+
append-only even though File atomically replaces its physical envelope.
22+
23+
Cold reads verify every retained transaction and the final head; a valid head
24+
cannot hide a corrupt old delta or receipt. Verified pagination reconstructs at
25+
most 63 predecessor deltas plus the requested page. The exact-byte cache remains
26+
bounded. File still reads/hashes and rewrites one retained file: this reduces
27+
repeated data, not asymptotic growth. Cold verification can be slower. Measure
28+
upgrade, cold verification, warm reads and steady writes separately.
29+
30+
## Format recognition
31+
32+
```bash
33+
loopx --format json authority-archive inspect --source /absolute/store-or-backup
34+
```
35+
36+
Recognition uses JSON schema tags or the SQLite file header plus database
37+
metadata and `user_version`, not filename extensions. It reports artifact kind,
38+
provider, physical format, Goal/store identity and migration route. Unknown
39+
versions and inconsistent SQLite version pairs are rejected by automatic
40+
upgrade. A recognized provider selector is only a routing record; PostgreSQL
41+
and NoKV still require their configured provider service for export.
42+
43+
`metadata_only` recognition is not full history verification. Logical archives
44+
are verified through their complete digest/seal contract; backup packages check
45+
source bytes and lineage. Upgrade subsequently validates the complete store
46+
under its publication boundary. Multiple local stores are reported/upgraded
47+
independently, never silently chosen as a new live authority.
48+
49+
Legacy Markdown/sidecar capture, project registry envelopes and shadow/outbox
50+
control records have different owners. They are not alternate File database
51+
encodings and are not rewritten by this command. Whole-Goal migration must use
52+
its source capture and writer-fence workflow.
53+
54+
## Automatic upgrade and backups
55+
56+
Normal readers and writers **do not accept the old File format**. Old parsing
57+
belongs only to migration. There is no migration-on-read or first-business-write
58+
conversion. SQLite's existing v1-to-v2 converter follows the same explicit gate.
59+
60+
Default local installation and Windows installation run the candidate's upgrade
61+
command before launcher activation. `loopx update apply` for pip/pipx runs it
62+
after package installation and before host updates or service restart. Canary
63+
installation does not migrate stores. Source checkouts and externally managed
64+
package updates use the same explicit command:
65+
66+
```bash
67+
# Preview selected runtime; global --runtime-root and --registry are supported.
68+
loopx --format json authority-archive upgrade
69+
# Back up and migrate known runtime roots from existing project registrations.
70+
loopx --format json authority-archive upgrade --all-known --execute
71+
# Read-only compatibility gate, also used before binary rollback.
72+
loopx --format json authority-archive upgrade --all-known --require-current
73+
```
74+
75+
Discovery includes File and SQLite stores in each known runtime's authority
76+
folders, including unselected shadows and File rollback documents. It does not
77+
scan arbitrary home directories. Disconnected custom runtime roots must be
78+
supplied explicitly. Selectors, registries, writer fences and execution leases
79+
are not changed by format upgrade.
80+
81+
Each store has its own durable publication boundary:
82+
83+
- File holds the ordinary writer lock, verifies the entire old history, encodes
84+
and decodes the target, and compares logical history digests. It saves exact
85+
source bytes plus store identity under `format-backups/<source-sha256>/`,
86+
verifies the backup and syncs directory entries before atomic replacement.
87+
- SQLite makes an online consistent backup, including committed WAL data. A
88+
disposable copy proves the backup through the actual v1-to-v2 converter.
89+
The source migration compares that history digest under `BEGIN IMMEDIATE`
90+
before adopting new tables. Concurrent source advancement aborts the upgrade;
91+
retry takes a fresh backup. It never silently discards intervening commits.
92+
- A manifest records source/target format, identity and integrity evidence.
93+
File recovery uses manifest hashes and actual source/target bytes, not a
94+
mutable completion flag. Interrupted conversion is retriable: before publish
95+
the old store remains; after publish the new store is already current.
96+
97+
Unknown formats, corrupt history, failed backups or failed validation stop the
98+
upgrade. A multi-store upgrade can have completed earlier stores when a later
99+
one fails; the report retains those results. Retry resumes per store. It does
100+
not pretend to roll back the whole runtime or overwrite later business writes.
101+
For package-manager updates, a failed data upgrade does not undo the package
102+
installation; service activation remains blocked until repair.
103+
104+
## Provider migration and recovery
105+
106+
Physical format upgrade preserves provider identity and old revisions. Changing
107+
providers uses the existing portable logical archive as the interchange format:
108+
109+
```bash
110+
loopx --format json authority-archive export --goal-id example --archive /absolute/history.ndjson
111+
loopx --format json authority-archive verify --archive /absolute/history.ndjson
112+
loopx --format json authority-archive restore --goal-id example --archive /absolute/history.ndjson \
113+
--destination /absolute/new-isolated-store --provider sqlite --archive-sha256 DIGEST --execute
114+
```
115+
116+
File/SQLite exports restore into either File or SQLite. Restore creates a new
117+
provider identity/revisions while preserving logical history and receipts; it
118+
never selects the restored directory as live authority. This avoids one
119+
converter for every pair of storage formats. PostgreSQL's existing archive
120+
source contract remains unchanged; authenticated service activation, cutover
121+
and PostgreSQL destination administration are separate work.
122+
123+
Old raw backups can be copied into an **isolated** provider directory, with their
124+
original identity and canonical filename, then upgraded and exported. Never
125+
rewrite a schema label or restore an old backup over newer acknowledged writes.
126+
Binary rollback requires the target runtime to pass `--require-current`; an old
127+
binary without that gate is not automatically activated. Data rollback and
128+
provider cutover require their own reviewed, fenced recovery operation.
129+
130+
## Qualification and limits
131+
132+
Tests cover legacy rejection, original historical identity/receipts, checkpoint
133+
pagination, malformed history, backup damage, interruptions around rename,
134+
competing migration processes, real SQLite backup/migration, and File/SQLite
135+
archive interchange. CLI validation uses the managed TS runtime. An authorized
136+
detached long-history snapshot additionally checks source immutability, exact
137+
backup bytes and every historical transaction/receipt against the parent.
138+
139+
The CLI/install surfaces change; frontend and Lark business commands continue
140+
using the unchanged provider contract and need no new settings. This does not
141+
close default-provider promotion, D1–D3, PostgreSQL production qualification or
142+
Python business-owner retirement. Native Windows execution still requires its
143+
platform CI evidence; POSIX validation does not substitute for it.
144+
145+
## 中文要点
146+
147+
旧 File 每次提交都复制完整状态;新格式每 64 条保留完整检查点,其余保存差量。
148+
事件、原始回执、操作身份、版本号和历史内容不变。复用 SQLite 的 TS 编码规则,
149+
不删除 append-only ledger 抽象,也不切换 provider。
150+
151+
正常读写只接受新格式。安装/更新调用统一升级入口:先验证、自动备份并核对,
152+
再迁移和读回;源码开发也可显式调用 `authority-archive upgrade --execute`。
153+
迁移解析旧数据属于升级工具,不是长期运行的旧格式兼容分支。
154+
155+
同 provider 的格式升级保持身份和版本;跨 provider 则用逻辑归档导出、验证、隔离
156+
恢复,生成目标 provider 的新身份和版本,保留历史事实及原始回执。迁移数据不等于
157+
获得执行权,恢复目录不会自动成为线上 authority。
158+
159+
升级失败时可能已有部分 store 完成,必须据实报告并重试,不能覆盖之后产生的写入。
160+
备份仍是旧格式,恢复时应先在隔离目录升级。只回退二进制并不等于安全回退数据。
161+
该方案减少重复存储和后续写入耗时,但冷校验仍验证全历史,可能更慢。

0 commit comments

Comments
 (0)