Skip to content

docs(decision): freeze decision protocol v1 contracts - #32

Merged
jamespud merged 5 commits into
mainfrom
codex/cas9-decision-contract
Oct 14, 2026
Merged

jamespud merged 5 commits into
mainfrom
codex/cas9-decision-contract

Conversation

@jamespud

@jamespud jamespud commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

内容

新增 docs/decision-protocol-contract.md,冻结多候选决策协议的领域契约:DecisionCharter → CandidateSnapshot → SealedBallot → BallotSet → DecisionRecord 的字段、状态枚举、不变量,以及与 ContextManifest / AuthorityProof / ExecutionGeneration 的绑定。

这是待独立审阅的冻结草案,不是实现,也不是对 Rev4 规范的修改批准。本 PR 不含任何业务代码或迁移。

Rev4 条款映射

§0.1 逐条回溯(本契约章节 → Rev4 条款 → 关系):

  • DecisionCharter → §2、§3.1–3.4
  • CandidateSnapshot → §4、§9
  • SealedBallot / BallotSet → §6.1–6.2、§10.1–10.2、§17
  • DecisionRecord → §4.3–4.4、§10.3–10.4、§11、§12.1
  • 绑定 → §3.2、§6.2–6.3、§12.2
  • 迁移 → §12.1、§12.3
  • 不变量索引 → §19

扩展不变量编号的定位

§0.2 明确:CHARTER-01..05、CAND-01..04、VOTE-04..11、DEC-01..06、TRIAL-01..02、LEGACY-01..04 是对 Rev4 原始要求(AGENDA-01、SELECT-01..03、VOTE-01..03、REPORT-01 等)的细化编号,不新增、不替换原始验收要求;与 Rev4 冲突时以原文为准并走 Design Change。

身份与绑定边界

  • 三种身份不可互替(§6.4):execution_generation(运行所有权)、决策 round(协议轮次身份)、SealedBallot 签发身份(snapshot_id + persona_spec_id + experience_snapshot_id + user_preference_snapshot_id + context_manifest_id + context_revocation_epoch)。不得仅凭字符串 ID 判定权威性(ID-01..03)。
  • 用户偏好快照:SealedBallot 显式绑定 user_preference_snapshot_id,或冻结唯一 ContextManifest 映射并按同规则校验(VOTE-10)。
  • 独立提交所有权:SealedBallot 提交即校验当前 execution_generation,旧代次写入被拒(VOTE-11)。

状态与裁决语义

  • 候选 APPROVED、全局 SELECTED、人工 HUMAN_SELECTED、执行 AUTHORIZED 四态分离;不沿用条件赞成隐含批准(DEC-04)。
  • 选择结果(selection_state)与提前选择政策(early_selection_policy)分离;REVERSIBLE_TRIAL 必须携带 TrialAuthorization(范围/期限/退出条件/不关闭替代路径/仅 R1/三角色确认),缺任一前提不得产生 SELECTED(TRIAL-01..02)。
  • 判定顺序固定为 BLOCKED → DEFERRED → INCOMPLETE → 计票;已确认硬约束违规无须等待三票,缺席不覆盖先验阻断(VOTE-05)。
  • 少候选意见分两层:候选级 CandidateDissent(必须带 candidate_id 与 ballot_id)与选择级 SelectionDissent;报告按候选分组(DEC-06)。

聚合与提交模型

  • 单人格不可变 SealedBallot(幂等键 (case_id, round, persona_id))与聚合 BallotSet 分层;BallotSet 在三个参与者槽位(SEALED/ABSENT)全部终结后生成,缺席产出不可变的不完整集合,只能得到 INCOMPLETE、先验 BLOCKED 或协议明确允许的结果(VOTE-09)。
  • 决策提交采用方案 A:RESOLVING 只形成 PENDING 待提交记录;唯一权威提交在终态事务中完成(与 Resolution/Case 终态/完成事件同一边界)。独立裁决提交点未冻结,另行设计。
  • 旧 Resolution 不等价为新式 DecisionRecord,不默认补 SELECTED;只能经显式 LegacyProjection(UNVERIFIED_LEGACY)读取(LEGACY-01..04)。

