Create VulnerabilityCase at Report Receipt (RM.RECEIVED)
Context and Problem Statement
When a vendor actor receives a Offer(Report) activity (i.e., a reporter
submits a vulnerability report), the current implementation defers
VulnerabilityCase creation until the report passes validation — that
is, until the ValidateReport behavior tree transitions the receiver's
RM state to RM.VALID.
This was originally a natural mapping from the CVD process model: a "case" traditionally implies the vendor has committed to working the issue. However, in the Vultron prototype this deferral creates several problems:
- Awkward pre-case tracking: Before a case exists, the system needs separate mechanisms to track the receiver's RM state and the reporter's participation. These "proto-case" structures mimic a case without being one, adding complexity with no benefit.
- Late finder notification: The reporter does not learn that a case has been opened until after validation. Under MPCVD, this creates unnecessary gaps in coordination.
- Overcrowded
ValidateReportBT: The validate-report behavior tree currently performs both report validation and case/participant setup. These are distinct concerns. Mixing them makes the tree harder to reason about and test. - Blocking FINDER-PART-1: The need to track participants before a case exists drove the FINDER-PART-1 task, which required a complex retroactive re-linking mechanism. This complexity dissolves if the case is created earlier.
The question is: when should the VulnerabilityCase object be
created?
Decision Drivers
- Simplicity: minimize distinct tracking mechanisms
- Protocol fidelity: the CVD process begins at receipt, not at validation
- Separation of concerns: case setup vs. report validation are distinct workflows
- Finder visibility: reporters should know a case was opened as soon as possible
Considered Options
- Keep case creation at RM.VALID (status quo) — create the case only after the report is validated
- Create case at RM.VALID, but emit earlier notification — keep creation deferred but send provisional notification sooner
- Create case at AckReport (RM.RECEIVED, post-ack) — wait for the receiver to acknowledge before creating the case
- Create case at
Offer(Report)receipt (RM.RECEIVED) — create the case immediately inSubmitReportReceivedUseCase
Decision Outcome
Chosen option: Option 4 — Create case at Offer(Report) receipt
(RM.RECEIVED).
When SubmitReportReceivedUseCase processes an inbound Offer(Report),
it MUST invoke a new behavior tree (receive_report_case_tree) that
creates a VulnerabilityCase, two initial VultronParticipant records
(reporter at RM.ACCEPTED, receiver at RM.RECEIVED), a default embargo,
and queues a Create(Case) notification to the reporter.
The ValidateReport BT is slimmed to validation-only logic.
Consequences
- Good: No separate "pre-case" object or participant tracking mechanism is needed. The case object exists from the moment the report is received.
- Good:
ValidateReportBT focuses on what it is named for: evaluating report credibility and validity. Case/participant creation moves to its own BT. - Good: Reporter receives immediate
Create(Case)notification, improving MPCVD coordination latency. - Good:
InvalidateReportReceivedUseCase,CloseReportReceivedUseCase, andValidateReportReceivedUseCasecan all dereferencereport_id → case_idand delegate to corresponding case-level use cases. This makes report-centric flows consistent. - Good: FINDER-PART-1 (the complex retroactive re-linking task) is superseded and can be removed from the backlog.
- Neutral: The term "proto-case" is preserved but redefined. A proto-case is now a case object in the RM.RECEIVED or RM.INVALID stage (i.e., the case exists but has not yet been validated). The caterpillar/butterfly analogy still holds: caterpillar = case in RM.RECEIVED/INVALID stages; butterfly = case in RM.VALID/ACCEPTED/ DEFERRED stages.
- Neutral: Cases for reports that are later invalidated or closed without validation do exist as persisted objects in a terminal proto-case state (RM.INVALID or RM.CLOSED). This is acceptable and consistent with the protocol model.
- Bad:
SubmitReportReceivedUseCasebecomes more complex (requires BT invocation). This is offset byValidateReportBT becoming simpler. - Bad: The
InitializeDefaultEmbargoNodeand participant-creation nodes move from the validate-report BT to the new case-from-report BT. The BT tests for these nodes must be updated accordingly.
Validation
This decision is validated by:
test/core/use_cases/received/test_submit_report.py: verifies thatSubmitReportReceivedUseCasecreates a case, two participants, and queuesCreate(Case)to the outboxtest/core/behaviors/case/test_receive_report_case_tree.py: verifies the new BT creates case and participants with correct initial RM statestest/core/behaviors/report/test_validate_tree.py: verifies the slimmed validate-report BT does NOT create case or participants- All existing tests for
ValidateReportReceivedUseCasecontinue to pass (the report→case dereference is transparent to callers)
Pros and Cons of the Options
Option 1 — Keep case creation at RM.VALID (status quo)
- Good, because it preserves the traditional CVD meaning of "case" (an accepted commitment to work the issue)
- Bad, because it requires separate pre-case tracking for RM state and participants
- Bad, because
ValidateReportBT mixes two concerns - Bad, because finder notification is delayed until after validation
Option 2 — Emit earlier notification, keep deferred creation
- Good, because "case" retains its committed-work meaning
- Bad, because adds another activity type to the protocol with no corresponding state change
- Bad, because the pre-case tracking problem remains
Option 3 — Create case at AckReport
- Good, because case creation is still tied to an explicit vendor action
- Bad, because the
AckReportstep is optional and may not occur in all demo or protocol paths - Bad, because complicates the path for implementations that skip explicit acknowledgment
Option 4 — Create case at Offer(Report) receipt (chosen)
- Good, because aligns case object lifecycle with the start of CVD work
- Good, because eliminates pre-case tracking complexity
- Good, because separates validation from case setup
- Good, because sends immediate notification to reporter
- Neutral, because "proto-case" term requires redefinition (not removal)
- Bad, because cases for subsequently-invalidated reports persist in storage (acceptable; they are in a terminal state)
Post-Decision Refinement (issue #1133, 2026-07-08)
The Option 4 "always create case" behavior is now configurable via
ActorConfig.auto_create_case: bool (default: True).
When auto_create_case=False, SubmitReportReceivedUseCase stores the
inbound VulnerabilityReport and Offer(Report) activity as before, but
the create_receive_report_case_tree BT exits early without creating a
VulnerabilityCase. This enables the Option 3 path that was evaluated
and rejected in the original decision: the receiver can send a pre-case
Read(Offer(Report)) acknowledgment (via AckReportReceivedUseCase) before
explicitly deciding to accept or reject the report.
The default preserves the original Option 4 behavior for all existing actors
and scenarios. The auto_create_case=False path is intended for scenarios
that model deliberate pre-case evaluation workflows (see issue #1221 —
tentative rejection → acceptance — as the first demo to use this flag).
Spec requirement: specs/case-management.yaml CM-15-001.
More Information
- Supersedes: FINDER-PART-1 task in
plan/IMPLEMENTATION_PLAN.md - Refines:
notes/case-state-model.md(proto-case / caterpillar–butterfly metaphor) - Updates:
specs/case-management.yaml(new CM-12 requirements, CM-15-001) - Updates:
specs/duration.yaml(DUR-07-002 timing, new DUR-07-004) - Updates:
notes/protocol-event-cascades.md(cascade list) - Source idea: IDEA-260408-01 in
plan/IDEAS.md - Post-decision refinement: issue #1133