Automations and webhooks for the AT Protocol airglow.run

feat(logs): show the latest events an automation's conditions filtered out #64

Closed tyb.there-hugo.dev
Closed opened by tyb.there-hugo.dev

Problem #

The "Filtered out" count (95cd138, #14) counts every event in the trigger's collection that fails the trigger gate. For the most common Airglow shape, a gate like event.commit.record.subject == {{self}} with no watched repos, that is the whole network's volume for the collection. The number keeps rising whether or not the owner's own test event arrived, so an owner still cannot tell "my event never arrived" from "my event was rejected", which is what #14 set out to fix.

Evidence #

  • lib/jetstream/consumer.ts:890-894: every trigger-gate miss calls noteFiltered.
  • lib/jetstream/filter-counts.ts: only a count and the latest time are stored.
  • app/routes/u/[handle]/[rkey]/logs.tsx:85-99.
  • The session scenario: docs/brainstorms/2026-10-17-graze-conference-automation-feedback.md:245-256.
  • The contributor's own note in the #14 pr text: "The count does not say why an event was rejected or which event it was".

Expected #

The logs page lists the last few events (for example 20) that each automation's conditions rejected. Each entry shows the event's repo DID, collection/rkey or AT URI, time, and which gate step rejected it (trigger gate or in-tree gate step id/label). The owner can then find their own test event, or see it is absent.

Acceptance criteria #

Out of scope #

  • Per-assertion "why" explanations.
  • Sampling configuration.
  • Changing the count itself.

Queued: the loop will work on this version of the issue.

loop:queued cid=bafyreibhyn2xsejnpypxugcmcaziqqzjxhakvzhnzthlpvqhkjnx4dv7l4

Working on this, attempt 1.

loop:claim run=contribute-20261030-104241-64 branch=loop/64 attempt=1 issue=64

feat(logs): show the latest events an automation's conditions filtered out

The logs page now lists the latest 20 events each automation's conditions rejected. Each entry shows the time, the repo DID, the record's collection/rkey with PDSls and atproto.at links, and the step that rejected it. The "Filtered out" count covers the whole network's volume for a collection, so it could not tell the owner whether their own test event arrived. The list lets them find that event, or see that it is not there. The hot path still makes no query: rejections go into a bounded ring per automation in memory, and the existing filter-count flush writes them.

What changed #

  • New table automation_filtered_events (migration 0003_low_christian_walker.sql, from pnpm db:generate). Its FK to automations cascades on delete, and it is indexed on (automation_uri, filtered_at). The id is bigint because rows churn on every flush, and an integer identity could run out.
  • noteFiltered(uri, event, step, now) in lib/jetstream/filter-counts.ts now also pushes the event onto a ring per automation that holds at most FILTERED_EVENTS_KEPT = 20 entries. The ring holds only references; the AT URI is built at flush time. flushFilterCounts writes the counts as before. It then inserts each ring, oldest first, 50 automations per insert, and trims storage to the newest 20 per automation with a row_number() delete. If a batch fails, it retries one automation at a time, the same as the counts do.
  • The rejecting step is recorded at every call site:
    • trigger for a trigger-gate miss (consumer);
    • the gate's step id for an in-tree gate stop (run-steps.ts);
    • fetch:<name> for a legacy row's data-source condition (handler.ts). A loop-item skip still records nothing.
  • pruneFilterCounts (30-day cleanup) also deletes events older than the cutoff.
  • DeliveryLog shows a <details> element under the count's alert, collapsed by default, with the entries newest first. The step label comes from the automation's tree. A gate removed since then shows as "Condition". The section appears only when there are entries.
  • GET /api/automations/:rkey returns filteredEvents, so Refresh updates the list. Both the logs page and the API are owner-only.
  • CONCEPTS.md: the Gate entry mentions the kept events.

Verification #

  • pnpm run check and pnpm run test pass: 183 files, 2829 tests.
  • New tests in filter-counts.test.ts:
    • the ring keeps only the latest N, and the count still counts every rejection;
    • a flush writes the repo, URI, time and step;
    • storage is trimmed to N per automation across flushes, without touching other automations;
    • a non-commit event is stored with no URI;
    • a flush drops only a deleted automation's events;
    • the prune removes events older than the cutoff;
    • deleting an automation deletes its events (cascade).
  • run-steps.test.ts: an in-tree gate stop calls noteFiltered with its step id (g1), and a loop-item skip calls nothing (the existing test still passes). consumer.test.ts: a trigger-gate miss records trigger and the event.
  • logs.test.tsx: the owner sees the collapsed list, newest first, with step labels and viewer links. Any other viewer is redirected and sees none of it. DeliveryLog.test.tsx: labels, an empty state with no list, and Refresh updating the list while keeping it open and keeping focus on the Refresh button. API test for filteredEvents.
  • Keyboard: the section uses a native <details>/<summary>, which you can focus and toggle with Enter/Space. The viewer links have their own names ("Open at://... in PDSls"). I could not run a real browser in this container (no PDS and no curl), so I have not tried the page with the keyboard. That is worth a quick check.

Acceptance criteria #

Decisions you can reverse #

  • N = 20 (FILTERED_EVENTS_KEPT in lib/jetstream/filter-summary.ts).
  • A legacy row's data-source condition records fetch:<name> and shows as Conditions on data source "<name>". The issue named only trigger and gate step ids.
  • The time shown is when the event was rejected (filtered_at). The Jetstream time_us is stored but not displayed.
  • The Record column shows collection/rkey because the repo DID has its own column. The full AT URI is in the viewer links.
  • The list is only on the logs page, not in the automation overview's summary.

Review: https://tangled.org/exosphere.site/airglow/compare/main...loop/64

loop:pushed run=contribute-20261030-104241-64 sha=f6f32d5dc49c1d34f548ff581dbba36f4e265626

The migration on f6f32d5dc49c is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0003_low_christian_walker.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261030-105125-64 sha=f6f32d5dc49c1d34f548ff581dbba36f4e265626 result=destructive

The review of f6f32d5dc49c was stopped; it does not count.

loop:failed run=review-20261030-110124-64 sha=f6f32d5dc49c1d34f548ff581dbba36f4e265626 interrupted=1

Verdict: merge. The branch meets all five acceptance criteria of #64, and it stays inside the issue's scope. Rejected events go into a bounded ring per automation, with no query on the hot path. The existing 10 s flush writes them and trims storage to 20 per automation. Each entry records trigger or the gate's step id. The logs page lists the entries for the owner only, newest first, in a collapsed <details> with PDSls/atproto.at links. Rows cascade with the automation and go in the 30-day prune. pnpm run check and pnpm run test both pass (183 files, 2829 tests).

What I checked and how:

  • Every caller of noteFiltered: I searched for them myself and found three. The consumer's trigger-gate miss records trigger. An in-tree gate stop in run-steps.ts records step.id, after the loopDepth > 0 return, so a loop-item skip records nothing. A legacy fetch-condition skip in handler.ts records fetch:<name>. skippedBy is always set when skip is true (fetcher.ts). Nothing else rejects an event without going through one of these three calls.
  • Readers of the new table: only getFilteredEvents, which the logs page and GET /api/automations/:rkey call. Both look up the automation through the owner's DID, or the page's owner check. The test for another viewer gets a 302 and none of the list.
  • Throwaway PGlite test (since deleted): it ran 120 automations × 100 network-wide app.bsky.feed.like creates per round, over 3 flushes, so the 50-automation insert chunks were used. It then flushed a batch holding a deleted automation plus a later g1 rejection. The results:
    • storage held exactly 20 × 120 rows;
    • each list came back newest first with the right URIs and steps;
    • the deleted automation's rows were dropped without losing the others;
    • the prune emptied the table. A tight loop of 1M noteFiltered calls also ran well under the test's time.
  • UI: the island reuses DeliveryLog's existing table, URI and viewer-link styles. The two new styles use only space, fontSize, fontWeight and vars.color tokens. The control is a native <summary>, so it is keyboard-operable with the global :focus-visible ring. A test checks that Refresh keeps the section open and focus on the Refresh button. Each viewer link's accessible name contains the full AT URI, which tells the rows apart.
    • Empty state: the count's alert ("No events were filtered out...") shows and the list does not. The list is data-driven, not a section waiting on a field to become valid, so I did not count it under the conditional-section rule.
  • Migration 0003: it only creates automation_filtered_events with a cascading FK and an (automation_uri, filtered_at) index. It changes no existing table and touches no existing rows. The owner merges it.
  • Merge with main: the branch is based on cdc51e5, and git merge-tree against main (d79e68c) merges cleanly. I judged the UI against main's docs/design.md.

Two limits to know about. Neither blocks the merge, and both follow from the issue's own design:

  • For a network-wide trigger such as likes with a subject == {{self}} gate, a ring of the latest 20 per 10 s flush covers only a fraction of a second of traffic. The owner's own test event will rarely be in it. For the low-volume lexicons in the session scenario, the list works as the issue intends. Keeping the owner's own events first would be a follow-up issue.
  • Condition steps have no name, so every in-tree gate shows as "Condition", the same label the dry-run log rows use. On an automation with two gates, the list does not say which one rejected the event.

loop:verdict run=review-20261102-175428-64 sha=f6f32d5dc49c1d34f548ff581dbba36f4e265626 verdict=merge

main moved and no longer merges cleanly into the branch, so a fix round will merge it.

loop:carry from=f6f32d5dc49c1d34f548ff581dbba36f4e265626 conflict=1

Fix round 1: main no longer merges cleanly into the branch.

loop:fix run=contribute-20261102-180013-64 round=1 issue=64

feat(logs): show the latest events an automation's conditions filtered out

The logs page now lists the latest 20 events each automation's conditions rejected. Each entry shows the time, the repo DID, the record's collection/rkey with PDSls and atproto.at links, and the step that rejected it. The "Filtered out" count covers the whole network's volume for a collection, so it could not tell the owner whether their own test event arrived. The list lets them find that event, or see that it is not there. The hot path still makes no query: rejections go into a bounded ring per automation in memory, and the existing filter-count flush writes them.

What changed #

  • Fix round 1: merged main (one import conflict in app/routes/api/automations/[rkey].ts, which now keeps both logAutomationUpdate and getFilteredEvents). Reset lib/db/migrations to main, removed the branch's 0003_low_christian_walker.sql, and regenerated the same table as 0004_abandoned_lord_tyger.sql on top of main's 0003_known_princess_powerful.sql.

  • New table automation_filtered_events (migration 0004_abandoned_lord_tyger.sql, from pnpm db:generate). Its FK to automations cascades on delete, and it is indexed on (automation_uri, filtered_at). The id is bigint because rows churn on every flush, and an integer identity could run out.

  • noteFiltered(uri, event, step, now) in lib/jetstream/filter-counts.ts now also pushes the event onto a ring per automation that holds at most FILTERED_EVENTS_KEPT = 20 entries. The ring holds only references; the AT URI is built at flush time. flushFilterCounts writes the counts as before. It then inserts each ring, oldest first, 50 automations per insert, and trims storage to the newest 20 per automation with a row_number() delete. If a batch fails, it retries one automation at a time, the same as the counts do.

  • The rejecting step is recorded at every call site:

    • trigger for a trigger-gate miss (consumer);
    • the gate's step id for an in-tree gate stop (run-steps.ts);
    • fetch:<name> for a legacy row's data-source condition (handler.ts). A loop-item skip still records nothing.
  • pruneFilterCounts (30-day cleanup) also deletes events older than the cutoff.

  • DeliveryLog shows a <details> element under the count's alert, collapsed by default, with the entries newest first. The step label comes from the automation's tree. A gate removed since then shows as "Condition". The section appears only when there are entries.

  • GET /api/automations/:rkey returns filteredEvents, so Refresh updates the list. Both the logs page and the API are owner-only.

  • CONCEPTS.md: the Gate entry mentions the kept events.

Verification #

  • pnpm run check and pnpm run test pass: 185 files, 2844 tests (after merging main).
  • New tests in filter-counts.test.ts:
    • the ring keeps only the latest N, and the count still counts every rejection;
    • a flush writes the repo, URI, time and step;
    • storage is trimmed to N per automation across flushes, without touching other automations;
    • a non-commit event is stored with no URI;
    • a flush drops only a deleted automation's events;
    • the prune removes events older than the cutoff;
    • deleting an automation deletes its events (cascade).
  • run-steps.test.ts: an in-tree gate stop calls noteFiltered with its step id (g1), and a loop-item skip calls nothing (the existing test still passes). consumer.test.ts: a trigger-gate miss records trigger and the event.
  • logs.test.tsx: the owner sees the collapsed list, newest first, with step labels and viewer links. Any other viewer is redirected and sees none of it. DeliveryLog.test.tsx: labels, an empty state with no list, and Refresh updating the list while keeping it open and keeping focus on the Refresh button. API test for filteredEvents.
  • Keyboard: the section uses a native <details>/<summary>, which you can focus and toggle with Enter/Space. The viewer links have their own names ("Open at://... in PDSls"). I could not run a real browser in this container (no PDS and no curl), so I have not tried the page with the keyboard. That is worth a quick check.

Acceptance criteria #

Decisions you can reverse #

  • N = 20 (FILTERED_EVENTS_KEPT in lib/jetstream/filter-summary.ts).
  • A legacy row's data-source condition records fetch:<name> and shows as Conditions on data source "<name>". The issue named only trigger and gate step ids.
  • The time shown is when the event was rejected (filtered_at). The Jetstream time_us is stored but not displayed.
  • The Record column shows collection/rkey because the repo DID has its own column. The full AT URI is in the viewer links.
  • The list is only on the logs page, not in the automation overview's summary.

Review: https://tangled.org/exosphere.site/airglow/compare/main...loop/64

loop:pushed run=contribute-20261102-180013-64 sha=7a36db700091909cb3f0267c8a8f8e99d246353b

The migration on 7a36db700091 is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261102-180233-64 sha=7a36db700091909cb3f0267c8a8f8e99d246353b result=destructive

Verdict: merge. This head (7a36db7) merges main into the branch the last round approved (f6f32d5) and regenerates the filtered-events migration as 0004 on top of main's 0003. The branch's diff against main matches what was approved, apart from the merge context. The one conflict, the imports in app/routes/api/automations/[rkey].ts, now keeps both logAutomationUpdate and getFilteredEvents. pnpm run check and pnpm run test both pass (185 files, 2844 tests).

What I checked and how:

  • The merge: I diffed cdc51e5..f6f32d5 against 398d214..7a36db7, leaving out the migrations. The only differences are hunk offsets, plus the kept logAutomationUpdate import. No branch logic changed, and main's #38 code is intact.
  • Acceptance criteria, checked again against the code:
    • Every call to noteFiltered (I searched for them myself) records a step: trigger in the consumer, step.id after the loopDepth > 0 return in run-steps.ts (so a loop-item skip records nothing), and fetch:<name> in handler.ts.
    • Rejections go into a ring of 20 per automation, with no query on the hot path. The existing flush writes them and trims storage to 20.
    • The rows cascade on delete and are cleared by pruneFilterCounts, which lib/db/cleanup.ts calls.
    • Both readers, the logs page and GET /api/automations/:rkey, are owner-only.
  • Real input (throwaway route test, since deleted): 25 plain app.bsky.feed.post creates, with full post records and alternating trigger/g1 steps, then one identity event, all through noteFiltered, then flushFilterCounts, then the real logs route on PGlite with the real migrations applied.
    • The page showed "26 events..." in the alert, and a collapsed "Latest 20 events filtered out" list, newest first.
    • The identity event showed as "No record". The posts showed as app.bsky.feed.post/<rkey>, with PDSls and atproto.at links whose names include the full AT URI.
    • The oldest 6 events had been dropped.
  • UI against docs/design.md: the list is a native <details>/<summary>, so it works from the keyboard. Refresh keeps it open and keeps focus on the Refresh button (tested). The two new styles use only tokens.
    • The table reuses DeliveryLog's existing table styles rather than the shared Table. That matches the delivery log table directly below it, and adds no new style that re-creates a component.
    • Empty state: the count's alert shows and the list does not, so no section waits on a field becoming valid.
  • Migration 0004_abandoned_lord_tyger.sql: it only creates automation_filtered_events, with a cascading FK to automations.uri and an (automation_uri, filtered_at) index. It changes no existing table and touches no existing rows. The owner merges it.

The last round's two limits still apply, and neither blocks the merge:

  • On a network-wide trigger, 20 entries per 10 s flush cover only a moment of traffic.
  • Every in-tree gate is labelled "Condition", so on an automation with two gates the list does not say which one rejected an event.

loop:verdict run=review-20261102-181027-64 sha=7a36db700091909cb3f0267c8a8f8e99d246353b verdict=merge

Merged main into the branch: 50d776518c7e318f172589e0536c2ad9544b340f.

loop:carry from=7a36db700091909cb3f0267c8a8f8e99d246353b sha=50d776518c7e318f172589e0536c2ad9544b340f

The migration on 50d776518c7e is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261102-181427-64 sha=50d776518c7e318f172589e0536c2ad9544b340f result=destructive

Merged main into the branch: 6eb93b61e4ce8ddff4d2ae148764a6790100189c.

loop:carry from=50d776518c7e318f172589e0536c2ad9544b340f sha=6eb93b61e4ce8ddff4d2ae148764a6790100189c

The migration on 6eb93b61e4ce is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261102-182222-64 sha=6eb93b61e4ce8ddff4d2ae148764a6790100189c result=destructive

Merged main into the branch: 344ef2a571eb07b3e2ce7b2c834e45ba0c8f0583.

loop:carry from=6eb93b61e4ce8ddff4d2ae148764a6790100189c sha=344ef2a571eb07b3e2ce7b2c834e45ba0c8f0583

The migration on 344ef2a571eb is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261102-183636-64 sha=344ef2a571eb07b3e2ce7b2c834e45ba0c8f0583 result=destructive

Merged main into the branch: 2261294217e317ad224a18c2d68292627e78cb0b.

loop:carry from=344ef2a571eb07b3e2ce7b2c834e45ba0c8f0583 sha=2261294217e317ad224a18c2d68292627e78cb0b

The migration on 2261294217e3 is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261102-213119-64 sha=2261294217e317ad224a18c2d68292627e78cb0b result=destructive

Merged main into the branch: 55ee9ec2d8f29061033589554495cbf0c03aec84.

loop:carry from=2261294217e317ad224a18c2d68292627e78cb0b sha=55ee9ec2d8f29061033589554495cbf0c03aec84

The migration on 55ee9ec2d8f2 is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261102-214550-64 sha=55ee9ec2d8f29061033589554495cbf0c03aec84 result=destructive

Merged main into the branch: 9f6f94ba307db5228a2afba5673b6c4c18c37fc7.

loop:carry from=55ee9ec2d8f29061033589554495cbf0c03aec84 sha=9f6f94ba307db5228a2afba5673b6c4c18c37fc7

The migration on 9f6f94ba307d is what pnpm db:generate writes from the schema, but it does more than add:

  • a comment the check cannot read past: --> statement-breakpoint CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtere...

Only loop merge 64 --destructive merges it, once the gate passes.

0004_abandoned_lord_tyger.sql:

CREATE TABLE "automation_filtered_events" (
	"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "automation_filtered_events_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
	"automation_uri" text NOT NULL,
	"did" text NOT NULL,
	"record_uri" text,
	"event_time_us" bigint NOT NULL,
	"step" text NOT NULL,
	"filtered_at" timestamp with time zone NOT NULL
);
--> statement-breakpoint
ALTER TABLE "automation_filtered_events" ADD CONSTRAINT "automation_filtered_events_automation_uri_automations_uri_fk" FOREIGN KEY ("automation_uri") REFERENCES "public"."automations"("uri") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "automation_filtered_events_automation_uri_filtered_at_idx" ON "automation_filtered_events" USING btree ("automation_uri","filtered_at");

loop:migration run=verify-20261103-115758-64 sha=9f6f94ba307db5228a2afba5673b6c4c18c37fc7 result=destructive

Merged onto main as 1dab9b7981f7e448c9b471d33fc458df97054eb1.

loop:merged sha=1dab9b7981f7e448c9b471d33fc458df97054eb1 head=9f6f94ba307db5228a2afba5673b6c4c18c37fc7

Sign up or Sign in to add to the discussion.