docs(triggers): TRG-1 gate records, event-transport matrices, and the checker's --design-root - #14955
docs(triggers): TRG-1 gate records, event-transport matrices, and the checker's --design-root#14955erichare wants to merge 12 commits into
Conversation
* feat: add FunASR transcription component * fix: address FunASR component review * fix(ci): include FunASR in full release inventory Signed-off-by: zhifu gao <18321252+LauraGPT@users.noreply.github.com> * test(bundles): register FunASR SSRF guard Signed-off-by: zhifu gao <18321252+LauraGPT@users.noreply.github.com> * chore: prepare lfx-bundles release for FunASR Signed-off-by: LauraGPT <18321252+LauraGPT@users.noreply.github.com> * [autofix.ci] apply automated fixes * fix(funasr): align release metadata and docs Signed-off-by: Eric Hare <ericrhare@gmail.com> --------- Signed-off-by: zhifu gao <18321252+LauraGPT@users.noreply.github.com> Signed-off-by: LauraGPT <18321252+LauraGPT@users.noreply.github.com> Signed-off-by: Eric Hare <ericrhare@gmail.com> Co-authored-by: zhifu gao <18321252+LauraGPT@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Hare <ericrhare@gmail.com>
Triggers are the separate initiative that the 1.13 actions plan promised in Scope Boundary 1 and that design/dedicated-integrations/triggers-deferred.md records as deferred. This scaffold is modeled on the INT-1 gate README: why the initiative is separate (listening cannot run in the API process; one supervised instance per bot), the four obligations 1.13 owes it and nothing more, the push-ingress and persistent-connection tracks, nine exit criteria with artifacts and machine checks, the two unmerged precedents (origin/mock-orchestra, origin/feat-native-triggers-v2) and the runtime seams on release-1.13.0 with file references, the sign-off roles, and the phase plan. A sibling directory keeps the INT-1 checker's sign-off coverage rules scoped to that gate. No code, tables, routes, or UI. 1.13 scope and estimate are unchanged.
… gate branch The TRG-1 gate records extend scripts/ci/check_capability_matrices.py with a --design-root argument so the same decision-record and sign-off validation runs against design/dedicated-integrations-triggers. That checker is introduced by #14906 (feat/int-1-discovery-gate) and does not exist on release-1.13.0 yet, and the triggers README links to ../dedicated-integrations records from the same PR. Merging #14906 here makes both resolvable; the extra files leave this diff as soon as #14906 merges to release-1.13.0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…decisions TRG-1 exit criteria 1, 3, 4 and 5. findings/2026-09-listeners.md is the stub the platform owner authors: it carries the dated evidence on both precedents and on why neither shape survives the current runtime, with the sidecar position and the recommendation left as marked author sections. It stays Status: draft and exit criterion 1 stays open. decisions/process-model.md selects both shapes: a separate `langflow listeners` process is primary, LANGFLOW_LISTENERS_MODE=subprocess is the single-replica and Desktop shape, the dispatcher stays in the API lifespan under a lease, and `lfx serve` hosts neither listeners nor a trigger ingress. Lease semantics are TTL 30 s, heartbeat 10 s, poll 5 s. decisions/self-managed-ingress.md states the no-relay rule first: Langflow operates no service that receives provider events on behalf of a self-managed instance. Every provider therefore ships at least one outbound-only mechanism, which answers the deferred record's third re-open trigger for three of three providers and settles "Calendar and Drive without ingress" as poll, not relay. decisions/delivery-semantics.md fixes at-least-once collapsed once by a UNIQUE (trigger_id, dedupe_key) index, a 7-day replay window with a 30-day purge, retries to max_attempts then dead-letter, no cross-trigger ordering, and per-trigger concurrency as the backpressure knob. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ider matrices TRG-1 exit criterion 2. One matrix per wave-1 provider, each mechanism recording its track, ingress requirement, inbound authentication, subscription TTL and renewal, payload shape, delivery guarantee, replay availability, rate limits, dedupe key, session key, and the deployment contexts it supports, with every claim pointing at a dated provider-docs source. Slack: Events API (Track A, hosted and self-managed) and Socket Mode (Track B, self-managed and Desktop; not hosted, because a Socket Mode app cannot be distributed). RTM is recorded as excluded so nobody re-opens it. Microsoft: Graph change notifications (Track A) with the validationToken handshake, clientState, lifecycle events and a derived dedupe key, falling back to Graph delta queries (Track B). Rich resource-data notifications are deferred on certificate lifecycle; Teams message subscriptions are excluded because they need protected APIs, application permissions and a Teams billing model, which answers the gate's open "Teams messages" question. Google: Calendar and Drive push channels with a Track B sync-token and page-token poll each, plus Gmail users.watch over Cloud Pub/Sub in both push and pull form, available only on a customer-owned registration because gmail.readonly is a restricted scope the hosted app avoids. Every push mechanism that claims the conditional self-managed context names an outbound-only fallback that covers the same context; the checker enforces it in the following commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d estimate
TRG-1 exit criteria 6, 8 and 9, plus the README's own criterion-7 row.
trigger-contract.md is the record TRG-2 through TRG-7 build against: five tables
in one migration (trigger, trigger_event with UNIQUE (trigger_id, dedupe_key),
trigger_lease, trigger_listener_lease, trigger_subscription); binding to a flow,
a pinned flow version, or a deployment target that is stored but returns a typed
binding-unsupported error; per-event session trigger:{trigger_id}:{event_id} with
a provider-correlated option whose keys come from the matrices; the trigger_push
and trigger_listener families executing as flow_owner with actor
trigger_dispatcher; provider_signed as the ingress access mode; authz on the flow
resource; and the boundary with the 1.13 connection contract.
frontend-surfaces.md lists every surface with its owning ticket and adds the
trigger display-name rule "Product: On Event", the extension of the 1.13
"Product: Verb Object" palette rule. It records the server-driven allowed_actions
contract, config-driven polling with no SSE, and the interim connection field
that INT-8 later replaces.
estimate.md re-issues 34 engineer-weeks as 39.5 across TRG-1 to TRG-8 and records
the release owner's 2026-09-04 decision that triggers are 1.13 scope, amending
the "1.14 candidate" framing here and the triggers exclusion in the 1.13 estimate
rather than leaving them to contradict this gate.
The README now carries the real statuses, both open criteria (the findings
document and 1.13 conformance against unmerged pull requests), the gap the
conformance walk already found (the connection_resolution matrix dimension that
INT-4 and INT-5 were assigned and neither delivered), the full sign-off map, and
the checker invocation.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The README promised a --design-root argument so the INT-1 decision-record and sign-off validation runs against design/dedicated-integrations-triggers, followed by a schema for event transports. Both land here. check_capability_matrices.py gains --design-root (and --matrix-dir now defaults to <design-root>/matrices). A design root that publishes schema/event_transport.schema.json is validated as a triggers gate; every other root, including the INT-1 one, behaves exactly as before, which the existing suite still proves. event_transport_matrix.py holds the triggers rules, kept in its own module so the capability checker does not grow past its size budget and so the import stays one directional. Beyond the JSON Schema it enforces the two rules a schema cannot express: every claim block on a wave-1 mechanism names a source that resolves, and the no-ingress rule per context - a mechanism needing public HTTPS may not claim a context whose public_ingress_by_context entry is unavailable, a conditional context is allowed only against an outbound_only fallback covering that same context, and every provider must ship at least one outbound-only wave-1 mechanism. test_event_transport_matrices.py covers all of it, including that the INT-1 gate keeps the capability rules and that gate-close mode still fails on the outstanding signatures. The CI Scripts Tests workflow now watches the triggers design directory. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The contract calls itself normative, so a downstream ticket coding to it must compile. Three names in it did not: session_policy `provider_correlated` and trigger_event.state `replayed` are rejected by TRG-2's CHECK constraints, and the `shared` session policy that TRG-2 actually ships was undocumented. - session_policy is `per_event` | `shared`, and section 4 states the real precedence: a provider conversation key on the event payload wins over the policy, which is where provider correlation lives - it needs no enum value. - trigger_event has no `replayed` state; a replay is a new row linked by `replay_of_event_id`, which is what keeps the ledger append-only. - Drop the `enabled` and `mechanism_id` columns TRG-2's migration does not create: `state = paused` is the off switch and the mechanism is derived from kind + provider with `config.mechanism_id` recording the matrix row. - Record `job_id`'s deliberate lack of a foreign key, add the `session_id`, `name`, `node_id`, `public_id`, `signing_secret_encrypted` and schedule columns TRG-2 creates, and name the two singleton leases by their constants (`trigger_dispatcher`, `trigger_scheduler`) so TRG-3's dispatcher cannot claim a different row and drain the ledger in parallel. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rsedes The triggers gate asserted that the "1.14 candidate" framing and the 1.13 estimate's triggers exclusion "are amended rather than left to contradict this record", but nothing amended them. An accepted record must not claim an edit that does not exist, and DECISIONS.md requires the amendment in the pull request that implements the work. Amended, each with a dated "release owner decision, 2026-09-04" note: - design/dedicated-integrations/estimate.md: the exclusion line keeps its meaning for the 48.75-engineer-week actions total (unchanged) and now points at the triggers estimate for the 39.5 that sit alongside it. - design/dedicated-integrations/triggers-deferred.md: Status records the re-open, and a new Amendment section walks the record's own three re-open clauses - the ingress clause is met three of three - while restating the boundary it fixed, which still binds every wave-1 action. - design/dedicated-integrations/README.md exit-criterion row 6, so the INT-1 gate does not read "remains deferred" beside a re-opened record. The triggers README and estimate now name the three amended files instead of asserting the amendment in the abstract. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A gate checker must fail the gate, never fail itself. Three reads assumed a well-formed matrix even though the rules also run on a file that already failed the schema: the inbound_auth/payload/delivery/dedupe_key enum checks called .get() on whatever was there (AttributeError on a scalar), and both the duplicate-id set and the no-ingress rule's index used the raw mechanism_id as a dict key (TypeError on a list). All three now coerce or skip and let the existing error strings do the reporting, with no duplicate messages. Also put scripts/ci on sys.path before importing the sibling event_transport_matrix module, so `python -m scripts.ci.check_capability_matrices` works as well as running the file directly. Two tests cover the hardening; scripts/ci is 212 passed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Test Coverage AdvisorNo source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## feat/int-1-discovery-gate #14955 +/- ##
=============================================================
+ Coverage 66.45% 66.74% +0.29%
=============================================================
Files 2499 2509 +10
Lines 259913 261683 +1770
Branches 36772 39325 +2553
=============================================================
+ Hits 172736 174673 +1937
+ Misses 85009 84846 -163
+ Partials 2168 2164 -4
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
TRG-1: gate records, event-transport matrices, and the checker's
--design-rootDocs-only, plus one CI checker. Base:
feat/int-1-discovery-gate(#14906), notfeat/trg-1-triggers-gate(#14911) — see "Why this base" below. #14911's content is an ancestor of this branch, so merging this closes both.
Summary
design/dedicated-integrations-triggers/findings/2026-09-listeners.md(exit criterion 1):the dated evidence on both precedents and on why neither shape survives the current runtime, with the sidecar
position and the recommendation left as marked author sections for the platform owner. It stays
Status: draftandcriterion 1 stays open.
schema/event_transport.schema.jsonplusmatrices/{google,microsoft,slack}-events.json. Every mechanism records track, ingress requirement, inboundauthentication, subscription TTL and renewal, payload shape, delivery guarantee, replay availability, rate limits,
dedupe key, session key, and the deployment contexts it supports, each claim pointing at a dated provider-docs
source. Excluded and deferred mechanisms are recorded with their reason so nobody re-opens them:
Slack RTM (excluded), Graph rich resource-data notifications (deferred on certificate lifecycle), and Teams message
subscriptions (excluded: protected APIs, application permissions and a Teams billing model) — which is this gate's
answer to the open "Teams messages" question.
decisions/process-model.md(criterion 3): both shapes. A separatelangflow listenersprocess isprimary;
LANGFLOW_LISTENERS_MODE=subprocessis the single-container and Desktop shape; the dispatcher and theschedule tick stay in the API lifespan under a
trigger_leasesingleton;lfx servehosts neither listeners nor atrigger ingress, which answers the "Track A on
lfx serve" question with no. Lease semantics: TTL 30 s,heartbeat 10 s, reconcile poll 5 s, failover within two TTLs. Health on
LANGFLOW_LISTENERS_HEALTH_PORT(7861).decisions/self-managed-ingress.md(criterion 4): the no-relay statement first — Langflow operates norelay, in this release or as a follow-up. Every provider therefore ships at least one outbound-only mechanism
(Slack Socket Mode, Graph delta, Google sync-token / page-token polling and Pub/Sub pull), which settles "Calendar
and Drive without ingress" as poll, not relay, "Slack on Desktop" as Socket Mode with a customer-owned app, and
moves the deferred record's third re-open trigger from two of three providers to three of three.
decisions/delivery-semantics.md(criterion 5): at-least-once collapsed once by aUNIQUE (trigger_id, dedupe_key)index; write-then-ack; a 7-day replay window with a 30-day purge; replay writes anew linked row rather than mutating; retries with backoff to
max_attemptsthen dead-letter; no cross-triggerordering; per-trigger concurrency as the backpressure knob.
trigger-contract.md(criterion 6): the record TRG-2 through TRG-7 build against — five tables in onemigration, binding and pinning, the
trigger_push/trigger_listenerfamilies executing asflow_ownerwithactor
trigger_dispatcher,provider_signedas the ingress access mode, authz on the flow resource, and theboundary with the 1.13 connection contract. Session derivation is stated as the precedence TRG-2 implements: a
provider conversation key on the event payload wins, otherwise the trigger's two-value
session_policy(
per_event→trigger:{trigger_id}:{event_id},shared→trigger:{trigger_id}). Accepted by the releaseowner; the lfx, langflow-base, Enterprise and platform sign-offs are outstanding.
frontend-surfaces.md(criterion 8): every surface with its owning ticket, plus the trigger display-name ruleProduct: On Eventextending the 1.13Product: Verb Objectpalette rule, the server-drivenallowed_actionscontract, config-driven polling with no SSE, and the interim connection field TRG-7 uses until INT-8's shared
picker lands.
estimate.md(criterion 9): 34 engineer-weeks re-issued as 39.5 across TRG-1 to TRG-8, per ticket with anamed cause for every delta, plus sequencing and external lead times.
(
DECISIONS.mditem 1: amend in the pull request that implements the work). Each carries a dated"release owner decision, 2026-09-04" note:
design/dedicated-integrations/estimate.md(the triggers exclusion —the 48.75-engineer-week actions total is unchanged, the 39.5 sit alongside it),
design/dedicated-integrations/triggers-deferred.md(Statusre-opened, plus an Amendment section walking its ownthree re-open clauses and restating the boundary it fixed, which still binds every wave-1 action), and the INT-1
README's exit-criterion row 6. The "1.14 candidate" framing is gone from the triggers README itself.
--design-root:scripts/ci/check_capability_matrices.pygains--design-root(and--matrix-dirnow defaults to
<design-root>/matrices). A design root that publishesschema/event_transport.schema.jsonisvalidated as a triggers gate; every other root, INT-1's included, behaves exactly as before. The triggers rules live
in the new
scripts/ci/event_transport_matrix.py: JSON Schema validation, sourced claims, and the no-ingress ruleper context — a mechanism needing public HTTPS may not claim a context whose
public_ingress_by_contextentry isunavailable, aconditionalcontext is allowed only against anoutbound_onlyfallback covering that samecontext, and every provider must ship at least one outbound-only wave-1 mechanism. The CI Scripts Tests workflow now
watches
design/dedicated-integrations-triggers/**.Google push channels added to the Track A list (they were in no gate record before), the full sign-off map, and the
checker invocation.
Why this base
scripts/ci/check_capability_matrices.py— the checker this pull request extends — is introduced by #14906(
feat/int-1-discovery-gate) and exists neither onrelease-1.13.0nor onfeat/trg-1-triggers-gate(
git ls-tree origin/feat/trg-1-triggers-gate scripts/ci/check_capability_matrices.pyreturns nothing). The triggersREADME also links
../dedicated-integrations/...records from that same pull request, and this branch amends three ofthem. Basing on #14906 keeps INT-1's eighteen files and ~5,800 lines out of this diff and avoids an add/add conflict
on files TRG-1 never touched once #14906 squash-merges into
release-1.13.0.#14911's two files are ancestors of this branch, so #14911 needs no separate merge. The diff against #14906 also
carries twelve files of
release-1.13.0drift between the two branch points (thefunasrbundle and itsregistration seams, ~530 lines); those disappear once #14906 merges. The TRG-1 work itself is nineteen files,
+2879/−79 (
git diff 13e88b13ce..HEAD).Verification
The two
--require-acceptedfailures are expected and one of them is asserted by a test: gate-close mode fails whilethe sign-off tables are empty, and it reports only outstanding signatures — no structural errors. The INT-1 run is
included to show this branch's amendments introduce none either.
No backend, frontend or lfx suite is exercised: this pull request changes no runtime code.
Review round
Three changes after review, all on this branch:
trigger-contract.mdnow compiles against the parallel TRG-2 build. The record calls itself normative, and twoof its names were rejected by TRG-2's
CHECKconstraints:session_policy: provider_correlated(TRG-2 shipsper_event|shared, and the record did not documentsharedat all) andtrigger_event.state: replayed(TRG-2 ships six states; a replay is a new linked row). Also dropped the
enabledandmechanism_idcolumnsTRG-2's migration does not create, recorded
job_id's deliberate lack of a foreign key, added the columns TRG-2does create, and named the two singleton leases by their constants —
trigger_dispatcherandtrigger_scheduler,not
dispatcher/schedule_tick— so TRG-3's dispatcher cannot claim a different row and drain the ledger inparallel.
the rules also run on one that already failed the schema: the
inbound_auth/payload/delivery/dedupe_keyenum checks raised
AttributeErroron a scalar block, and both the duplicate-id set and the no-ingress indexraised
TypeErroron an unhashablemechanism_id. Two new tests cover it.scripts/ciwas also put onsys.pathsopython -m scripts.ci.check_capability_matricesworks alongside running the file directly.What is still open (and deliberately so)
README and the record both say so. It is the one record left at
Status: draft: marking a stub accepted would makethe README's criterion-1 row read done before it is written. The checker only enforces
acceptedunderdecisions/, so flipping it is a one-line change if the release owner prefers the letter of the rule.open. One gap is already recorded in the README boundary table:
connection-contract.mdassigns theconnection_resolutionmatrix dimension and its checker vocabulary to INT-4 and INT-5, and neither feat(integrations): add persistent connection API #14921 norfeat(integrations): broker delegated OAuth connections #14935 delivers it; INT-6 now carries it. The walk is repeated before gate close.
Status: acceptedrecords the release owner's acceptanceonly; the other roles sign in review.
estimate.mdcarries the per-ticket 39.5-week breakdown with the right keys(LE-2481, LE-2479, LE-2478, LE-2483, LE-2484, LE-2485, LE-2482 under epic LE-2477); pushing those numbers into the
Jira fields is a human pass.
events/hour per-workspace ceiling (carried as an open question on the mechanism row), Microsoft Graph subscription
lifetimes (4230 minutes for Outlook,
confidence: medium, recorded as "readsubscriptionExpirationDateTime, donot assume a constant"), and the Google Calendar/Drive channel expiries, left as
max_ttl_seconds: nullratherthan invented.