picatz / picatz/flowstate

The connectivity family: sql first — plugins for the data every business workflow touches

Open
#181 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

design enhancement kind/design-record
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

The factory (#180) proves the system on ourselves; the connectivity family proves it on everyone else's actual work. Most business workflows are, at their core, "read something, decide, write something, tell someone" — and the somethings are databases, queues, object stores, and messages. This issue records the family's shared rules and designs its first member (sql) precisely, because SQL carries the sharpest traps and the decisions made there template the rest.

The sql plugin

  • Parameterized-only, structurally. query: takes SQL text and a separate params: map — there is no spelling that interpolates a value into query text, and CEL expressions produce parameters, never SQL fragments. String-assembled SQL is the injection class; the schema simply doesn't express it. (An advanced identifier-substitution need — dynamic table names — is refused until a real workload argues it, and then designed as its own quoted-identifier input, never text splicing.)
  • DSNs are secrets, credentials invisible where possible. The connection string is a secret ref (secret_inputs — third consumer); user/password never in the URL input; and this family is rung-2 motivation for #173 (a sidecar/proxy holding the credential while the plugin speaks to a local socket is exactly how the enterprise pattern goes).
  • Results are bounded and typed. max_rows required with a cap, byte-bound on the wire below the driver where achievable (the RoundTripper lesson applied to database drivers — investigate per-driver feasibility honestly and record what each can't do); a truncated result is a refusal naming the bound, never a silent prefix (the no-silent-caps rule — a partial answer that looks complete is the worst outcome for a decision-feeding query).
  • The #177 convergence, and this is the beautiful part: a query's result-set schema (column names/types from the driver) projects into a descriptor, so rows come back as typed values CEL reasons over with checked field access — ${steps.lookup.rows.filter(r, r.balance_cents > 0)} type-checks. Where a workflow declares the expected row type, the plugin validates the live result against the declaration — schema drift in the database becomes a positioned, diagnosed failure at the step, not a silent misread downstream. Declared-type-vs-live-schema checking is the single strongest practical argument for the types work.
  • Transactions end where the activity ends — stated, not discovered. A transaction cannot span steps: steps are activities, retried and resumed on different workers, and a held transaction is worktree-state in database costume (the #149 values-not-worktrees rule again). One step = at most one transaction, committed or rolled back inside it. The cross-step consistency story is what the engine already has — sagas (undo:), idempotency keys as params, sdk.OutcomeUnknown for the commit-ack lost case (its sharpest real-world instance: the INSERT that may have committed). The docs teach this the way DSL.md teaches control-flow costs: the wrong instinct (BEGIN in step one, COMMIT in step three) named, refused, and rewritten.
  • Drivers: postgres first (one excellent driver beats three adequate ones), the family pattern making mysql/sqlite additions mechanical. Pure-Go drivers only; no cgo in plugins.

Family rules (so each next member is mostly decided)

Queues (kafka/sqs/pubsub — publish is easy; consume interacts with triggers #180-stage-6 and needs its own design), object storage (s3/gcs — converges with the content-addressed store thread in #149), notifications (slack/email — the humans-in-the-loop output half). Every member: typed bounded outputs shaped for CEL; secrets by ref with #173 as the direction; explicit connection targets (no ambient endpoints); fail-closed egress under the same netpolicy; manifest-declared constraints (#177's plugin projection) so the LSP/MCP/validator know each verb's contract; examples with the #165 charter shape, exercised by the reachable harness against real local instances where feasible (postgres in a container for the plugin's own CI, the same honesty the git plugin's local-server tests have).

Sequencing: after the current wave and the greenlit language slices — sql lands with (or just after) types slice 1, because the typed-rows convergence is its headline; an examples/ order-fulfillment variant reading/writing real postgres becomes the portfolio's business-workload anchor (#165 slice 2 material).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation file is named. Start by reading DSL.md and the #177 types work, then inspect the existing git plugin's local-server tests and the reachable harness. The design is done when a postgres-first plugin specifies bounded typed rows, secret-ref DSNs, one-step transactions, manifest constraints, and an exercised examples/ order-fulfillment workflow.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql, sql
Domain
backend, database, devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.