picatz / picatz/flowstate

Design exploration: history-aware dispatch policy. Temporal conditions as plain CEL over a bounded, typed event projection (Dogwood lessons, not Dogwood)

Open
#331 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

An external research pass read AWS Dogwood (Cedar's temporal sibling, Apache 2.0, 2026-08) against Flowstate and proposed a direction. This issue records that proposal with its claims checked against the tree, as an exploration to chew on, not a commitment. Flowstate will not use Cedar or Dogwood; the question is which of their lessons are worth stealing for our own YAML + CEL substrate.

The one-sentence idea

The task-dispatch policy activation gains one binding, history, a bounded list of typed flowstate.policy.v1.Event values, so a rule can condition on what has already happened in this run, in the same CEL, under the same fail-closed rules, with no new sub-language.

Why this fits Flowstate better than it fits Cedar

Dogwood exists because Cedar cannot iterate or aggregate, so it lowers temporal macros (since, count_within, sum_within) into context slots computed by a facts layer. CEL can iterate and aggregate natively (exists, filter().size(), sets.size, cel.bind). So the macro layer and the facts DSL are Cedar workarounds we do not need. What Dogwood leaves to the deployer, a durable, ordered, attested event trace, is the one thing our substrate already has: Temporal history. The proposal reduces to a projection and a binding.

What it would unlock, concretely:

  • Deny the exfil shape: once this run resolved any secret, no further http dispatch. Stated in deployment policy the Flowfile cannot weaken.
  • Cumulative bounds per-request checks cannot express: at most N http dispatches per hour per run.
  • The #206 invariant in enforcement form: deploy.apply requires two distinct attested approvals in the last 24h, where distinctness is issuer plus subject per the #215 collision rule, and the m-of-n holds regardless of what the file's wait_for_signal: gate says.

Verified against the tree (2026-08-08, main @2840287)

  • The proposal assumes an activation carrying identity, task, inputs, and run context. Reality: taskpolicy.go:210-211 declares exactly two bindings, task (string) and identity (object). No inputs, no now. Any history work sits on a surface that would first need now, and the inputs question is its own decision with its own payload-retention hazards.
  • Enforcement chokepoints exist where claimed: the dispatch check runs host-side on both drivers before secret resolution, and the signal-acceptance path knows its attested sender. Emission points for a projection are real.
  • The virtual clock in flowtest makes windowed assertions deterministic, as claimed; the ordering gate already exercises that machinery.
  • The closed protobuf event vocabulary type-checked at load would genuinely kill Dogwood's silent non-match hazard; that mechanism (protos library, load-time compile of policy files) is how the egress and task-shape surfaces already work.

The parts to be most skeptical of

  1. Projection retention vs Continue-As-New. A run that compacts its history across CAN segments (the engine works hard at exactly this) cannot cheaply re-derive a 10k-event projection on replay. Whether the projection lives in carried state (competing with CheckRunStateSize and the compaction walker), a side store (new infrastructure), or re-computation (cost at replay) changes the feasibility entirely. This is the load-bearing open question, and the proposal parks it in an appendix.
  2. Cost. A 10k-element list activation per dispatch decision, on the hot path of every step, on both drivers. The load-time cost estimator helps but the constant factor is real. The bound would need to be much smaller than proposed, or the projection incremental.
  3. Surface bloat in the other direction. #326 just argued for shrinking bespoke YAML policy keys into CEL. This proposal is aligned in language (plain CEL, no macro layer) but adds a whole new dimension of vocabulary (event kinds, windows, overflow semantics). The bar for adding it should be a worked deployment need, not symmetry with Dogwood.
  4. Run-scoped only. The honest version ships run-scope and names the cross-run gap. The m-of-n approval example is the flagship use case and is run-scoped, so it survives; cumulative tenant-wide limits do not, and the tenant ledger (entity workflow, Temporal Update) is a separate design with #105/#289 overlap.

Suggested investigation slices, if this advances

  1. Cheapest first: does any real deployment shape need run-scoped history at dispatch that wait_for_signal: plus signal policy cannot already enforce? Write the three worked examples as real policy files against a hypothetical schema and test whether each survives contact with the retention question.
  2. now in the task-policy activation, alone, is small, useful without history (time-of-day dispatch windows), and a prerequisite. It could land independently under #326's coherence work.
  3. Prototype the projection as explain-only (an audit surface, no rule reads it) to price retention and emission honestly before any enforcement semantics exist.

Related: #187 (the surface), #326 (one policy language), #206 (the approval invariant), #215 (identity distinctness), #146 (layering), #177 (typed substrate), #105/#289 (entity ledger for cross-run state).

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

Start with taskpolicy.go:210-211 and the dispatch checks in both drivers, then inspect flowtest's virtual clock and the retention paths around Continue-As-New and CheckRunStateSize. Treat the suggested slices as investigation work: produce worked policy examples, assess whether run-scoped history is needed, and price an explain-only projection before any enforcement semantics are proposed.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, distributed-systems, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.