I-0138: packaged-first examples — gold-path Python peers + cross-tenant fix#193
Merged
Conversation
added 30 commits
July 11, 2026 18:31
…ams, typed validation, per-run binding New canonical example for the params(...) surface (the I-0116 authoring half): a sync_file template declaring source/dst (required) + mode/max_files (defaulted). The compiler extracts the typed input interface; the server validates every run's --context values against it; bound values arrive in tasks as top-level context keys. Harness: the simple-packaged bespoke runner is generalized into _run_gold_path()/_run_to_completed() and a new demos features parameterized-workflow command runs the template twice with different bindings (both must Complete) and asserts a missing-required-param run is rejected BEFORE execution. Auto-joins the CI matrix via demos matrix (13 examples now). Loud finding filed as CLOACI-T-0894: I-0116 instance REGISTRATION is embedded-runner-only (register_cron_workflow_instance) — no server route, no cloacinactl noun. Named/scheduled instances cannot be created through the primary interface; the README says so honestly instead of papering over it. Verified live: build success -> two Completed executions with different param bindings -> missing-param run rejected. Exit 0.
…; blocked on the plugin secrets channel (T-0895)
Building the secrets example surfaced and fixed three gaps in the
primary-interface secrets path:
1. The execute route could not bind secrets at all: it merged context
naively, so {"$secret": "name"} references never became the alias map.
It now routes through the SAME merge_instance_params the instance fire
path uses — refs go to the reserved alias map (names only), reserved
scheduler keys are protected, malformed refs are 400s.
2. validate_declared_params now understands encrypted slots: a declared
secret must be bound via a $secret reference; a LITERAL value is
rejected before execution.
3. Neither server runner path threaded a secret resolver onto the
in-process executor. New DefaultRunner::with_database_secrets carries
one at construction; the server wires tenant-scoped resolvers
(secrets::runner_secret_resolver) on both the global runner and the
TenantRunnerCache. Fail-closed without CLOACINA_SECRET_KEK.
The demo compose ships a fixed demo KEK. The example (notify_oncall:
params + secrets(api_token), side-channel resolution, derived-facts-only
persistence) and its harness lane (create -> $secret-bound run -> rotate
-> rerun -> metadata-only reads -> literal rejected) are complete but the
lane is EXCLUDED from CI: verification surfaced CLOACI-T-0895 — the
fidius task protocol has no secrets channel, so a PACKAGED task's
context.secret() cannot resolve anywhere (the agent D-5 unwrap attaches a
resolver the FFI bridge then drops). The lane is that fix's verification
vehicle; the README carries an honest status banner.
…an resolve context.secret()
The fidius task protocol had no secrets channel: DynamicLibraryTask
serialized only context.data(), dropping the host-attached secret
resolver, so context.secret() in a PACKAGED task failed in every
deployment mode — including agents, whose D-5 one-time-key unwrap
attached a resolver the bridge then discarded. Secret delivery to
packaged tasks had never worked.
The bridge: the host resolves every {"$secret"}-referenced name via the
context's resolver BEFORE the plugin call (fail-closed per secret) and
ships the VALUES in a new TaskExecutionRequest.resolved_secrets field,
keyed by concrete secret name; the plugin shell attaches them to the
rebuilt scope via the new cloacina_workflow::secret::MapSecretResolver,
so context.secret()/secret_field() work identically inside packages. The
alias map already crosses in context_json, so local-binding aliasing
keeps working. One bridge serves both in-process and agent execution.
Both new Debug impls render secret NAMES only.
Plugin interface version 4 -> 5: the request struct is a bincode wire
change, so stale artifacts fail the version gate at load rather than
mis-decoding.
Verified: angreal demos features workflow-secrets FULL PASS — create ->
$secret-bound run -> execution Completed -> rotate -> rerun Completed ->
metadata-only reads -> literal rejected. Lane re-enabled in the CI
matrix (14 examples).
…ently passthrough in packaged graphs)
…crates; cg-feature-tour example The CG macro emitted umbrella-crate (cloacina::) paths that only resolve for embedded consumers, so a packaged crate with a trigger-less computation_graph or a task(invokes=computation_graph(...)) failed with 'cannot find crate cloacina' — task-to-graph invocation was unshippable on the primary (packaged) path. Two single-emission sites missed the cfg(feature=packaged) dual-emit the surrounding ctor/trait impl already used: the trigger-less compiled-fn signature (codegen.rs) and the invoke tail's GraphResult match (tasks.rs, now a cfg-gated alias). Host-crate emission untouched; T-0538/T-0540 integration tests unaffected. New example examples/features/computation-graphs/cg-feature-tour: Kafka stream accumulator (typed via JsonSchema, upgraded in package.toml) + a workflow task that invokes a trigger-less graph with a post_invocation hook. Bespoke demos-features lane runs the invoking workflow to Completed, injects a typed event + polls reactor fires, and produces a Kafka message to fire the stream accumulator. Auto-joins the CI matrix (15 examples). Also files T-0896 (polling/batch silently passthrough in packaged graphs) and the T-0897 open tail (handle-param tasks still emit ungated ::cloacina). Verified: cg-feature-tour compiles clean offline against the local crates.
…the T-0898 provider migration Per maintainer steer: kafka is a consumption connector, not core arch — it should compile into the package, not the host. Rather than gut the example, keep all its code (kafka stream accumulator + typed inject + task-to-graph invocation) and migrate kafka onto the delivered constructor/provider mechanism next session (CLOACI-T-0898). The CI lane asserts only the task-to-graph INVOCATION surface (works today, package-clean, the T-0897 fix). The kafka stream + inject/fire surfaces stay in the example code but aren't asserted yet: kafka is currently a host cargo feature (rdkafka in core cloacina), so a stream accumulator silently degrades to passthrough unless the server was built --features kafka. README 'Status of the surfaces' says so honestly and points at T-0898.
…ion done, stream deferred
…simple-packaged Establishes the packaged-PYTHON gold path that no user-facing example showed (only demo-py-* fixtures). examples/features/workflows/python-packaged: a data_pipeline (collect_data -> process_data -> generate_report) authored with bare @cloaca.task decorators + minimal package.toml (language + entry_module inferred from the workflow/<name>/ layout; NOT a WorkflowBuilder, which is in-process only). No Cargo/build.rs: the compiler skips cargo for language=python and the server reconciler imports the module via its embedded Python runtime. Python is a core server capability, so a default host server loads Python packages with no extra build features. New bespoke `angreal demos features python-packaged` lane reuses _run_gold_path; auto-joins the CI matrix (16 examples). Verified live: pack -> upload -> build success -> workflow run data_pipeline -> execution Completed.
…on param/secret/boundary parsing Python peer of parameterized-workflow: examples/features/workflows/ python-parameterized declares typed params with @cloaca.workflow_params. Bespoke demos-features lane runs it twice with different --context bindings (both Completed) and asserts a missing-required-param run is rejected. In CI. Building it surfaced CLOACI-T-0899: the compiler's Python source scanners (param_parse.rs) parse workflow_params/workflow_secrets/boundary_schema by naive comma/= splitting with no lexer, so a normal inline comment broke the declaration — source=str, # required parsed as a param named the comment, and the server rejected every run with 'missing required param'. A user commenting their params silently made the workflow unrunnable. Fix: strip_py_comments() applied at all three read sites before parsing (comment-aware: # to EOL outside string literals; handles single/double/ triple quotes + escapes; preserves newlines). One fix covers params, secrets, and boundary schemas. Verified: python-parameterized builds + validates + runs to Completed; was broken before.
…nores docstring-quoted decorator syntax
Python peer of workflow-secrets: examples/features/workflows/python-secrets
declares @cloaca.workflow_secrets("api_token"), reads it via
context.secret_field at execution, persists only derived facts. Bespoke lane
(with the demo KEK) asserts create -> $secret-bound run -> Completed ->
rotate -> rerun -> metadata-only get -> literal rejected. In CI.
Positive finding: Python needs NO equivalent of the Rust T-0895 FFI
secrets-channel fix — Python packaged tasks run IN-PROCESS, so the resolver
the server threads onto the runner (T-0890) flows straight through the
context into the Python task; context.secret() resolves directly.
Building it surfaced the second half of CLOACI-T-0899: the source scanners
match / anywhere, including inside
DOCSTRINGS — a task docstring showing @cloaca.workflow_secrets("name") as
example text was parsed as a real required secret named 'name', failing every
run with 'missing required param name'. Extended strip_py_comments to blank
the interior of triple-quoted strings (docstrings) for the scanner's view,
while preserving single/double-quoted param DEFAULT values and leaving doc
extraction (doc_parse) untouched. Verified: python-secrets (whose docstring
contains the decorator syntax) now builds + runs to Completed.
…espoke command per example
The bespoke @angreal.command-per-packaged-example was harness boilerplate,
not a per-example feature (as the maintainer noted). package.toml presence
cleanly classifies an example: embedded (cargo run) vs packaged (server gold
path). So:
- get_rust_feature_directories now SKIPS any dir with a package.toml (they're
packaged); the manual exclude list collapses to two genuine special cases
(python-workflow bespoke wheel, validation-failures negative fixture).
- New get_packaged_example_directories discovers every package.toml example +
parses its workflow_name/graph_name.
- New _register_packaged_example drives them ALL through one gold-path command.
Default assertion from the manifest: workflow_name -> run to Completed. Thin
overrides for the few that need more: params (2 runs + rejection), secrets
(create/bind/rotate/get/reject + KEK), and graphs (inject -> reactor fires).
_PACKAGED_SKIP holds the not-yet-driveable ones WITH REASONS (complex-dag,
packaged-triggers, packaged-workflows) — no silent drops.
- ~8 near-identical bespoke functions deleted; matrix() now unions the embedded
+ packaged + python-workflow sources.
This also fixes two latent CI-wiring bugs: packaged-graph and
python-packaged-graph were auto-registered as `cargo run` (no Cargo.toml ->
fail); they're now proper gold-path lanes. And fixes the fires-endpoint parse
(ListResponse is {items,total}, not {fires}) that made my earlier
python-packaged-graph assertion wrongly fail — the reactor was firing fine.
…e Python CG example Adds @cloaca.boundary_schema(best_bid, best_ask) to python-packaged-graph's orderbook accumulator — the Python parity of deriving schemars::JsonSchema on a Rust boundary type — and extends the generic graph-inject lane with an optional typed-rejection check. Verified end-to-end: a non-object event (42) is rejected by the accumulator's declared boundary schema, and a valid event fires the reactor. Closes the boundary_schema Python coverage gap (previously fixtures-only); no bug this time — the typed-inject path works.
…— drop the engine umbrella
complex-dag, packaged-workflows, and packaged-graph still used the pre-T-0887
shape: ../../../../crates/ PATH deps (which don't resolve when the compiler
stages a package to a temp dir, and which --dev-workspace can't patch), and —
for complex-dag — a full cloacina engine UMBRELLA dependency pulled in only to
use cloacina::{Context, TaskError} (both re-exported by the lean
cloacina-workflow). So a packaged build compiled the entire engine for two
types.
Re-authored all three to the lean version-dep form (mirror simple-packaged):
crates.io version deps, Context/TaskError from cloacina-workflow, no umbrella
dep, cruft trimmed. Offline cargo build --lib dropped from a multi-minute
umbrella compile to ~12s each. Un-skipped complex-dag + packaged-workflows in
the gold-path registrar (packaged-graph already registered); packaged-triggers
stays skipped pending a fire-the-trigger step. Filed as CLOACI-T-0900.
…as doc-only) + lean deps — T-0900 complete
packaged-triggers had no actual trigger — it declared a #[workflow] and merely
DOCUMENTED (in the README) how a trigger would inject filename/source_path; the
tasks unwrap_or("unknown"), so the example never demonstrated the feature it is
named for. Added a real poll trigger — #[trigger(on = "file_processing",
poll_interval = "3s")] — that fires the workflow automatically and injects the
filename via TriggerResult::Fire(Some(ctx)). Re-authored deps to the lean
version-dep form (path -> version) like the other examples.
New _trigger_wait_steps lane override: instead of running the workflow, it waits
for the poll trigger to fire an execution AUTOMATICALLY and asserts it reaches
Completed — proving the packaged-trigger path end to end (macro -> FFI
projection -> host trigger registry -> scheduled fire). Verified live: the
trigger fired an execution on its own and it Completed. _PACKAGED_SKIP is now
empty — every packaged example is driveable on the gold path. Closes T-0900.
…on the gold path
The Python peer of the Rust packaged-triggers example, and a gap probe: the
Python @cloaca.trigger surface existed only as a demo-stack fixture
(demo-py-cron) — never verified through the features gold path (host compiler →
reconcile → server trigger registry → scheduled fire).
New example examples/features/workflows/python-triggers/: a pure-Python
validate → transform → archive workflow plus @cloaca.trigger(on="file_processing_py",
poll_interval="3s") that fires it automatically, injecting the filename via
cloaca.Context + TriggerResult.fire(ctx). Minimal manifest (language + entry
module inferred from the workflow/file_inbox/ layout), no triggers section — the
decorator running at import IS the declaration.
Registered with the _trigger_wait_steps("file_processing_py") lane (auto-run,
no `workflow run`). Verified live: the poll trigger fired an execution on its own
and it Completed. No product bug — the Python packaged-trigger path is solid;
this closes the coverage gap.
…n the gold path The Python peer of the Rust conditional-retries example (which is embedded-only), and a gap probe for the Python packaged retry path. fetch_unreliable RAISES on its first two attempts and only succeeds on the third, under @cloaca.task(retry_attempts=4, retry_backoff="fixed", retry_delay_ms=200). The run can therefore only reach Completed if the server honored the retry policy and re-executed the task — if retries were ignored, attempt 1's exception would fail the execution. New example examples/features/workflows/python-retries/: fetch_unreliable -> summarize, module-global attempt counter (persists across in-process retries of one execution; fresh server per lane starts at 0). Default lane (workflow run -> Completed) is the assertion — Completed after a designed double-failure proves 2 retries occurred. Verified live: execution Completed. No product bug — the Python packaged retry path is solid.
…ped example on the gold path
Probes the Python trigger_rules -> Skipped state through the server gold path.
The Rust<->Python parity closed in T-0763 was only ever exercised by the
demo-stack fixture (demo-py-cron), never through compile -> reconcile -> execute.
New example examples/features/workflows/python-conditional/: gate sets
do_audit=False; audit is gated by context_value("do_audit","Equals",True) so the
rule never fires and the planner must Skip it. audit RAISES if it ever runs, so
Completed proves the skip was honored (broken trigger_rules would run it ->
raise -> Failed). record fans in on process + audit (a Skipped dep counts as
resolved) and asserts process actually ran, catching the opposite bug
(everything wrongly skipped). Default lane (workflow run -> Completed) is the
assertion. Verified live: execution Completed. No product bug — the Python
packaged trigger_rules/Skipped path is solid.
…he gold path The cron peer of python-triggers (poll). Cron and poll fire through DIFFERENT server subsystems — cron via the cron scheduler, poll via the runtime trigger registry — so this exercises a distinct code path. The Python cron surface (T-0688 added cron/timezone to @cloaca.trigger) was only ever run in the demo-stack fixture (demo-py-cron); this lifts it onto the features gold path. New example examples/features/workflows/python-cron/: @cloaca.trigger(on="heartbeat_workflow", cron="*/3 * * * * *") fires the workflow every 3 seconds. Registered with the _trigger_wait_steps lane (auto-fire, no `workflow run`). Verified live: the cron scheduler fired an execution on its own and it Completed. No product bug — the Python packaged cron path is solid.
…ant isolation bug (T-0901) The Python peer of the Rust multi-tenant examples (embedded-only), demonstrating the FULL per-tenant deployment model on the server gold path — and the probe that found a genuine isolation bug. New example examples/features/workflows/python-multi-tenant/ (workflow tenant_job) plus a _multi_tenant_steps lane that: - runs the package (already deployed in `public` by the harness) in tenant 1; - creates tenant `mtbeta`, stands up its OWN compiler (cloacina-compiler --tenant-schema mtbeta — the default compiler only claims the public/admin schema, by design), deploys the same archive, and runs it in tenant 2; - HARD-asserts execution-state isolation: neither tenant's `execution list` contains the other's run. Found T-0901: a third tenant `mtgamma` that never installed the package was still allowed to run tenant_job. execute_workflow resolves the workflow name against the process-shared in-memory Runtime (populated by public/mtbeta) with no check that the workflow exists in the CALLING tenant's own registry (mtgamma.workflow_packages has 0 rows for it). Execution STATE is isolated; workflow-DEFINITION visibility leaks across the tenant boundary. The lane surfaces this loudly as a KNOWN GAP rather than failing (flip to a hard assert once T-0901 lands). Filed CLOACI-T-0901 (P1) with root cause + proposed fix (a per-tenant existence gate before execute_async).
…e cross-tenant workflow leak A non-public tenant could execute a workflow it never installed, because execute_workflow resolved the workflow name against the process-shared in-memory Runtime (populated by every tenant's reconciler) with no check that the workflow exists in the CALLING tenant's registry. Execution state was already isolated (the run lands in the caller's schema); the leak was workflow-DEFINITION visibility across the tenant boundary. Surfaced by the python-multi-tenant gold-path example (I-0138). - cloacina/registry/workflow_registry: new workflow_exists(&name) — mirrors the is_workflow_paused / declared-params lookup (workflow_name or package_name) over this tenant's list_workflows(). - cloacina-server/routes/executions::execute_workflow: for tenant_id != "public", reject with 404 workflow_not_found when the workflow is absent from the tenant's own registry, BEFORE resolving against the runner. Definitive not-found fails CLOSED; a registry error fails open (a transient DB fault never wedges execution). public is left exempt (admin/global catalog; may serve inventory workflows not tracked as tenant packages) — documented in code. - python-multi-tenant lane: Isolation-2 (a tenant with no package cannot run the workflow) flipped from a logged known-gap to a HARD assertion. Verified live: public + mtbeta (installed) still run; mtgamma (never installed) now rejected. Regression guard: the python-multi-tenant CI lane exercises the negative end-to-end. Closes CLOACI-T-0901.
…failures The integration suite's fixture pre-build (`build_test_packages`) compiled two ship-form example packages (packaged-workflows, simple-packaged) with plain `cargo build`. Since those examples ship crates.io VERSION deps (`= "0.10"`, unpublished) and rely on the compiler's `--dev-workspace` patch to resolve them locally, plain cargo couldn't resolve them and the whole suite aborted before running any tests. - .angreal/test/integration.py: new `_build_shipform_fixture` + `_local_crate_patch_block` — build ship-form example fixtures with file-based dependency resolution by appending the same local `[patch.crates-io]` block `--dev-workspace` injects, then restoring the example's Cargo.toml/Cargo.lock so the shipped files stay pristine. Path-dep examples build as-is. Unblocking the suite surfaced 3 latent failures (masked because the suite never ran this far), now fixed: - database::connection::test_url_parsing_basic: URL is `localhost:15432` but the assertion still expected port 5432 (stale after the dev-stack 5432->15432 move). - fidius_validation::test_plugin_info_populated: expected interface version 4, but it is 5 since T-0895 (resolved_secrets on TaskExecutionRequest). - computation_graph::resilience_tests::test_state_accumulator_survives_restart: decoded the boundary as bincode `Vec<AlphaData>`, but a state-accumulator boundary is double-encoded — `state_window_frame` emits JSON, then `BoundarySender::send` wraps it with `types::serialize`. Added a `decode_state_window` helper that peels both layers, and replaced the fixed 300ms sleep + non-blocking drain with a poll-until-ready wait (up to 5s) so it no longer flakes under a loaded single-threaded run. Full suite now green: Rust integration + 29 Python pytest scenarios all pass; auth suite 49/0.
All three were latent on main and surfaced on this PR's run:
1. Discover Examples — angreal 2.8.8 auto-installs shell completion and prints a
banner to stdout, which corrupted `angreal demos matrix` captured into
$GITHUB_OUTPUT ("Invalid format '✅ Shell completion installed!'"). Set
ANGREAL_NO_AUTO_COMPLETION=1 at the examples-docs workflow level.
2. Rust Tutorial 06 (multi-tenancy) — the harness probed `"tutorial-06" in
example_dir`, but the real path is `06-multi-tenancy`, so it never matched;
DATABASE_URL was left unset and the tutorial fell back to :5432 while the dev
stack publishes :15432 (connection refused). Match the real dir name. Verified
locally: tutorial 06 now connects and completes.
3. Integration Tests (postgres, macOS) — the Rust test fixtures hardcode the
dev-stack port 15432, but the macOS lane started Homebrew postgres on the
default 5432, so every postgres test refused (155 passed / 154 failed in 4s).
Move the Homebrew cluster onto 15432 via ALTER SYSTEM + restart before
creating the cloacina role/db.
…uses :15432 Two more fixes after unmasking the example-execution jobs: 1. packaged-workflows example — its `analytics_workflow` declares a REQUIRED `source_id` param, but the default lane runs `workflow run` with no context, which the execute route rejects (I-0128 validation: "missing required param 'source_id'"). Added a `_context_run_steps` override supplying the param. Verified locally: gold path now Completes. 2. smart_postgres_reset — the direct psql reset omitted the port, defaulting to 5432. The dev stack (Docker on Ubuntu, Homebrew on macOS) publishes postgres on 15432, so the reset silently missed and fell through to the Docker path — which doesn't exist on macOS CI, breaking the postgres integration lane once the cluster was moved onto 15432. Connect on 15432.
…or CG on the gold path The stateful peer of python-packaged-graph (passthrough). Covers the state-accumulator kind (bounded rolling window), previously fixtures-only (demo-py-state), on the server gold path. New example examples/features/computation-graphs/python-stateful-graph/: @cloaca.state_accumulator(capacity=5) + @cloaca.boundary_schema(bid, ask) on tick_window; a tick_reactor (when_any) fires a 2-node graph (aggregate -> report) where the entry node receives the whole retained window (a list), not a single event. Registered with _graph_inject_steps. Verified live: a non-object event is rejected by the boundary schema, and an injected {bid,ask} tick fires the reactor (the window emits and the graph runs). No product bug — the Python packaged state-accumulator path is solid.
…CG on the gold path Covers the batch-accumulator kind — @cloaca.batch_accumulator(flush_interval, max_buffer_size) — which buffers events and flushes the whole buffer as one boundary when the buffer fills or the interval elapses. This kind had NO prior example or fixture (the least-exercised accumulator on the Python path). New example examples/features/computation-graphs/python-batch-graph/: @cloaca.batch_accumulator(flush_interval="1s", max_buffer_size=5) + @cloaca.boundary_schema(level=float) on event_batch; a batch_reactor (when_any) fires a 2-node graph (summarize -> report) where the entry node receives the flushed batch (a list). Registered with _graph_inject_steps. Verified live: a non-object event is rejected by the boundary schema, and injected events flush the buffer and fire the reactor. No product bug — the Python packaged batch-accumulator path is solid. (First run flaked on a cold server-startup 30s timeout — a known harness cold-start flake, unrelated to the example; passed on re-run.)
…back for unknown kinds Packaged graphs matched only `stream`/`state` in the accumulator-factory dispatch; `batch` (and `polling`) fell through the `_ =>` arm and silently became passthrough — a declared batch accumulator fired per-event instead of buffering/flushing (no warning). Confirmed live by python-batch-graph. - New JsonListBatchAccumulator (BatchAccumulator impl): buffers JSON socket events, emits the whole batch as a JSON array on flush — the boundary shape the FFI cache expects (bincode(Vec<u8>) of JSON), mirroring state_window_frame. - New BatchAccumulatorFactory: socket-driven, spawns batch_accumulator_runtime with flush_interval/max_buffer_size parsed from config (via the shared parse_duration_str); holds the flush sender so flush_rx stays open (timer/size drive flushes on the packaged path — no external reactor flusher). - New central accumulator_factory_for(type, config): all four packaged-reactor dispatch sites (Python runtime reg, Rust cdylib metadata, manifest overrides) route through it, so the kind set is consistent. Unknown types now WARN loudly and fall back to passthrough instead of silently degrading (T-0896 accept #2). python-batch-graph now exercises the REAL batch factory (was passthrough); verified end to end. State/passthrough unchanged (regression-checked live). Polling remains — it needs an FFI method to invoke the Python poll fn on an interval (follow-up).
added 3 commits
July 14, 2026 18:22
…n poll fn, no FFI) — T-0896 complete A packaged polling accumulator must call its poll function on an interval. On the Python path that fn is the registered Python callable, which lives in-process (the reconciler imports the module in the server) — so no FFI accumulator-invoke method is needed. The poll fn is driven exactly like a Python poll trigger: spawn_blocking + Python::with_gil, off the async executor. - cloacina/packaging_bridge: a PollClosure type + OnceLock builder hook (register_polling_accumulator_builder), a ClosurePollingAccumulator (PollingAccumulator impl that runs the injected closure under spawn_blocking), and a PollingAccumulatorFactory that resolves the closure by name at spawn and runs polling_accumulator_runtime on the configured interval. Wired into accumulator_factory_for's "polling" arm. - cloacina-python: resolve_poll_closure looks up the registered Python poll fn by name (ACCUMULATOR_REGISTRY persists callables — only tests drain it) and wraps it (call0 -> depythonize -> JSON bytes; None -> skip). Installed via register_authoring, so BOTH embeddings wire it (pip wheel + the server's synthetic ensure_cloaca_module) — the anti-drift single-source contract. New example examples/features/computation-graphs/python-polling-graph/: @cloaca.polling_accumulator(interval="2s") whose poll fn self-emits; a new _graph_autofire_steps lane asserts poll_reactor fires on its own (no inject). Verified live: reactor self-fired. Closes CLOACI-T-0896 (batch d2043bb + polling here). No plugin interface/ABI bump was needed.
Recurring 'No space left on device' on the example/tutorial/integration matrix: each job rebuilds cloacina + an example (~GB each) and runs the docker stack on a ~14GB GitHub runner. Delete the preinstalled Android SDK / .NET / GHC / CodeQL (~18GB, never used here) before checkout, and print df for future diagnosis. Linux-only in cloacina.yml (macOS runners have ample disk).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Packaged-first examples on the server gold path (I-0138). Adds Python peers (triggers, retries, conditional/trigger_rules, cron, multi-tenant) and re-authors stale examples to lean version deps. Surfaced and fixed a cross-tenant workflow-definition leak (T-0901) and unblocked the integration suite (file-based dep resolution for ship-form fixtures) + 3 latent test fixes. Full integration + auth suites green.