兼容与迁移

CandidateSnapshot 在进入 COLLECTING_VOTES 前冻结;决策结果六维与流程状态分开存储;历史行缺少新字段按“不可证明”处理,不补默认值。

五个实施切片与依赖

§9 冻结切片与依赖:切片 1(契约类型 + 语义验证器)为关键路径;切片 2(CandidateSnapshot 议程)与切片 3(SealedBallot/BallotSet)在切片 1 后可并行开发;切片 4(DecisionRecord 裁决)同时依赖切片 2 与切片 3(需要冻结快照 + 密封票据),端到端集成必须串行;切片 5(维度拆分与迁移 + LegacyProjection)依赖 1–4。DoD 要求结构校验 + 语义校验 + 独立真值表测试。

审阅状态与边界

冻结 ≠ 独立设计审阅通过,也不代表领域协议已实现。合并前需与 Rev4 逐条对照并由独立审阅确认;在此之前不启动切片 1。

审阅修订记录

  • 首轮:F32-01 单候选合法化、F32-02 去除权威 ranking、F32-03 选择结果/政策分离、F32-04 LegacyProjection、F32-05 四阶段截止、F32-06 Dissent 决定值限定、F32-07 依赖图补入切片 2。
  • 第二轮:F32-08 candidate_count 归属冻结快照(CAND-04)、F32-09 先验硬阻断优先于缺席、F32-10 REVERSIBLE_TRIAL 的 TrialAuthorization(TRIAL-01..02)、F32-11 明确方案 A、F32-12 SealedBallot/BallotSet 分层(VOTE-09)、F32-13 显式绑定 user_preference_snapshot_id(VOTE-10)。
  • 第三轮(47a982a):F32-14 候选级/选择级异议拆分(DEC-06、LEGACY-04)、F32-15 参与者槽位聚合与不完整 BallotSet、SealedBallot 独立提交所有权(VOTE-11)、TrialAuthorization.risk_level 收紧为 enum{R1}。

审阅重点

  • Schema 与 Rev4 的一致性。
  • ExecutionGeneration / 决策轮次 / SealedBallot 的身份边界。
  • 投票提交唯一性、偏序约束、候选裁决与全局选择状态、候选级异议归属。
  • 五个实施切片之间是否存在循环依赖。
  • 数据库迁移、旧 API 兼容及未来 ContextManifest / AuthorityProof 接入是否合理。

审阅修订(第四轮,F32-16..18)

修订提交:5e7e2a8(第四轮审阅对象为 47a982a)。

  • F32-16(P1):ballot_set_digest 现在覆盖全部权威字段(case_id、round、charter_id、domain_profile_id、snapshot_id、context_manifest_id、authority_proof_id、execution_generation)并纳入 slots_digest;ballot_set_id 由该完整摘要派生。此前只算 snapshot_id + slots,两个引用不同授权证明或不同代次的集合可能碰撞。
  • F32-17(P1):candidate_count 唯一定义为 INCLUDED(正式投票)候选数(即 k);新增 candidate_entries = len(candidates) 表示含 MERGED/WITHDRAWN/EXCLUDED 的历史条目总数。VOTE-01 的 k(k-1)/2 与 K_max 校验一律取 candidate_count。
  • F32-18(P2):SealedBallot 显式绑定 authority_proof_id,并要求在提交 / 聚合 / 裁决三个时点校验有效性;授权撤销后整轮作废而不是沿用旧票(新增 VOTE-12)。此前 VOTE-06 要求票据级绑定,但 schema 里没有该字段。
  • 文档一致性:§0.2 与 §9 的验收范围补齐为 VOTE-01..12、CAND-01..04、DEC-01..06、TRIAL-01..02、LEGACY-01..04;索引同步 VOTE-12 与 CAND-04 表述。

