Skip to content

[#640][CODE] LedgerPage 切 V1 append-only 事实形状 + 严格 decode + cutover consumer pin - #687

Merged
jinjunnn merged 1 commit into
alphafrom
feat/640-ledger-page-v1
Jul 29, 2026
Merged

[#640][CODE] LedgerPage 切 V1 append-only 事实形状 + 严格 decode + cutover consumer pin#687
jinjunnn merged 1 commit into
alphafrom
feat/640-ledger-page-v1

Conversation

@jinjunnn

Copy link
Copy Markdown
Owner

Fixes #640
Refs jinjunnn/alpha-platform#101

这改了什么

alpha-platform 把资金真相源翻到 append-only ledger_facts,LedgerEntryV1
schema_version 不变的前提下原地 breaking:旧的可变流水行
{id, type, title, amount_fen, status} 换成事实行
{seq, op_id, kind, domain, 有符号 amount, created_at(整数毫秒)}
本仓是两个消费方之一,按 portfolio 规矩不做双形状兼容层

勘破:严格 decode 的权威不在 types.ts

decodeContract 校验的是 vendor/alpha-platform/.../alpha-wire-contracts.schema.json
——一份被 alpha-platform-contract.lock.json 逐字节哈希锁住的上游镜像。
只改 types.ts运行时零效果,而且会让 typecheck 说谎(类型说新形状,decode 仍按旧形状拒)。

所以先把 pin 从 bcc60bbf 抬到 2fe1d010,再跑 bun run vendor 让字节与锁一起走:

  • 2fe1d010origin/main 上,且其 contracts/origin/main tip 逐字节相同
    (选它而不是 tip,是因为它是最后一个真正动过 contracts 的 commit)。
  • 18 个受管件里只有两件真的变了:wire schema 与 producer 的 ledger-page.json
    其余 16 件哈希不变——逐件核对过,不是"应该没变"。

代码侧

文件 改动
types.ts LedgerEntryV1 换形状 + LedgerFactKindV1 枚举;created_at 由 ISO 串变整数毫秒
alpha-account.ts decode 后原样带过:不合成 title、不做跨 domain 加总
preload/types.ts AccountTransaction 1:1 镜像事实行;kind 走 type-only import,避免第二处枚举漂移

两条读者必须知道的语义,已写进 docs/contracts/platform-integration.md:
amount 自带符号(不再靠 status 区分收支);单位由 domain 决定——
wallet 计 fen、allowance 计 credits,两个 domain 的金额永远不能相加

另一半:cutover consumer pin

alpha-platform 的部署闸 contracts/v1/consumer-cutover-required.json 要求
alpha-web#81 与本票提交 LedgerPageV1 consumer fixture 且版本对齐,否则
runLedgerCutoverGate fail-closed 阻断账户服务部署。

本 PR 产出 packages/alpha-contracts-consumer/fixtures/consumers/alpha-code-640/ledger-page.json
(内容将由主 session 落进 alpha-platform 的合并 PR)。它落在 vendor/ 之外,
因为 vendor/ 按上游字节哈希锁定,而这份是本仓作者的。

fixture 覆盖了账户面真要扛的东西:wallet + allowance 两个 domain、正负 amount 各有、
window_id / external_ref / action_id / reservation_id 四个可选字段各至少一条。

闸门不是靠声称的

新增两条断言让"消费方确实在新形状上"被执行:

  1. pin 走出货的 decodeJsonContract("LedgerPageV1", ...)——fetchTransactions
    用的正是这一个调用,不是测试里另写的替身。
  2. pin 的 consumer_version 必须等于 ui-mac 的 package version(防 pin 陈旧,
    正是 platform 闸的 consumer pin version mismatch 那条)。

原来那条 LedgerPage drift 测试改的是 status = "pending"——新形状里根本没有 status,
它会退化成"未知字段被拒"而不再检验枚举漂移。改成 kind 漂移,并补一条:
切换前的旧行形状现在必须被拒(哪天它变绿,就说明兼容层长回来了)。

我自己先把绕过实施了一遍,确认这两条不是白绿——用 pin 的 schema 编译验证器:

OLD schema accepts the #640 pin (new shape)? false  <- 新 fixture 在旧闸下会红
OLD schema accepts the pre-cut legacy row?   true   <- 旧行在旧闸下是合法的

本地门(真实输出)

bash scripts/alpha-check.sh 在 worktree(已跑 worktree-link-deps.sh 补齐各包软链):

▶ [1/3] north-star guard (zero upstream edits)
    ✓ zero upstream package edits
▶ [2/3] typecheck (alpha packages: contracts-consumer + ext + ui-mac)
    ✓ typecheck
▶ [3/3] contract lock + unit tests
verified 18 contract artifacts from jinjunnn/alpha-platform@2fe1d0103b7c3f68acb98c44d13ed0fcfe8bf196
verified 3 contract artifacts from jinjunnn/alpha-web@b597f0d548db9ffafc6d6301e548dbd323c810ad
 22 pass / 0 fail   (contracts-consumer)
 132 pass / 0 fail  (ext)
 3163 pass / 0 fail (ui-mac)
✅ all local gates green

与 base fail-set 的差:同一 worktree 在动笔前跑过同一条门,
19 / 132 / 3163,0 fail,exit 0。唯一的差是 contracts-consumer 19 → 22
(本 PR 新增 3 条)。没有任何假红需要解释。

CI 另外跑而 alpha-check.sh 不跑的两道也单独跑了:
scripts/assert-gate-files.sh✓ 40 个闸门文件全部在位且真的跑过;
docs gate python3 scripts/check-doc-links.py docs/contracts/platform-integration.md
✓ 5 relative link(s) resolve across 1 file(s)

--check删掉 .upstream-contracts 暂存目录后复跑过一次(与 CI 同构,
只比 lock 与 vendored 字节),仍绿。

…onsumer pin

platform#101 把资金真相源翻转到 append-only ledger_facts,LedgerEntryV1 在
schema_version 不变的前提下原地 breaking:旧的可变流水行
{id,type,title,amount_fen,status} 换成事实行
{seq,op_id,kind,domain,有符号 amount,created_at(ms)}。本仓是两个消费方之一,
不做双形状兼容层。

严格 decode 的权威是 vendor/ 下被哈希锁钉住的 JSON Schema,不是 types.ts ——
所以先把 alpha-platform 的 pin 从 bcc60bbf 抬到 2fe1d010(该 commit 在
origin/main 上,且 contracts/ 与 origin/main tip 逐字节相同),重跑 vendor 脚本
让锁与字节一起走。18 个受管件里只有两件真的变了:wire schema 与 producer 的
ledger-page fixture。

- types.ts:LedgerEntryV1 换形状 + LedgerFactKindV1 枚举;created_at 由 ISO 串
  变成整数毫秒。
- alpha-account.ts:decode 后原样带过,不再合成 title、不做跨 domain 加总
  (wallet 计 fen、allowance 计 credits,两者不可相加)。
- preload/types.ts:AccountTransaction 1:1 镜像事实行;kind 用 type-only import
  从契约包取,避免第二处枚举漂移。

另一半交付是 alpha-platform 部署闸要的 consumer pin:
fixtures/consumers/alpha-code-640/ledger-page.json(声明 consumer_version =
ui-mac 的发布版本)。它落在 vendor/ 之外,因为 vendor/ 按上游字节哈希锁定,而这
份是本仓作者的。两条新断言让「消费方确实在新形状上」被执行而不是被声称:pin 走
出货的 decodeJsonContract(fetchTransactions 用的正是这一个调用),以及 pin 的
版本号必须等于 ui-mac 的 package version(防 pin 陈旧)。

原来那条 LedgerPage drift 测试改的是 status="pending" —— 新形状里没有 status,
它会退化成「未知字段被拒」而不再检验枚举漂移,故改成 kind 漂移,并补一条:
切换前的旧行形状现在必须被拒(若哪天变绿,说明兼容层长回来了)。

Fixes #640
Refs jinjunnn/alpha-platform#101
@jinjunnn
jinjunnn merged commit 1622e9c into alpha Jul 29, 2026
6 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.

随 platform ledger V1 hard cut 同步:contracts-consumer LedgerPage 类型/严格 decode + fixture pin

1 participant