Publication-Intent Subtree Collapse: Bypass Leaves → Intent-Record-Driven Arms
Implemented by issue #1310 (task/1310-publication-intent-arms).
Context and Problem Statement
The simulator Publication BT encodes publication intent as a combination of
a PublicationIntentsSet flag check, a PrioritizePublicationIntents Evaluator,
and per-artifact bypass leaves (NoPublishExploit, NoPublishFix, NoPublishReport)
that allow the BT to short-circuit each artifact arm. In production, these bypass
leaves and the flag check are structural artifacts of the simulator representation
and do not represent real call-out points.
How should the publication-intent subtree be structured in production?
Decision Drivers
- Eliminate structural artifacts (bypass leaves, flag checks) that add BT complexity without adding real call-out point seams
- Preserve
PrioritizePublicationIntentsas the primary Evaluator — it is already the correct shape and should survive - Keep per-artifact arms independently executable (exploit, fix, report)
Considered Options
- Intent-record-driven arms — Evaluator output gates which arms execute; bypass leaves disappear; three named arms (exploit, fix, report) remain
- Unified loop over artifact list — Evaluator returns an ordered list; BT iterates it; no named arms
- Keep all simulator nodes (no collapse)
Decision Outcome
Chosen option: Option 1 (lean) — intent-record-driven named arms.
PrioritizePublicationIntents returns a PublicationIntentDecision record
{publish_exploit, publish_fix, publish_report, rationale}; the BT uses these
booleans to gate which of the three named arms execute. The
PublicationIntentsSet flag check and NoPublish* bypass leaves disappear.
The choice between Options 1 and 2 is finalized as Option 1 at implementation time (issue #1310). Option 1 preserves a readable BT structure with three named arms, which is easier to audit and debug than a generic loop over an artifact list; the added arm count is small (exactly three) and fixed by the CVD domain (exploit, fix, report), so the generality of Option 2 buys nothing here.
Each named arm is a Selector(Sequence(ShouldPublishX, PrepareX, Publish),
Inverter(ShouldPublishX)): the intent-record boolean gates the Prepare→Publish
Sequence, and the Inverter makes a "not intended" arm a graceful SUCCESS
no-op (rather than failing the whole PublicationBT). This mirrors the
routing-no-op idiom already used in vultron/core/behaviors/sync/announce_tree.py
and honours the positive-condition-naming rule (BTND-08-001): ShouldPublishX
is named positively, not NoPublishX.
Consequences
- Good, because
NoPublish*bypass leaves andPublicationIntentsSetflag check are eliminated — they were ProtocolInternal no-ops masquerading as structural nodes - Good, because three named per-artifact arms are easier to understand and debug than a generic loop
- Good, because the
ShouldPublishXgate nodes are named positively (BTND-08-001) and read the intent record directly, so the removedNoPublish*leaves leave no behavioural gap - Neutral, because the intent record must be designed as a typed Pydantic BaseModel
(
PublicationIntentDecision) to support the boolean-gate pattern
More Information
- Planning issue: #1200; implementation issue: #1310
- Simulator nodes:
PublicationIntentsSet,PrioritizePublicationIntents,NoPublishExploit,NoPublishFix,NoPublishReportand the Reprioritize* nodes (seenotes/bt-fuzzer-nodes-report-management.md§ "Publication" and "Production Collapse 2") - Output schema:
PublicationIntentDecision(publish_exploit, publish_fix, publish_report, rationale)(Pydantic BaseModel) invultron/core/behaviors/report/publication_tree.py - Fuzzer backend:
PrioritizePublicationIntents(Evaluator) and theShouldPublishExploit/ShouldPublishFix/ShouldPublishReportgate nodes invultron/demo/fuzzer/report_management/publication.py - Precedent: ADR-0027 (Production Collapse 1) uses the same Evaluator-writes-typed-record pattern
- The
Publishleaf expands into a draft-review-submit pipeline separately in ADR-0030 (Production Collapse 4); this ADR keepsPublishas a single Actuator per arm
Generated spec requirements: behavior-tree-integration.yaml BT-20-002