Freeze the domain contract for the multi-candidate decision protocol:
DecisionCharter -> CandidateSnapshot -> BallotSet -> DecisionRecord, their
states and invariants, and how they bind to ContextManifest, AuthorityProof
and ExecutionGeneration.

The document is a frozen draft pending independent design review, not an
implementation or an approval to change the Rev4 specification. It maps each
section back to Rev4 clauses, states that the extended invariant numbers
(CHARTER/CAND/VOTE/DEC) refine rather than replace the Rev4 acceptance
requirements, separates the three identities (execution generation, protocol
round, ballot signing identity), and fixes the five implementation slices and
their dependencies.
Addresses the first contract review round.

- F32-01: drop the `candidate_limit >= 2` constraint. Candidate count and K_max
  are validated separately; a single-candidate snapshot is legal and must still
  pass the selection-sufficiency gate (Rev4 §4.2).
- F32-02: remove the authoritative flat `ranking`. PairPreference is the sole
  source of formal preference; any display order is a derived, non-authoritative
  projection and cannot be used to collapse TIED/INCOMPARABLE into a strict
  preference.
- F32-03: split the selection result (`selection_state`: NONE / SELECTED /
  HUMAN_SELECTED / SELECTION_DEFERRED) from the early-selection policy
  (`early_selection_policy`: WAIT / REVERSIBLE_TRIAL / HUMAN_WAIVER). The
  unfounded FORBID policy is removed, and NONE vs SELECTION_DEFERRED is defined.
- F32-04: a legacy Resolution is no longer equated with a k=1 DecisionRecord or
  an automatic SELECTED. It is readable only through an explicit LegacyProjection
  marked UNVERIFIED_LEGACY.
- F32-05: the charter now fixes submission/objection/revision/freeze deadlines
  with strict ordering instead of a single stage deadline (Rev4 §9, §18.5).
- F32-06: new-protocol ballot and dissent decision values are limited to
  APPROVE/REJECT/ABSTAIN; CONDITIONAL_APPROVE is confined to the legacy
  projection (Rev4 §10.1).
- F32-07: slice 4 now depends on both the frozen CandidateSnapshot (slice 2) and
  the sealed BallotSet (slice 3); the dependency graph separates module-parallel
  development from mandatory serial integration.
- F32-08: `candidate_count` is no longer a DecisionCharter field. The charter
  freezes only the K_max limit (confirmed before candidates are solicited); the
  count is derived from the frozen CandidateSnapshot and validated as
  1 <= k <= K_max (new CAND-04).
- F32-09: absence no longer overrides a proven hard block. VOTE-05 and the
  verdict order now follow Rev4 §10.3: confirmed hard-constraint violation ->
  BLOCKED (no quorum needed) precedes DEFERRED and INCOMPLETE; absences are
  still recorded and a blocked round keeps them.
- F32-10: REVERSIBLE_TRIAL now requires a TrialAuthorization (scope, deadline,
  exit conditions, alternatives stay open, R1 only, three-persona confirmation).
  Missing any prerequisite cannot produce SELECTED (new TRIAL-01..02).
- F32-11: fixed the DecisionRecord commit point to match the existing FSM:
  RESOLVING forms a PENDING record only; the unique authoritative commit happens
  in the terminal transaction. An independent decision-commit point is called
  out as separate, un-frozen work.
- F32-12: split the immutable per-persona SealedBallot from the aggregate
  BallotSet snapshot, with separate idempotency key and aggregate digest
  (new VOTE-09).
- F32-13: SealedBallot explicitly binds user_preference_snapshot_id per
  Rev4 §6.2, or freezes a unique ContextManifest mapping and validates it
  (new VOTE-10).

