Skip to content

[P2][架构] PostgreSQL 会话继承具体 SQLite 会话,存储后端与共享契约职责混合 #157

Closed

Description

@LIghtJUNction

范围与基线

架构审查项,只检查继承关系、接口归属和存储模块边界;不据此断言 SQL、隔离级别或并发实现存在缺陷。

基线:476e64f04ed1d9c7dcab4a41c4f3cdb72faad6a7。Refs #85;与 #65 的存量迁移验收、#69 的恢复验收是不同范围。

结构证据

  • core/contracts.py 已定义 MetadataSession、MetadataStore,事务接口返回元数据会话契约。
  • storage/postgres.py 导入 msg.storage.sqlite.SqliteSession,声明 class PostgresSession(SqliteSession)。
  • storage/sqlite.py 因此同时承载一个具体后端和生产 PostgreSQL 会话所继承的行为。
  • PostgreSQL 模块的说明明确保留跨进程/主机的连接级 advisory lock 和会话连接约束。这些是需要继续明确表达的后端语义,不能在抽取公共代码时抹去。

类声明搜索索引当时指向父提交 01e39345c755d6ec8f584534de20d9cd265ca922;已分别读取父提交和本次基线的文件元数据,二者 postgres.py blob 均为 5ac02cff5b7b048a84e4812c60502ffba889c9c1,不是用旧实现推断新结构。

架构问题

生产后端并未只依赖共同契约,而是继承另一个具体数据库后端。共享的元数据行为与 SQLite 适配职责没有清晰分开,导致“修改 SQLite 后端”也可能改变 PostgreSQL 的继承行为。

这不代表继承一定导致运行错误;问题在于所有权和替换边界不准确。维护者难以仅根据包名和类关系判断:哪些是共同数据访问规则,哪些是 SQLite 约束,哪些是 PostgreSQL 专有事务保证。用这种继承关系复用代码,也不等同于两个独立后端通过同一契约验收。

建议的目标结构

保留 PostgreSQL 作为唯一生产权威数据库,也保留现有测试/辅助后端;不新增数据库服务、通用 ORM 或每个业务名词一套 Repository。

只将真正可共享的会话辅助行为放到后端中立的位置,采用小型共享基类或组合均可。PostgreSQL 与 SQLite 的具体适配器分别依赖公共契约/公共机制,不再让前者继承后者。连接、事务、锁、SQL 方言、约束和迁移仍归各自后端,不以“统一”为由削弱 PostgreSQL 保证。

                 MetadataSession 契约
                   /            \
         PostgreSQL 适配器     SQLite/测试适配器
                   \            /
                   必要的共享机制

验收条件

  • PostgresSession 不再继承具体 SqliteSession,且生产存储模块不导入 SQLite 适配模块作为其行为底座。
  • 明确记录公共机制与后端专有职责;不是只把 SqliteSession 换个中性名字,却仍把 SQLite 连接/方言混在公共层。
  • MetadataStore/MetadataSession 的实际依赖与声明一致,必要扩展显式记录,不用万能对象绕过边界。
  • 同一组存储契约验收分别运行于测试后端和真实 PostgreSQL;后者另保留其事务、锁、唯一约束和并发回归。
  • 不改变数据库 schema、历史 ID、账项、签名或 receipt;需要迁移的额外变化另行提案,不与这次类关系调整捆绑。
  • 现有 LedgerAccount 迁移、恢复隔离及提交/回滚回归保持,不以 SQLite 通过代替 PostgreSQL 通过。

依据权威设计第11、14、15章。保持模块化单体;无需全仓搬目录。本 issue 不授权生产迁移或恢复。

