黑板事务:共享键值表必须有Schema、模式与提交代次

自动关联目录:黑板事务:共享键值表必须有Schema、模式与提交代次

核心判断:黑板一旦同时服务创作、Undo、DS 运行时和观察者,就不再是 Map<String, Variant>;它需要类型 Schema、写入模式、不可变 Revision 和一次提交只生效一次的代次令牌。

一、实际实现中已经形成的正确边界

工程把创作设计值与服务器运行时覆盖分开,字段先经 Schema 归一化和关系校验。编辑变更先构造 prepared transaction,令牌绑定历史记录 generation 与准备者;提交时通过影子状态交换一次生效,回滚与重复提交都有明确语义。观察者通知在令牌释放后发布,单个观察者报错不会破坏已提交状态。

为了让旧 Undo 数据可恢复,还保留了受信任的 opaque envelope 通道。它是兼容入口,不应成为普通脚本绕过当前 Schema 的写入口。

二、多份“真相”仍需收敛

原始封包、解码设计值、运行时 overlay 和观察者缓存并存时,必须回答哪一个 Revision 是读取基线。若模型已提交,发布副作用却失败,简单回滚模型可能比重试通知更危险;若通知没有提交标识,重试又会重复触发外部动作。

三、目标模型:不可变基线 + 有代次覆盖 + Outbox

struct BlackboardRevision {
    RevisionId id;
    SchemaId schema;
    CanonicalBytes authoringValues;
    Hash contentHash;
};

struct RuntimeOverlay {
    RevisionId base;
    OverlayGeneration generation;
    TypedValueMap values;
};

CommitResult Commit(PreparedBlackboard tx) {
    Require(tx.token.ConsumeOnce());
    Require(CurrentRevision() == tx.expectedRevision);
    auto next = Freeze(tx.shadowValues, tx.schema);
    AtomicSwap(currentRevision, next);
    outbox.Append(tx.effects.WithCommitId(next.id));
    return next.id;
}

读者持有 Revision 快照,不在遍历中观察到半次批量修改。运行时覆盖显式引用基线 Revision;基线更新时按策略重放、丢弃或迁移。发布失败只让 Outbox 重试,不能让已可见模型悄悄倒退。

四、Schema 与模式必须进入权限判断

字段定义至少包含类型、默认值、可空性、范围、关系约束、创作期可写、运行期可写和复制策略。客户端脚本提交的是意图,DS 根据字段模式与行为实例权限重新验证;“值能序列化”不代表允许写。

五、验证与反思

覆盖旧 Schema 迁移、并发 prepared transaction、重复提交、提交后通知失败、观察者重入、overlay 基线更新和受信任 Undo 封包。断言模型 Revision 单调、令牌只消费一次、每个 Effect 以 CommitId 幂等处理。

复盘后的判断是:黑板的难点从来不是 Variant 容器,而是多个生命周期围绕同一字段发生读写时,谁拥有事实、谁能提交、失败后如何继续。