Skip to content

port(phase 6): workflows bundle from block/buzz - #799

Merged
nocodeafrica merged 7 commits into
canary/upstream-portfrom
port/phase6-workflows
Sep 14, 2026
Merged

nocodeafrica merged 7 commits into
canary/upstream-portfrom
port/phase6-workflows

Conversation

@nocodeafrica

@nocodeafrica nocodeafrica commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Phase 6 workflows bundle from block/buzz

Six upstream commits in upstream's first-parent order (#6470 and #6712 split out, see below), hand-merged with Colony's files as the base, identifier-gated (only upstream's own removals) and trailer-verified with check-trailers.sh.

What is in it

  • #5780 authoritative run history: migration lands as 0075_workflow_run_error_codes with its schema/schema.sql mirror; the Db facade hunk lives in store/workflow.rs; the regression sits in runtime/migration.rs (looked up by version).
  • #6008 responsive library card actions: relay half not taken, Colony already reaches all three revision refusals through parse_expected_workflow_revision; update_workflow now requires the revision.
  • #6009 multi-channel listing semantics: per-channel release from removed.scope; topic_for_subscription gone.
  • #6168 exact batch limit test.
  • #6248 the workflow editor: AppShell wrapped by hand around Colony's community rail and sidebar providers (now composed in AppShellProviders for the size ratchet); the three new specs open Workflows through Colony's More group. Divergence kept on purpose: Colony's shipped Run history and Run-again stay inside the editor where upstream commented the entry out pending a capability gate; the two assertions pinning its absence were flipped.
  • #6178 reply in-thread from send_message: Colony's workflow_sink.rs is the base, carrying authored_text and reply_to; a lone NIP-10 root marker anchors to that thread in queue::parse_thread_tags so an ACP session is not forked away from the thread.

Split out

  • #6470 (clarify setup and activation) breaks workflows.spec.ts when more than one workflow exists: the activation confirmation, an AlertDialog inside #6248's modal editor, dismisses itself right after opening. Three diagnostic rounds (focus-outside prevention, deferred open) did not settle it; next lead is Radix DismissableLayer. #6712 (trigger filter discovery) is welded to #6470's files. Both live on port/phase6-workflows-6470 for a dedicated fix.

Also: ActionCenterWorkflowDetail no longer renders Approve and Deny buttons from approval.token (the relay stores a hash, so they could never work); it carries the same line as the approval card, which is #5780's own change.

Report: epics/42f611d5-ba62-464d-b797-5a3ebb0ba700/artifacts/upstream-port-2026-09/phase-6-workflows/bundle-report-2026-09-14/index.md.

Commits

  • 64c3ada71 Make workflow run history authoritative in Desktop (#5780)
  • 8379a23df feat(workflows): add responsive library card actions (#6008)
  • 66e4b35d4 fix(workflows): preserve multi-channel listing semantics (#6009)
  • 940655b91 test(desktop): cover exact workflow batch limit (#6168)
  • a5b095d42 feat(workflows): add workflow editor (#6248)
  • c84092c56 feat(workflows): reply in-thread from send_message action (#6178)
  • 823f7d1df chore(desktop): regenerate the native inventory for the workflow bundle

🤖 Generated with Claude Code

https://claude.ai/code/session_01FD8THgkKDssuVYgumfTHJM

wesbillman and others added 7 commits September 14, 2026 11:16
(cherry picked from commit 2693e0db1fc4980a551c2492031812dc4bad985f)
Signed-off-by: Basheer Phiri <phiribash@gmail.com>
(cherry picked from commit edc4a09aaa41c29e2495a28247c895febaf6587d)
Signed-off-by: Basheer Phiri <phiribash@gmail.com>
A subscription is now scoped to a set of channels rather than one optional
channel, so `topic_for_subscription` is gone in favour of releasing Global and
each channel topic from `removed.scope`.

Colony adaptations, all in files where Colony's text differed:

- `crates/buzz-db/src/event.rs` is `store/event.rs` here after the Phase 2
  split. The `EventQuery::channel_ids` doc takes upstream's wording, which now
  has to explain `channel_ids_include_global`; the `tag_contains` doc above it
  is Colony's and stays.
- `connection.rs`: upstream's diff and Colony's file disagree around the
  helper because Colony added `request_rejection_message` and
  `enforce_ws_admission` next to it. Applied by hand: the per-channel release
  loop replaces the single `release_topic` call, the helper and its now-unused
  `EventTopic` import are deleted, and both Colony functions are untouched.
- `req.rs`: `apply_access_scope_to_query` becomes upstream's
  `apply_channel_scope_to_query`, which also takes the filter so an explicit
  multi-channel `#h` request scopes to exactly those channels. The comment
  under it keeps Colony's persona example inside upstream's more general
  wording, since personas are what that pushdown was added for here.

Identifier gate against 0d6e6ba reports five removals across five files:
`topic_for_subscription` (four copies), `extract_channel_from_filter` and
`apply_access_scope_to_query`. All are upstream's own deletions in this
commit, and their replacements (`scope.channel_ids()`,
`apply_channel_scope_to_query`) are in the tree.

Checks: cargo check and clippy -D warnings clean on buzz-relay, buzz-db and
buzz-core; 133 buzz-db and 15 buzz-core filter tests pass; 18 desktop
src-tauri workflow tests pass; tsc --noEmit clean.

buzz-relay's lib suite reports 33 failures on this machine, none of them
caused by this commit: they are the NIP-98 replay check finding no local Redis,
which CI has. `mint_and_revoke_a_gateway_token` fails with "NIP-98: replay
check unavailable", and both it and
`owner_archive_rejects_stale_request_after_live_kind0_owner_flip` fail
identically in an untouched worktree at e01436b.

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>

(cherry picked from commit f7a01bda7b1bf95cdbc9dc21bb69970955b14ecc)
Signed-off-by: Basheer Phiri <phiribash@gmail.com>
## Summary

- retain explicit regression coverage for the exact 128-channel relay
request limit
- cover the 129-channel split into 128 + 1 filters

The workflow-listing implementation originally carried by this PR landed
through #6009. This branch is now rebased onto current `main`, so the
remaining diff is only the boundary test that #6009 did not include.

Fixes #6116

## Test plan

- `cargo test --manifest-path desktop/src-tauri/Cargo.toml
workflow_queries_respect_relay_explicit_channel_limit`
- pre-push hook: Desktop checks, Desktop tests, Desktop Tauri checks,
and path-scoped Rust tests

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
(cherry picked from commit f8692fa9b52ddcfeb4b95fb4862109983509f131)
Signed-off-by: Basheer Phiri <phiribash@gmail.com>
**Category:** new-feature
**User Impact:** Users can create, edit, duplicate, and deep-link to
workflows in a responsive visual editor without losing unsupported YAML
or unsaved work.
**Problem:** Workflow editing was split across disconnected surfaces and
lacked reliable URL state, lifecycle protection, and parity between Form
and YAML modes. **Solution:** This adds a route-addressable editor
foundation with stable pane identity, guarded dirty exits, lossless
Form/YAML transitions, responsive workflow and channel controls, and
matching reaction-filter execution support.

<details>
<summary>File changes</summary>

**crates/buzz-workflow/src/lib.rs**
Apply reaction trigger filters during workflow execution and cover
target-message gating.

**crates/buzz-workflow/src/schema.rs**
Extend the reaction trigger schema with the editor-owned filter field.

**desktop/src/app/navigation/useAppNavigation.ts**
Add navigation helpers for explicit workflow create, edit, and duplicate
editor modes.

**desktop/src/app/routes/WorkflowsRouteScreen.tsx**
Coordinate route state with the shared workflow library and editor
dialog.

**desktop/src/app/routes/lazyWorkflowsRouteScreen.ts**
Share one lazy route component across workflow route entry points to
avoid loading flashes.

**desktop/src/app/routes/workflows.$workflowId.tsx**
Parse workflow editor modes and pane deep links for workflow-specific
URLs.

**desktop/src/app/routes/workflows.tsx**
Parse library-level create state and render the shared workflow route
screen.

**desktop/src/app/AppWorkflowEditorOverlayProvider.tsx**
Host the shared workflow editor at the app-shell level so
channel-originated workflow dialogs stay above the active channel
instead of replacing it.

**desktop/src/shared/context/WorkflowEditorOverlayContext.tsx**
Expose route-independent open-existing and create-new workflow actions
to channel settings.

**desktop/src/features/workflows/ui/WorkflowEditorHost.tsx**
Share editor loading, unavailable, and dialog lifecycle wiring between
canonical workflow routes and the channel overlay.

**desktop/src/features/channels/ui/ChannelManagementSheet.tsx**
Add an experiment-gated, Canvas-style Workflows ingress below Canvas,
including channel-scoped loading, error, empty, and list states plus
open/create actions; disabled users issue no workflow query.

**desktop/src/features/channels/ui/ChannelWorkflowsSection.tsx**
Render the channel workflow list and New workflow action without pushing
the existing settings sheet past its file-size ceiling.

**desktop/src/features/workflows/ui/ChannelCombobox.tsx**
Adopt the final channel presentation, portalled scrolling, and one-shot
create-flow opening behavior.

**desktop/src/features/workflows/ui/CreateWorkflowDialog.tsx**
Remove the superseded create-only dialog in favor of the unified
workflow editor.

**desktop/src/features/workflows/ui/WorkflowCard.tsx**
Open workflow cards in the detail and run-history modal while preserving
explicit edit and duplicate actions.

**desktop/src/features/workflows/ui/WorkflowDetailDialog.tsx**
Present workflow Trigger/Steps in the shared modal chrome, with
top-chrome ingress to a responsive right-side run-history inspector and
an explicit edit action.

**desktop/src/features/workflows/ui/WorkflowDialog.tsx**
Unify create, edit, and duplicate lifecycle handling with URL panes,
generated-name synchronization, dirty-exit guards, stale-write
preservation, and protected webhook-secret handoff.

**desktop/src/features/workflows/ui/WorkflowFormBuilder.tsx**
Build the responsive Form/YAML editor shell, stable step selection,
insertion and removal behavior, and lossless canonical-YAML
synchronization.

**desktop/src/features/workflows/ui/WorkflowStepCard.tsx**
Align workflow step controls and presentation with the final editor
interaction model.

**desktop/src/features/workflows/ui/WorkflowUnavailableDialog.tsx**
Show a non-disclosing loading or unavailable state for missing and
inaccessible workflow links, with retry and close actions.

**desktop/src/features/workflows/ui/WorkflowWebhookSecretDialog.tsx**
Obscure one-time webhook secrets by default and require explicit
confirmation before any close or navigation discards them.

**desktop/src/features/workflows/ui/WorkflowsScreen.tsx**
Connect library state and workflow actions to the route-addressable
editor.

**desktop/src/features/workflows/ui/WorkflowsView.tsx**
Restore the responsive workflow library, create tile, cards, loading
states, and shared action menu.

**desktop/src/features/workflows/ui/workflowEditorPane.test.mjs**
Cover pane parsing, serialization, and stable step-ID reconciliation.

**desktop/src/features/workflows/ui/workflowEditorPane.ts**
Define explicit trigger and stable step pane URL state.

**desktop/src/features/workflows/ui/workflowYamlDocument.ts**
Read and update header fields independently of full form validation so
incomplete steps cannot clear or disable the workflow title.

**desktop/src/features/workflows/ui/workflowYamlDocument.test.mjs**
Cover document-level workflow header reads and writes for incomplete
definitions.

**desktop/tests/e2e/workflow-title-stability.spec.ts**
Verify generated, renamed, saved, and duplicated titles remain stable
while moving between trigger and step panes.

**desktop/src/features/workflows/ui/workflowFormTypes.test.mjs**
Cover lossless Form/YAML round trips and actionable fallback for
unsupported fields.

**desktop/src/features/workflows/ui/workflowFormTypes.ts**
Own canonical workflow YAML conversion while preserving supported
trigger and step fields.

**desktop/src/shared/ui/PortalledScrollArea.tsx**
Provide bounded scrolling for popovers rendered outside their dialog
container.

**desktop/src/shared/ui/popover.tsx**
Allow workflow popovers to use the shared portalled scroll container.

**desktop/tests/e2e/channels.spec.ts**
Cover disabled and enabled Workflows experiment states, including
suppressed queries while disabled, placement beneath Canvas, channel
workflow listing and opening, channel-preselected workflow creation, and
direct return to the channel Workflows panel after close, discard, or
cancel.

**desktop/tests/e2e/workflows.spec.ts**
Exercise library actions, deep links, create/edit/duplicate lifecycle,
dirty exits, responsive editor behavior, YAML safety, stale updates, and
one-shot channel selection.

</details>

1. Open **Workflows** and confirm the responsive card library, create
tile, card action menu, and card-to-detail/run-history modal navigation.
2. Open `?view=create`; confirm the channel chooser opens once, the
trigger inspector stays hidden until a channel is selected, and closing
the chooser does not make it reopen after unrelated edits.
3. Create a workflow, switch between Form and YAML, add and remove
steps, refresh a pane deep link, and confirm the selected trigger or
stable step remains addressable.
4. Edit or duplicate a workflow, make an unsaved change, and confirm
close, Escape, browser navigation, and route target changes require
discard confirmation while pane-only navigation does not.
5. Enter unsupported YAML and confirm Form mode gives an actionable
fallback without rewriting the definition; verify reaction triggers
preserve and execute their filter.

6. Open a channel’s settings, select **Workflows** below **Canvas**, and
open or create a workflow; confirm the shared modal stays over the
channel, the channel URL does not change, New workflow preselects that
channel, and closing or discarding returns directly to the channel’s
**Workflows** panel.
7. In create, edit, and duplicate modes, move between the trigger and
incomplete step panes and confirm the generated or edited title remains
visible and editable.

Fresh captures from product head
`c5c3abc91a71fe511d43e6cc9168b1626d0c217c`; the later review-guidance
fix does not alter these pictured states.

![Workflow library with action
menu](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-library-actions-c5c3abc.png)

![Wide workflow editor with step
details](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-wide-c5c3abc.png)

![Narrow workflow editor with inspector
overlay](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-narrow-c5c3abc.png)

![Workflow editor portalled over the active
channel](https://d24qwcpro867f5.cloudfront.net/repos/buzz/prs/6248/workflow-editor-channel-overlay-c5c3abc.png)

- Corrected Diff Posted condition guidance to use the executor-supported
`str_contains(trigger_text, "deploy")` syntax and added a visible
Playwright regression assertion.
- Scoped direct workflow-detail navigation coverage to the stable `Edit
workflow` dialog name, asserted the workflow title separately, and
retained the trigger-node assertion.
- Routed dirty channel-overlay Duplicate/Edit transitions through the
existing discard confirmation, preserving the original YAML draft when
the user keeps editing.
- Made workflow deletion await relay success, remain non-dismissible
while pending, and retain the confirmation/editor/draft with an
actionable inline error on rejection.
- Gated the channel-settings Workflows ingress and channel workflow
query behind the `workflows` experiment, with defensive rendering if the
flag changes while that view is active.
- Matched the Reaction Added trigger to the prototype reaction picker,
preserving native/custom/legacy values in canonical YAML and providing
an explicit clear action.
- Kept a channel’s Workflows panel mounted beneath channel-origin
editors so clean close, dirty discard, and create cancel return directly
to that panel without changing the channel URL.

Verified at exact pushed head
`76ebba7b7ace1e13445744200da70ca9da231b7e`:

- Push hooks passed: destination-org policy, branch-skew, differential
file-size, Desktop checks, TypeScript typecheck, and **5,115/5,115**
Desktop unit tests
- Focused channel lifecycle E2E passed: dirty edit discard returns
directly to the channel Workflows panel; create cancel does the same
while preserving the channel URL and preselected channel
- E2E production build, standalone TypeScript typecheck, and Biome
checks on both touched files passed
- Reaction-picker regression spec remains recorded at
`dc28ffa98ec34b4e0656757fb2dd93e60a84674d`: **5/5 passed** (picker
interaction, canonical YAML persistence/clear, legacy-value
preservation, save/reopen round trip, narrow viewport containment)
- Blox existing workflow E2E regression set at
`dc28ffa98ec34b4e0656757fb2dd93e60a84674d`: **36/36 passed**
- Earlier blocker and review regressions remain recorded at
`3760c3d657a525f5af98e8d0f98bdd03999d8e61`: **5,114/5,114** Desktop unit
tests and the dirty-overlay/deletion focused checks
- Working tree clean; local branch, remote branch, and PR head all match
the exact SHA above

None found. Closest prior work: #231.

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Codex <noreply@openai.com>

Colony adaptations:

- `AppShell` wraps the profile-panel subtree in
  `AppWorkflowEditorOverlayProvider`. Upstream's diff also re-indents the whole
  block, and Colony's shell has a CommunityRail and SidebarProvider upstream
  does not, so the wrapper was placed by hand and nothing else in that file
  moved.
- `commitNavigation` gains `state?: Record<string, unknown>`, matching
  upstream's own signature. The editor marks navigations it opened so closing
  it knows whether there is an origin to return to.
- `ChannelManagementSheet` is on the size ratchet and this commit pushes it to
  1009 lines. Its workflow wiring moves to `useChannelSheetWorkflows`, taking
  the file to 980. Behaviour is upstream's unchanged; the limit is untouched.
- Colony's sidebar keeps Workflows inside the More group, so the three new
  specs reach it through `openSidebarDestination` rather than clicking
  `open-workflows-view` directly. Without that they time out on a nav item that
  is not on screen yet.
- Playwright's smoke list keeps Colony's `workflow-run-recovery.spec.ts`
  alongside upstream's three new specs.

One deliberate divergence, and the reason:

Upstream comments out the Run history entry point inside the editor, pending a
NIP-11 capability gate, and two of its specs pin the button's absence. Colony
already ships run history and the Run-again affordance (the authoritative
reads landed with #5780), so leaving the popover with no trigger would delete a
working Colony feature rather than defer an unbuilt one. The trigger stays, and
the two upstream assertions now expect it. Colony's own recovery spec moves to
the new surface: opening a card opens the editor, and run history is behind
that button.

Identifier gate against 6557114 reports fourteen removals across eight
files. Every one is upstream's own deletion in this commit, confirmed against
its diff.

Checks: 156 buzz-workflow tests pass and clippy -D warnings is clean;
tsc --noEmit clean; biome zero errors over src and tests; the file-size ratchet
passes. E2E on PLAYWRIGHT_PORT=4193: 136 specs across workflows, channels,
workflow-run-recovery, workflow-local-controls, workflow-reaction-picker and
sidebar-more-nav, plus 20 across workflow-title-stability and navigation. The
editor route itself renders under E2E, not only in unit tests.

(cherry picked from commit 1934e83bf5a5d8cd00f0cf28b558547b8d0dffb0)
Signed-off-by: Basheer Phiri <phiribash@gmail.com>
The `send_message` workflow action could only post new top-level channel
messages. This adds a `reply_in_thread` option so a `message_posted`
workflow can reply in the triggering message's thread, plus a
`trigger_is_reply` filter variable so a workflow can fire only on
top-level messages.

Every NIP-10 thread-marker reader in the tree now routes through one
shared parser and one collapse rule in `buzz-core`, deleting four
hand-rolled copies that had drifted on id-validity and marker semantics.

- **Schema** (`crates/buzz-workflow/src/schema.rs`): new
`reply_in_thread: bool` (serde default `false`) on
`ActionDef::SendMessage`. `validate()` rejects `reply_in_thread: true`
on `schedule`/`webhook` triggers — they carry no message to reply to.
- **Executor** (`crates/buzz-workflow/src/executor.rs`): threads
`reply_to: Option<&str>` (the trigger `message_id`) through
`ActionSink::send_message` when `reply_in_thread` is set; errors clearly
if the trigger has no `message_id`. `resolve_step_templates` carries the
new field. Adds `trigger_is_reply` (boolean) to the eval context.
- **Relay sink** (`crates/buzz-relay/src/workflow_sink.rs`): when
`reply_to` is set, resolves parent/root/depth from the known trigger
event, persists real thread metadata instead of the hardcoded top-level
`depth: 0`, and pushes the live kind:39005 thread-summary overlay after
insert so subscribed desktops update the root's reply badge without
refetching — matching the human ingest path. Emits the same NIP-10
`e`-tag shape as `buzz_sdk::builders::thread_tags`: a single `["e", id,
"", "reply"]` tag for a direct reply (parent == root), and the `root` +
`reply` pair only when nested — so every writer produces one wire shape
per reply kind.
- **Ingest resolver** (`crates/buzz-relay/src/handlers/ingest.rs`): new
`resolve_relay_reply_thread_meta` + `ReplyAncestry`. Unlike the
client-facing `resolve_nip10_thread_meta` (which validates
client-supplied tags), this computes root/depth from the known parent
and enforces the same same-channel and depth-limit invariants. When the
parent has no `thread_metadata` row, both resolvers share
`derive_ancestry_from_parent_tags`, which applies
`ThreadMarkers::resolve()`: a marked nested parent remains depth 2,
while a root-only, malformed, or unmarked parent is top-level and starts
its reply thread at itself. Both the client resolver and the
parent-ancestor fallback now read markers via the shared parser instead
of hand-scanning `e`-tags.
- **Shared NIP-10 parser** (`crates/buzz-core/src/nip10.rs`):
`parse_thread_markers` reads an event's `root`/`reply` markers, honoring
a marker only when its event id is exactly 64 ASCII-hex characters.
`ThreadMarkers::resolve()` is the single definition of the (root, reply)
→ (root_id, parent_id) collapse: `root`+`reply` as-is, `reply`-only →
`(reply, reply)`, a lone `root` or neither → top-level. A slice-based
`parse_thread_markers_from_parts` entry point serves consumers holding
raw JSON tag arrays. Relay ingest, the workflow `trigger_is_reply`
predicate, ACP anchoring, and the CLI reply resolver all call these, so
they cannot drift on marker, id-validity, or collapse semantics.
- **ACP** (`crates/buzz-acp/src/queue.rs`): `parse_thread_tags`
delegates marker parsing and collapse to `buzz_core::nip10`, keeping
only its local `p`-tag mention collection. This fixes a parity gap with
ingest: a malformed non-64-hex marker id is no longer counted as a
thread link, and a lone `root` marker is now top-level rather than being
treated as root == parent.
- **CLI** (`crates/buzz-cli/src/commands/messages.rs`):
`find_root_from_tags` routes its JSON tags through the shared slice
parser and collapse rule. CLI replies to root-only, malformed, or
unmarked parents now correctly start at that immediate parent;
reply-only and root+reply parent ancestry remain intact.
- **Trigger context** (`crates/buzz-workflow/src/lib.rs`):
`build_trigger_context` derives `is_reply` solely from a valid NIP-10
`reply` marker (no DB hit). A lone `root` marker is top-level to ingest,
so it does not count; neither does a `reply` marker whose event id is
malformed, nor a bare/unmarked `e`-tag (mentions, quotes).
- **Desktop** (`workflowFormTypes.ts`, `WorkflowStepCard.tsx`):
`replyInThread` form field with YAML round-trip, and a "Reply to
triggering message in thread" checkbox shown only for message-based
triggers. Switching to `schedule` or `webhook` clears the option on
every step before serialization, so a value hidden behind an action
change cannot resurrect when the action is switched back. The form
parser also requires `reply_in_thread` to be a boolean and refuses
`reply_in_thread: true` under an ineligible trigger, falling back to
YAML mode rather than silently normalizing a backend-invalid definition.

```yaml
trigger:
  on: message_posted
  filter: trigger_is_reply == false
steps:
  - id: auto_reply
    action: send_message
    text: "pre-written reply text"
    reply_in_thread: true
```

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>

Colony adaptations:

- `workflow_sink.rs` here already carries Phase 3's owner-contact hierarchy and
  the workflow-mention provenance from #6953, so it is the base. Upstream's
  thread-ancestry block is inserted into it, and upstream's shorter
  "Resolve `@Name` mentions" comment is dropped in favour of Colony's fuller
  one that documents Option C routing.
- `send_message` now carries BOTH Colony's `authored_text` and upstream's
  `reply_to`. Colony's five existing sink tests pass `None` for the new
  parameter; upstream's five new ones pass their own literal as
  `authored_text`.
- Upstream's new PG-gated tests were placed in the `write_path_guard` module,
  which has neither `test_state` nor `RelayActionSink` in scope. They move to
  `integration_tests`, which owns both.
- `ingest.rs` keeps Colony's event-write fence: the shared
  `derive_ancestry_from_parent_tags` helper and the new
  `resolve_relay_reply_thread_meta` read through
  `get_event_by_id_for_event_write`, not `get_event_by_id`, so the workflow
  path sees the same snapshot the ingest path does.

One deliberate divergence, and the reason:

`ThreadMarkers::resolve()` reads a lone `root` marker with no `reply` as
top-level. That is right for relay ingest and for the CLI, and both use it
unchanged. On the ACP side it is not: a client that writes into an existing
thread with only a `root` marker would get a NEW session rather than the
thread's own, which is the behaviour
`scope::tests::direct_reply_to_root_scopes_to_that_root` exists to prevent.
`queue::parse_thread_tags` therefore anchors that case to the named root, and
upstream's new `test_parse_thread_tags_root_only_is_top_level` becomes
`..._anchors_to_that_root` with the reason written out. Threads are the unit of
work here, so an ACP session must not fork away from one.

Identifier gate against 41938a8 reports three removals, all upstream's own:
`valid_event_id` folded into `buzz_core::nip10`, and two renamed tests.

Checks: 1135 buzz-acp, 169 buzz-workflow, 759 buzz-cli, 854 buzz-core and 22
workflow_sink tests pass; clippy -D warnings clean across all five crates;
tsc --noEmit clean and 61 desktop workflow specs pass. The 33 buzz-relay lib
failures are the same local-Redis NIP-98 replay check as before.

(cherry picked from commit c6e3fe7dfa751096d8c4083aaf15d6f6af296572)
Signed-off-by: Basheer Phiri <phiribash@gmail.com>
#5780's relay reader and #6248's routes and overlay providers all change what
the inventory records, and CI's check fails on a stale file.

Signed-off-by: Basheer Phiri <phiribash@gmail.com>
@nocodeafrica
nocodeafrica merged commit 3c4fa72 into canary/upstream-port Sep 14, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants