Repository navigation
docs(decision): freeze decision protocol v1 contracts - #32
Conversation
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
left a comment
There was a problem hiding this comment.
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_digesthashes canonical participant slots separately;ballot_set_digestbindscase_id, round, charter/domain/snapshot/context/authority references, execution generation and the slot digest, withballot_set_idderived from the complete digest. - F32-17:
candidate_countuniquely countsINCLUDEDballot candidates;candidate_entriescounts all retained candidate records; VOTE-01 consistently setsk=candidate_count. - F32-18:
SealedBallotbindsauthority_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.
内容
新增
docs/decision-protocol-contract.md,冻结多候选决策协议的领域契约:DecisionCharter → CandidateSnapshot → SealedBallot → BallotSet → DecisionRecord的字段、状态枚举、不变量,以及与ContextManifest/AuthorityProof/ExecutionGeneration的绑定。这是待独立审阅的冻结草案,不是实现,也不是对 Rev4 规范的修改批准。本 PR 不含任何业务代码或迁移。
Rev4 条款映射
§0.1 逐条回溯(本契约章节 → Rev4 条款 → 关系):
扩展不变量编号的定位
§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。身份与绑定边界
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)。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。
审阅修订记录
candidate_count归属冻结快照(CAND-04)、F32-09 先验硬阻断优先于缺席、F32-10REVERSIBLE_TRIAL的TrialAuthorization(TRIAL-01..02)、F32-11 明确方案 A、F32-12SealedBallot/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}。审阅重点
ExecutionGeneration/ 决策轮次 /SealedBallot的身份边界。审阅修订(第四轮,F32-16..18)
修订提交:
5e7e2a8(第四轮审阅对象为47a982a)。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,两个引用不同授权证明或不同代次的集合可能碰撞。candidate_count唯一定义为 INCLUDED(正式投票)候选数(即k);新增candidate_entries = len(candidates)表示含MERGED/WITHDRAWN/EXCLUDED的历史条目总数。VOTE-01 的k(k-1)/2与K_max校验一律取candidate_count。SealedBallot显式绑定authority_proof_id,并要求在提交 / 聚合 / 裁决三个时点校验有效性;授权撤销后整轮作废而不是沿用旧票(新增VOTE-12)。此前 VOTE-06 要求票据级绑定,但 schema 里没有该字段。VOTE-01..12、CAND-01..04、DEC-01..06、TRIAL-01..02、LEGACY-01..04;索引同步VOTE-12与CAND-04表述。