Index, §0.2 numbering, the identity/binding tables and the revision log are
updated accordingly. The document remains a frozen draft pending independent
review.
- F32-14: split minority positions into candidate-level `CandidateDissent`
  (requires candidate_id and ballot_id) and `SelectionDissent` for opinions on
  the global selection, so a multi-candidate round can attribute each objection.
  Reports group candidate dissent by candidate and list selection dissent
  separately (new DEC-06). The legacy candidate-less `entity.Dissent` shape is
  confined to the LegacyProjection (new LEGACY-04).
- F32-15: a BallotSet is now formed once every participant slot reaches a
  terminal outcome (SEALED or ABSENT) instead of requiring three valid ballots,
  which previously deadlocked the round whenever one persona timed out. Absences
  yield an immutable incomplete BallotSet that can only produce INCOMPLETE,
  prior BLOCKED, or otherwise explicitly permitted results.
- Non-blocking: SealedBallot submission itself must enforce the
  execution_generation ownership check (new VOTE-11), not only aggregation; and
  TrialAuthorization.risk_level is tightened to enum{R1} so structure and
  semantics agree.

Index, numbering and the revision log are updated.
- F32-16: ballot_set_digest now covers every authoritative field (case_id,
  round, charter_id, domain_profile_id, snapshot_id, context_manifest_id,
  authority_proof_id, execution_generation) plus a slots_digest, and
  ballot_set_id is derived from it. Digesting only snapshot_id + slots let two
  assemblies with different authority proofs or generations collide.
- F32-17: candidate_count is defined once as the INCLUDED (voting) count, and a
  new candidate_entries carries len(candidates) including MERGED/WITHDRAWN/
  EXCLUDED. VOTE-01's k is candidate_count; the paired-preference count and the
  K_max check use it, not the historical entry total.
- F32-18: SealedBallot now binds authority_proof_id, with validity verified at
  submission, aggregation and adjudication (new VOTE-12). Previously VOTE-06
  required a ballot-level binding the schema did not carry, and a revocation
  between submission and aggregation was unrepresentable.
- Consistency: §0.2 and §9 now list the full invariant ranges (VOTE-01..12,
  CAND-01..04, TRIAL-01..02, LEGACY-01..04), and the index reflects the new
  VOTE-12 / CAND-04 wording.
@jamespud
jamespud marked this pull request as ready for review October 14, 2026 11:49

@jamespud jamespud left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contract review — 5e7e2a860f59a340b5ef7f82788741fcde27fe33

Reviewed the final F32-16/17/18 fixes against the frozen Rev4 design intent and prior review findings. No remaining blocking findings identified in the reviewed contract scope. This is a COMMENT review by the connected PR-author account, not an independent approval or a statement that the protocol is implemented.

  • F32-16: slots_digest hashes canonical participant slots separately; ballot_set_digest binds case_id, round, charter/domain/snapshot/context/authority references, execution generation and the slot digest, with ballot_set_id derived from the complete digest.
  • F32-17: candidate_count uniquely counts INCLUDED ballot candidates; candidate_entries counts all retained candidate records; VOTE-01 consistently sets k=candidate_count.
  • F32-18: SealedBallot binds authority_proof_id; VOTE-12 checks validity at independent submission, aggregation and decision time. Invariant indexes and slice responsibilities are updated.
  • Verified the six passing CI jobs on this exact head. This CI validates repository gates, not the semantics of a future implementation.

Two nonblocking editorial consistency follow-ups: in §6.1 change the authority binding target to sealed_ballot.authority_proof_id (rather than only ballot_set.authority_proof_id); in VOTE-12 say 'all ballots corresponding to SEALED participant slots' rather than 'three ballots' so ABSENT slots are represented correctly.

Recommendation: PR is suitable for Ready review / independent merge decision. Preserve its design-only scope, and implement RED→GREEN reference validation in the separately scoped slices; do not treat this as Rev4 implementation acceptance.

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.

1 participant