Skip to content

proof: reject cross-effort create-time relations and report legacy edges #251

Description

@toeknee-figma

Describe the bug

@flatbread/proof@1.0.1 validates that create-time relation targets exist, but
it does not apply the same Effort boundary used by later lifecycle mutations.
Three create forms commit cross-Effort edges:

  • derives_from on WriteDecision;
  • supersedes on WriteFinding;
  • invalidates on WriteDecision.

The equivalent later Supersede and Invalidate mutations reject the edge.
Cross-Effort ResolveIssue, SetRiskState.evidence, and cites also reject.

An effort-scoped proof relations read then drops the committed foreign
derives_from target and reports 0 records; complete. The snapshot still
contains the edge, and create-time supersedes and invalidates also write
reverse projections into the foreign target.

This lets one mutation commit data that the read contract hides and the later
mutation contract rejects.

Reproduction

Using exact @flatbread/proof@1.0.1 and flatbread@1.0.1:

  1. Create Efforts A and B.
  2. Create Finding A in Effort A and Finding B in Effort B.
  3. Run these writes:
{
  "type": "WriteDecision",
  "effort": "<effort-b>",
  "title": "Cross derives-from",
  "body": "Must stay inside Effort B.",
  "derives_from": ["<finding-a>"]
}
{
  "type": "WriteFinding",
  "effort": "<effort-b>",
  "title": "Cross supersedes",
  "body": "Must stay inside Effort B.",
  "kind": "measurement",
  "supersedes": ["<finding-a>"]
}
{
  "type": "WriteDecision",
  "effort": "<effort-b>",
  "title": "Cross invalidates",
  "body": "Must stay inside Effort B.",
  "invalidates": ["<finding-a>"]
}

All three exit 0 and advance the durable generation. A strict read of the first
edge then exits 0 with no record:

flatbread proof relations <effort-b> <decision-id> \
  --relations derives_from \
  --strict-min-generation <write-generation>

Observed envelope fields:

{
  "summary": "0 records; complete",
  "page": { "returned": 0, "has_more": false, "next_cursor": null }
}

buildProofSnapshot(root).getRecord(decisionId).frontmatter.derives_from
still contains Finding A.

Expected behavior

  • Every create-time derives_from, supersedes, and invalidates target must
    belong to the source record's Effort. The Effort record itself may count as
    belonging to that Effort if such links are supported.
  • A rejected write must create no record, write no reverse edge, and leave the
    durable generation unchanged.
  • Same-Effort create-time and later relation forms must keep working.
  • Legacy or hand-edited foreign edges must fail with an explicit structured
    integrity error. They must not become a successful empty relation page.
  • Regression tests must cover all three create fields, their later mutation
    forms, reverse projections, same-Effort links, and strict relation recall.

Published package identity

  • @flatbread/proof@1.0.1
    • integrity: sha512-khANh86EXyZ0bPPOkUzGU0VRAPOpv+5h4vGKjpuFwLdfI/Eihxk63+YHbIxtFp08gffahxgViz/SlyFPJ1LR/A==
    • SHA-1: ec969767685bec108c04d78a4dcf4e7e1ad2cf78
  • flatbread@1.0.1
    • integrity: sha512-WNqK93IlIRBKq6IeyAZjEqVMDcsKVBi0v3yihU+JVXSYHJMQGX7i6wt0L53RQZJ06BPxFJNG9k4yiyBGdkuIgA==

The executable Harnessflow Gate-0 fixture checks every path above without
pre-validating relations or creating collection directories.

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