feat(acp): isolated workflow-delivery verifier (node E) - #6824
Draft
loganj wants to merge 17 commits into
Draft
Conversation
Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: loganj <loganj@squareup.com>
Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Retain exact-revision manual triggering and its transaction boundary while deferring automatic trigger and approval lifecycle propagation. Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Checkpoint run-level revision persistence before wiring every execution and resume path. Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: loganj <loganj@squareup.com>
Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
The SEC-006 event-path tests seeded rows through the legacy create_workflow helper, which leaves definition_event_id NULL. Run creation now fails closed on NULL-revision rows, so the positive arms (owner-authorized workflows must fire) broke. Seed through upsert_workflow — the production insert path — so fixtures carry a bound signed revision like every real workflow row. Co-authored-by: Wakko <0999168a3b1a4dabdf398cf43ba2893bb29b74dc06d0b31c2d3b51dbebea1612@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
WorkflowRunRecord grew a definition_event_id field for revision-bound execution; the five pure field-shape unit tests in buzz-db still built the struct without it, breaking every test target in the crate (cargo check --workspace passes because it skips test cfg). Add the field so --all-targets compiles again. Co-authored-by: Wakko <0999168a3b1a4dabdf398cf43ba2893bb29b74dc06d0b31c2d3b51dbebea1612@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Historical runs execute the exact signed revision persisted at run creation; NIP-33 replacement soft-deletes the superseded kind-30620 event, so load_run_definition must read through soft deletion. Pin that invariant: the test fails against get_event_by_id and passes against get_event_by_id_including_deleted (mutation-verified on the validation workstation). Co-authored-by: Wakko <0999168a3b1a4dabdf398cf43ba2893bb29b74dc06d0b31c2d3b51dbebea1612@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
…endpoint
The current_workflow_revision helper in desktop trigger_workflow was
referenced only from #[cfg(test)] workflows_tests.rs after the exact
signed-revision binding moved server-side behind the authenticated
/workflows/{id}/revision endpoint, leaving a dead-code lint risk in
non-test desktop builds. Remove the helper and its unit test.
Co-authored-by: Wakko <0999168a3b1a4dabdf398cf43ba2893bb29b74dc06d0b31c2d3b51dbebea1612@buzz.block.builderlab.xyz>
Signed-off-by: Logan Johnson <loganj@squareup.com>
…trigger-foundation * origin/main: Extract community persistence (#6668) Fix mobile Huddle agent voice turn states (#6611) Add inline profile camera capture (#6680) Hide Huddles in mobile agent DMs (#6676) fix(desktop): polish inline chip states (#6718) Centralize replaceable event persistence (#6660) feat(workflows): discover trigger filter values (#6712) feat(desktop): simplify the message action rail (#6529) Signed-off-by: Logan Johnson <loganj@squareup.com> # Conflicts: # crates/buzz-relay/src/handlers/command_executor.rs
Keep revision revalidation on the command transaction and carry the immutable authorized workflow owner across the transaction boundary. Add one-connection and concurrent PostgreSQL regressions. Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
…trigger-foundation * origin/main: Add database pressure observability (#6700) revert fixed mention highlight (#6716) highlight search terms in results and messages (#6702) fix(desktop): make lightbox zoom controls interactive (#6710) Support community deletion in versioned media buckets (#6738) Fix TipTap editor mount race (#6779) feat(buzz-agent): gate LLM tool calls on session/request_permission (#5712) Add staging dev relay image workflow (#6709) Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz> Signed-off-by: Logan Johnson <loganj@squareup.com>
loganj
force-pushed
the
wakko/workflow-acp-verifier
branch
from
August 25, 2026 20:54
27ff389 to
d4f5cda
Compare
Extract the pure workflow-delivery verification behavior preserved in PR #2737 into a dedicated, isolated module (node E of the workflow replacement tree) and centralize exact definition/message/owner/ channel/step/cause verification behind a typed result, built on the canonical delivery protocol vocabulary (node B, buzz_core::workflow_delivery). - crates/buzz-acp/src/verifier.rs: pure module, no I/O and no production caller. Callers supply already-fetched signed events. - Wake authentication adopts the canonical identifier-only WorkflowDeliveryWake (strict kind-24620 parse, relay authorship, signature, exact target). Wakes are hints: they name a delivery, never carry binding authority; every binding field is verified against signed authority instead of wake tags. - Target admission uses canonical message_v1_targets: only the four-field marker p-tag admits a durable delivery recipient; ordinary mentions never do, and malformed marker tags fail closed. - verify_workflow_delivery types failures: VerifyError::Mismatch (permanent - binding disagreement or forgery) vs VerifyError::Unavailable (transient - authority not supplied). Neither becomes dispatch. - The recorded canonical WorkflowDeliveryCause is re-verified against independent caller-fetched authority (CauseAuthority) for every cause class, and durable authority must carry the source row's full binding identity, never just the scalar the delivery re-presents: an Event cause requires the exact signed event (id, signature, channel binding); a Schedule cause requires the durable scheduled_workflow_fires claim binding (community, workflow, slot, linked run - two workflows can fire the same second); a Webhook cause requires the durable invocation record binding (community, workflow, invocation id, linked run; the durable record itself is owned by a later node and modeled here as the required authority input). The delivery snapshot carries the server-resolved CommunityId for these comparisons. Absent authority is Unavailable; disagreeing, unbound, or wrong-class authority is Mismatch. The claimed delivery row is never its own proof. - Mutation tests flip every binding field (workflow, run, step, channel, target, definition event, message event, cause, rendered content) one at a time and assert permanent mismatch. Durable-cause coverage includes the exact matching row control plus one-field row mutations (different community, same-slot different workflow, different slot/invocation, different linked run, unattached run) for both Schedule and Webhook; dropped authority for every cause class asserts transient unavailability; wrong-class authority in all directions asserts mismatch. Dormant by contract: no polling, claims, dispatch, producer, or production reachability. PRs #2737 and #6697 are unchanged. Signed-off-by: Logan Johnson <loganj@squareup.com> Co-authored-by: Wakko <0999168a3b1a4dabdf398cf43ba2893bb29b74dc06d0b31c2d3b51dbebea1612@buzz.block.builderlab.xyz>
loganj
force-pushed
the
wakko/workflow-acp-verifier
branch
from
August 25, 2026 21:23
d4f5cda to
c8b89d3
Compare
loganj
force-pushed
the
darryl/delivery-protocol-vocabulary
branch
from
August 26, 2026 02:49
46aae72 to
092f9fb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖
Summary
darryl/delivery-protocol-vocabulary).crates/buzz-acp/src/verifier.rs: a pure, zero-I/O module that centralizes exact definition/message/owner/channel/step/cause verification for durable workflow deliveries, built on the canonicalbuzz_core::workflow_deliveryvocabulary.Details
Why. The preserved #2737 verifier flattened every failure to
None, so a transient fetch failure was indistinguishable from a forged binding, and the recorded run cause was never re-verified. This node fixes both while preserving the fail-closed behavior of every existing check.Typed outcomes.
verify_workflow_deliveryreturnsVerifyError::Mismatch(MismatchKind)(permanent — binding disagreement or forgery; never retried) vsVerifyError::Unavailable(UnavailableKind)(transient — required signed authority not supplied; retriable). Neither variant may become dispatch. The verifier performs no I/O: callers fetch the signed definition/message/cause events and pass them in (FetchedAuthority), so absence is typed asUnavailable, never conflated with mismatch.Canonical vocabulary (from B).
WorkflowDeliveryWakestrict parse (kind 24620, relay-authored, signature-verified, exact target). Wakes are hints: they name a delivery and nothing else; every binding field is verified against signed authority, not wake tags.message_v1_targets: only the canonical four-fieldmessage-v1marker p-tag admits a durable delivery recipient. Ordinary mentions never do; malformed marker tags fail closed.WorkflowDeliveryCauseis re-verified. AnEventcause requires the exact signed event (id + signature + channel binding →Mismatchon disagreement,Unavailablewhen not supplied).Schedule/Webhookidentities are opaque typed server-side authority and cannot be conflated with an absent signed cause.Preserved behavior. Definition identity (kind 30620,
dworkflow UUID,hchannel), message identity (kind 9, channel, relay authorship, workflow-definition/run/step tags), step lookup +send_messageaction + channel-field consistency, trigger-context revision binding, and exact template re-render equality all match the preserved #2737 source; so doworkflow_delivery_principal/is_workflow_delivery_candidatefail-closed admission.Tests. 10 pure tests including mutation vectors: every binding field (workflow, run, step, channel, target, definition event, message event, cause, rendered content) is flipped one at a time and must produce a permanent
Mismatch; every dropped input must produce a transientUnavailable; a control fixture verifies. Cause verification requires independent authority for every cause class — the exact signed event forEvent, the durablescheduled_workflow_firesclaim binding (community, workflow, slot, linked run) forSchedule, and the durable invocation record binding forWebhook(the record itself is owned by a later node; modeled as the required typed authority input). The claimed delivery row is never its own proof: absent authority isUnavailable(Cause); disagreeing, unbound, or wrong-class authority isMismatch(Cause), covered by one-field row mutations (different community, same-slot different workflow, different slot/invocation, different linked run, unattached run) for both durable classes. Validated withcargo fmt --check,cargo clippy -p buzz-acp --all-targets -- -D warnings, andcargo test -p buzz-acp(811 unit + 9 integration passing) at this exact head.Buzz channel: buzz-workflow-owner-trigger-a-foundation (
11ae68c1-38e7-4591-958e-e4da94d758f0)