Activity

  1. LIghtJUNction commented on Sep 28, 2026

    @LIghtJUNction
    ContributorAuthor

    第二轮架构补充:除后端继承外,声明的存储接口也未覆盖真实依赖

    基线仍为 476e64f04ed1d9c7dcab4a41c4f3cdb72faad6a7。这是本 issue「实际依赖与契约一致」验收项的具体证据,不另开重复 issue。

    结构证据

    • core/contracts.py 中 MetadataStore.transaction() 返回 MetadataSession;该 Protocol 声明资源、身份、证书、分片、事件等操作,但没有 one 或 execute。
    • core/models.py 的 OperationSpec.handler/requirements 也把会话参数描述为 MetadataSession。
    • storage/sqlite.py 和 storage/postgres.py 的具体会话却提供 execute(self, sql, parameters=(), *, write=False)。
    • 实际跨模块依赖包括 plugins.money._balance、market.policy.load_policy、market.targets.validate_target、security.vault._open、extensions.keystore 等对 tx.one 的使用,以及 workers.maintenance 对 tx.execute 的使用。可从这些模块的调用符号与会话方法声明核对;本轮没有检查查询条件、SQL 正确性或事务实现。

    架构含义

    一个满足已声明 MetadataSession 的替代会话,仍未必满足这些调用者的真实需求。业务/安全/扩展层还隐含依赖数据库查询接口及表结构,因此只解除 PostgresSession(SqliteSession) 的继承关系,不能独立解决存储抽象失真。

    这不意味着直接写 SQL 天生错误,也不证明现有会话会绕过只读/事务保护;缺少类型注解本身同样不是故障。问题是工程对外宣称的接口范围与实际依赖范围不同。

    请在原验收中明确选择

    可以保留 SQL 型模块化单体:显式声明受限查询会话的参数、返回类型、错误和事务所有权,限定哪些模块可依赖它。也可以只把关键跨域数据访问收敛到小型有类型接口。两种路线都比名义上只依赖 MetadataSession、实际使用额外方法更清楚。

    不要求为每张表新增 Repository、不引入 ORM、不把全部业务方法塞进一个更大的万能 Session,也不把裸连接及 commit 权限公开给 handler。

    建议补充检查:选取真实业务消费者,通过声明的接口类型完成装配/契约检查;存储层变化不能依靠 Any 或放宽断言掩盖缺失方法。继续保留唯一事务提交者、真实 PostgreSQL、当前授权、账本及恢复回归。

  2. LIghtJUNction commented on Sep 28, 2026

    @LIghtJUNction
    ContributorAuthor

    本会话接续处理本 issue,独立分支 fix/storage-session-20260929-2050(与#156/#160不共用源分支)。保留SQL型模块化单体:拆出真正不持有数据库连接/方言的共享会话逻辑;SQLite/PG各自管理连接、锁、迁移、事务及错误映射。同时补显式受限查询接口与结果读取接口,选择真实policy消费者验证声明,不新增逐表Repository/ORM,不改schema/账本历史。先提交双后端回归,所有执行放云端,包含拒绝只读写入、跨任务/关闭后的会话结果、嵌套回滚与现有补偿写栅栏。

  3. LIghtJUNction commented on Sep 28, 2026

    @LIghtJUNction
    ContributorAuthor

    认领并实施于独立 PR #166,分支 fix/metadata-session-boundary-20260929;不重叠 #165 的执行内核/工具契约与 #155 恢复实现。

    已取得真实 red:Actions 36481798533,精确 head 7f8752e37fe5b5a8021f192b87e731caec2bbc2d / tree 686dbddc1bdfc52d97c127bdb7338f002cabf735。16 项中 4 failed / 12 passed / 0 error / 0 skip:4项失败均为本 issue 的依赖/归属问题;资源世代、事件/回执/审计/任务持久化、保存点与补偿、只读/跨任务/关闭保护、唯一约束回滚及占位符/字面量的两后端回归都已通过。下载产物10997260030的SHA-256与提供方一致(50ae1ff1b71684d60e0ff133cde41c6cb81658c0855aeb9c376fff110dc27e2e)。

    下一提交仅提取共同模型查询/会话约束到中立 storage.session.MetadataSessionBase,两驱动分别持有自己的连接和 execute;PostgreSQL advisory lock、事务/补偿、SQL/error适配及两边schema/migration保持不变。将对原共享方法与store类做逐方法结构一致性核对并上传证据。笔记:docs/METADATA_SESSION_PROGRESS.md。当前仍是回归先行,未声明修复完成。

  4. LIghtJUNction commented on Sep 29, 2026

    @LIghtJUNction
    ContributorAuthor

    架构验收完成,按已合入源码关闭

    唯一实现随PR #167于2026-09-29T08:58:23Z合入main 261c881 / tree 6171f6041ffd0addaf72eadd35acf562f478281f。#166的16个双后端补充用例和历史均保留,没有叠入第二份基类实现。

    • PostgresSession与SqliteSession独立继承storage.session.RelationalSession;生产PG导入会被测试环境主动禁止SQLite模块/驱动,当前仍可通过。
    • 共享层只持有域查询和任务/生命周期约束;构造只收write,不持有连接、方言、schema、PRAGMA、commit/rollback或advisory锁。驱动仍分别拥有execute和事务机制。职责记录在session模块及docs/ISSUE_PROGRESS.md。
    • core.query.QuerySession/QueryResult明确受限SQL参数/结果/错误/事务所有权;MetadataSession补齐真实域方法,无connection/commit/万能对象。实际market.policy.load_policy使用声明接口,通过真实已存政策、损坏digest拒绝、双后端嵌套回滚验证,不只检查一个假会话。
    • test_session_boundary.py及test_metadata_session_boundary.py在真实PG和SQLite分别运行,含会话/结果跨任务与关闭保护、保存点补偿、资源世代/路径/分页、事件/审计/作业、约束冲突、占位符/字面量。PG原锁与并发回归保留。
    • 本次按共享会话归属调整,不引入新的迁移/ORM/生产数据库,不重写历史ID、账本或签署/receipt;原schema/Store/事务保证的对照记录和回归保留于#167及既有笔记。
    • 旧LedgerAccount迁移、恢复隔离、回滚写栅栏纳入完整1,894/1,894去重node通过,0失败/错误/跳过;另8conformance及wheel/sdist/contracts门槛通过。已逐个读取4份JUnit/selected/all清单并校验散列,详情 refactor: repair executor and storage boundaries with cloud regression evidence #167 comment5887987237。合并后main全量36546119029与恢复36546118849也success。

    SQLite的政策表仅隔离fixture复用真实DDL,不把测试辅助后端说成完整生产市场等价实现。#65真实旧库迁移、#69恢复、#85总体验收仍独立开放。此关闭不表示生产部署或生产迁移已执行。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions