# 首切片操作边界：这些是设计验收材料，尚未执行产品运行时测试。
# detail-of 不支持；merge 仅接收同层 active 叶子，且来源不能有历史子树。
# 每步从真实提交的状态继续；失败不写日志、不占用 batch_id、不改变 revision。
# 信息契约未命名错误码的约束（缺 reason、同批重复改写、未知批注、层预算）只核对目标、字段与数值。

budget: 64
actor: assistant

steps:
  - name: 建立两个无子层的方案，以及一个带子项的方案
    now: "2026-10-09T10:00:00+08:00"
    commit:
      batch_id: boundaries-initial
      declarations:
        - id: leaf-a
          title: 方案甲
          summary: 甲报价 200。
          weight: normal
          kind: fyi
          sources: [{channel: email, ref: "quote:a", quote: 甲报价 200。}]
        - id: leaf-b
          title: 方案乙
          summary: 乙报价 220。
          weight: normal
          kind: fyi
          sources: [{channel: email, ref: "quote:b", quote: 乙报价 220。}]
        - id: parent
          title: 方案丙
          summary: 方案丙待确认。
          weight: high
          kind: in-progress
          children:
            - {id: child, title: 方案丙材料, summary: 收到一份说明。, weight: low, kind: fyi}
      acknowledges: []
    expect:
      accepted: true
      batch_status: committed
      revision: r1
      events_appended: 1
      used: 24
      shares: {parent: 12, leaf-a: 6, leaf-b: 6}
      rank: [parent, leaf-a, leaf-b]
      children:
        parent: {used: 3, shares: {child: 3}}

  - name: 用户给方案甲留下一条批注
    actor: user
    now: "2026-10-09T10:01:00+08:00"
    annotate: {batch_id: boundaries-note, item: leaf-a, text: 比较时保留两份原始报价。}
    expect:
      accepted: true
      batch_status: committed
      annotation_id: ann-1
      annotation_status: saved
      revision: r1
      events_appended: 1

  - name: 合并之前先确认批注，建立应被保留的首次绑定
    now: "2026-10-09T10:02:00+08:00"
    commit: {batch_id: boundaries-ack, declarations: [], acknowledges: [ann-1]}
    expect:
      accepted: true
      batch_status: committed
      revision: r2
      events_appended: 1
      annotation_status: {ann-1: acknowledged}
      annotation_bound_to: {ann-1: r2}
      events_contain:
        - {event_seq: 3, type: acknowledge, batch_id: boundaries-ack, revision: r2}

  - name: 即使目标存在，detail-of 仍在首切片明确拒绝
    now: "2026-10-09T10:03:00+08:00"
    commit:
      batch_id: boundaries-detail-of
      declarations:
        - {id: extra-detail, relation: "detail-of:parent", title: 补充说明, summary: 新收到的说明。, weight: low, kind: fyi}
      acknowledges: []
    expect:
      accepted: false
      error: {code: unsupported_relation}
      revision: r2
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 两个 active 叶子也不能跨层合并
    now: "2026-10-09T10:04:00+08:00"
    commit:
      batch_id: boundaries-cross-layer
      declarations:
        - {id: cross-layer, relation: "merges:[leaf-a, child]", title: 跨层整理, summary: 将两个层的内容合并。, weight: high, kind: fyi}
      acknowledges: []
    expect:
      accepted: false
      error: {code: merge_layer_mismatch}
      revision: r2
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 同层来源含 active 子层时，不支持合并
    now: "2026-10-09T10:05:00+08:00"
    commit:
      batch_id: boundaries-active-subtree
      declarations:
        - {id: active-subtree, relation: "merges:[parent, leaf-a]", title: 方案汇总, summary: 合并两份方案。, weight: high, kind: fyi}
      acknowledges: []
    expect:
      accepted: false
      error: {code: unsupported_merge_structure}
      revision: r2
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 显式撤下子项后，父项不再有 active 孩子
    now: "2026-10-09T10:06:00+08:00"
    commit:
      batch_id: boundaries-withdraw-child
      declarations:
        - {id: child, relation: withdraw, reason: 材料暂离当前层，原内容与归属留存。}
      acknowledges: []
    expect:
      accepted: true
      batch_status: committed
      revision: r3
      events_appended: 1
      used: 24
      withdrawn: [child]
      items:
        parent: {status: active, active_children: [], updated_at: "2026-10-09T10:06:00+08:00"}
        child: {status: withdrawn}

  - name: 即使 active 子层已空，来源的历史子树仍使合并不受支持
    now: "2026-10-09T10:07:00+08:00"
    commit:
      batch_id: boundaries-historical-subtree
      declarations:
        - {id: historical-subtree, relation: "merges:[parent, leaf-a]", title: 方案汇总, summary: 合并两份方案。, weight: high, kind: fyi}
      acknowledges: []
    expect:
      accepted: false
      error: {code: unsupported_merge_structure}
      revision: r3
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 合法叶子合并继承来源与批注，不重置确认状态和首次 revision
    now: "2026-10-09T10:08:00+08:00"
    commit:
      batch_id: boundaries-leaf-merge
      declarations:
        - id: comparison
          relation: "merges:[leaf-a, leaf-b]"
          title: 方案比较
          summary: 甲报价 200，乙报价 220。
          weight: high
          kind: fyi
      acknowledges: []
    expect:
      accepted: true
      batch_status: committed
      revision: r4
      events_appended: 1
      events_contain:
        - {event_seq: 5, type: commit, batch_id: boundaries-leaf-merge, revision: r4}
      changes_contain:
        - {op: merge, item: comparison, merged: [leaf-a, leaf-b]}
      used: 24
      shares: {comparison: 12, parent: 12}
      rank: [comparison, parent]
      pending_annotations: []
      annotation_status: {ann-1: acknowledged}
      annotation_bound_to: {ann-1: r2}
      items:
        comparison:
          status: active
          active_children: []
          annotations: [ann-1]
          sources:
            - {channel: email, ref: "quote:a", quote: 甲报价 200。}
            - {channel: email, ref: "quote:b", quote: 乙报价 220。}
        leaf-a: {status: merged, merged_into: comparison}
        leaf-b: {status: merged, merged_into: comparison}

  - name: 标题超过二十四个 Unicode 字符时整批拒绝
    now: "2026-10-09T10:09:00+08:00"
    commit:
      batch_id: boundaries-title-length
      declarations:
        - id: payment
          title: 方案报价与实施日期均已确认但付款节点仍待双方核对。
          summary: 已确认报价与实施日期，双方尚未核对付款节点。
          weight: trace
          kind: in-progress
      acknowledges: []
    expect:
      accepted: false
      error: {code: invalid_field, field: title}
      revision: r4
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 去掉句号后恰好二十四个字符，拒绝过的批次可修正后提交
    now: "2026-10-09T10:10:00+08:00"
    commit:
      batch_id: boundaries-title-length
      declarations:
        - id: payment
          title: 方案报价与实施日期均已确认但付款节点仍待双方核对
          summary: 已确认报价与实施日期，双方尚未核对付款节点。
          weight: trace
          kind: in-progress
      acknowledges: []
    expect:
      accepted: true
      batch_status: committed
      revision: r5
      events_appended: 1
      used: 25
      items:
        payment:
          title: 方案报价与实施日期均已确认但付款节点仍待双方核对
          created_at: "2026-10-09T10:10:00+08:00"
          updated_at: "2026-10-09T10:10:00+08:00"

  - name: 补充摘要时省略 title，保留已接受的二十四字标题
    now: "2026-10-09T10:11:00+08:00"
    commit:
      batch_id: boundaries-title-inherit
      declarations:
        - id: payment
          relation: supersedes:payment
          weight: trace
          kind: in-progress
          summary: 双方约定明天继续核对付款节点，报价与实施日期维持不变。
      acknowledges: []
    expect:
      accepted: true
      batch_status: committed
      revision: r6
      events_appended: 1
      items:
        payment:
          title: 方案报价与实施日期均已确认但付款节点仍待双方核对
          summary: 双方约定明天继续核对付款节点，报价与实施日期维持不变。
          created_at: "2026-10-09T10:10:00+08:00"
          updated_at: "2026-10-09T10:11:00+08:00"

  - name: 复核省略标题及摘要，不制造新的内容或更新时间
    now: "2026-10-09T10:12:00+08:00"
    commit:
      batch_id: boundaries-title-checked
      declarations:
        - {id: payment, relation: supersedes:payment, weight: trace, kind: in-progress}
      acknowledges: []
    expect:
      accepted: true
      batch_status: committed
      revision: r6
      events_appended: 1
      state_unchanged: true
      events_contain:
        - {type: checked, batch_id: boundaries-title-checked, revision: r6, changes: []}
      items:
        payment:
          title: 方案报价与实施日期均已确认但付款节点仍待双方核对
          updated_at: "2026-10-09T10:11:00+08:00"

  - name: 降档必须写明 reason，缺少时整批拒绝
    now: "2026-10-09T10:13:00+08:00"
    commit:
      batch_id: boundaries-downgrade-no-reason
      declarations:
        - {id: comparison, relation: supersedes:comparison, weight: normal, kind: fyi}
      acknowledges: []
    expect:
      accepted: false
      error: {field: reason, item: comparison}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 显式份额覆盖必须同时写明 reason
    now: "2026-10-09T10:14:00+08:00"
    commit:
      batch_id: boundaries-share-no-reason
      declarations:
        - {id: comparison, relation: supersedes:comparison, weight: high, kind: fyi, share: 10}
      acknowledges: []
    expect:
      accepted: false
      error: {field: reason, item: comparison}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 新建条目带显式份额时同样需要 reason
    now: "2026-10-09T10:14:30+08:00"
    commit:
      batch_id: boundaries-new-share-no-reason
      declarations:
        - {id: memo, title: 方案备忘, summary: 新收到的补充说明。, weight: low, kind: fyi, share: 2}
      acknowledges: []
    expect:
      accepted: false
      error: {field: reason, item: memo}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 撤下必须写明 reason
    now: "2026-10-09T10:15:00+08:00"
    commit:
      batch_id: boundaries-withdraw-no-reason
      declarations:
        - {id: payment, relation: withdraw}
      acknowledges: []
    expect:
      accepted: false
      error: {field: reason, item: payment}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 对已合并的旧 ID 写入返回后继，不当成可恢复的撤下
    now: "2026-10-09T10:16:00+08:00"
    commit:
      batch_id: boundaries-write-merged
      declarations:
        - {id: leaf-a, relation: supersedes:leaf-a, weight: normal, kind: fyi, summary: 甲报价更新为 190。}
      acknowledges: []
    expect:
      accepted: false
      error: {code: item_merged, item: leaf-a, merged_into: comparison}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 确认不存在的批注时整批拒绝，不默默忽略
    now: "2026-10-09T10:17:00+08:00"
    commit: {batch_id: boundaries-ack-unknown, declarations: [], acknowledges: [ann-9]}
    expect:
      accepted: false
      error: {annotation: ann-9}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 同一批两个声明改写同一条目时整批拒绝
    now: "2026-10-09T10:18:00+08:00"
    commit:
      batch_id: boundaries-duplicate-declaration
      declarations:
        - {id: payment, relation: supersedes:payment, weight: trace, kind: in-progress, summary: 甲版本说明。}
        - {id: payment, relation: supersedes:payment, weight: trace, kind: in-progress, summary: 乙版本说明。}
      acknowledges: []
    expect:
      accepted: false
      error: {item: payment}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: 子层单独计算预算，超额时同样整批拒绝
    now: "2026-10-09T10:19:00+08:00"
    commit:
      batch_id: boundaries-child-budget
      declarations:
        - id: parent
          relation: supersedes:parent
          weight: high
          kind: in-progress
          children:
            - {id: part-a, title: 方案丙甲段, summary: 待确认。, weight: critical, kind: needs-you}
            - {id: part-b, title: 方案丙乙段, summary: 待确认。, weight: critical, kind: needs-you}
            - {id: part-c, title: 方案丙丙段, summary: 待确认。, weight: high, kind: in-progress}
            - {id: part-d, title: 方案丙丁段, summary: 待确认。, weight: normal, kind: fyi}
      acknowledges: []
    expect:
      accepted: false
      error: {constraint: layer_budget, layer: parent, budget: 64, declared: 66, over: 2}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false

  - name: children 列表不能把已有条目改挂到另一层
    now: "2026-10-09T10:20:00+08:00"
    commit:
      batch_id: boundaries-move-into-children
      declarations:
        - id: parent
          relation: supersedes:parent
          weight: high
          kind: in-progress
          children:
            - {id: payment, relation: supersedes:payment, weight: trace, kind: in-progress}
      acknowledges: []
    expect:
      accepted: false
      error: {code: unsupported_move, item: payment}
      revision: r6
      events_appended: 0
      state_unchanged: true
      batch_id_recorded: false
