Skip to content

feat: URL-based stack bootstrapping and example Taskfile migration#15

Merged
kingwill101 merged 4 commits intomasterfrom
feature/dx-api-improvements
Feb 24, 2026
Merged

feat: URL-based stack bootstrapping and example Taskfile migration#15
kingwill101 merged 4 commits intomasterfrom
feature/dx-api-improvements

Conversation

@kingwill101
Copy link
Owner

@kingwill101 kingwill101 commented Feb 24, 2026

Summary

  • add URL-first bootstrapping helpers across StemApp, StemClient, and workflow app setup
  • harden StemStack.fromUrl adapter resolution with clearer unsupported-store errors and sqlite toggle guardrails
  • migrate example command runners from justfile to Taskfile.yml (plus docs/changelog updates)
  • refresh adapter docs/changelogs and add dashboard changelog entry for release alignment

Validation

  • dart test packages/stem/test/bootstrap
  • dart analyze packages/stem/lib/src/bootstrap packages/stem/test/bootstrap

Summary by CodeRabbit

  • New Features

    • URL-based initialization for client/app/workflow bootstrapping to simplify setup.
  • Documentation

    • Quick Start and examples updated to client-first flows and Taskfile-based automation.
    • Adapter contract docs expanded with capability flags, skip behavior, and recipes.
  • Bug Fixes

    • Clearer, actionable error messages for unsupported store/adapter configurations.
  • Chores

    • Standardized factory naming for in-memory result backend.
  • Tests

    • New and expanded bootstrap and adapter contract tests covering URL-based flows and failure cases.

@coderabbitai
Copy link

coderabbitai bot commented Feb 24, 2026

Warning

Rate limit exceeded

@kingwill101 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between f4a4cc0 and 0491f1c.

📒 Files selected for processing (36)
  • packages/dashboard/CHANGELOG.md
  • packages/stem/CHANGELOG.md
  • packages/stem/example/autoscaling_demo/README.md
  • packages/stem/example/canvas_patterns/Taskfile.yml
  • packages/stem/example/docs_snippets/lib/workflows.dart
  • packages/stem/example/encrypted_payload/Taskfile.yml
  • packages/stem/example/microservice/README.md
  • packages/stem/example/microservice/Taskfile.yml
  • packages/stem/example/monolith_service/Taskfile.yml
  • packages/stem/example/postgres_tls/Taskfile.yml
  • packages/stem/example/progress_heartbeat/README.md
  • packages/stem/example/progress_heartbeat/Taskfile.yml
  • packages/stem/example/rate_limit_delay/Taskfile.yml
  • packages/stem/example/security/ed25519_tls/Taskfile.yml
  • packages/stem/example/security/hmac/Taskfile.yml
  • packages/stem/example/security/hmac_tls/README.md
  • packages/stem/example/security/hmac_tls/Taskfile.yml
  • packages/stem/example/signing_key_rotation/Taskfile.yml
  • packages/stem/example/task_context_mixed/README.md
  • packages/stem/example/task_context_mixed/Taskfile.yml
  • packages/stem/example/unique_tasks/Taskfile.yml
  • packages/stem/lib/src/bootstrap/stem_app.dart
  • packages/stem/lib/src/bootstrap/stem_stack.dart
  • packages/stem/lib/src/bootstrap/workflow_app.dart
  • packages/stem/test/bootstrap/stem_app_test.dart
  • packages/stem/test/bootstrap/stem_client_test.dart
  • packages/stem/test/bootstrap/stem_stack_test.dart
  • packages/stem/test/bootstrap/test_store_adapter.dart
  • packages/stem_adapter_tests/CHANGELOG.md
  • packages/stem_builder/CHANGELOG.md
  • packages/stem_cli/CHANGELOG.md
  • packages/stem_cli/test/unit/cli/cloud_config_test.dart
  • packages/stem_memory/CHANGELOG.md
  • packages/stem_postgres/CHANGELOG.md
  • packages/stem_redis/CHANGELOG.md
  • packages/stem_sqlite/CHANGELOG.md
📝 Walkthrough

Walkthrough

The PR adds URL-based bootstrap factories (fromUrl) for StemApp/StemClient/StemWorkflowApp, enhances StemStack adapter/error handling, renames memory result backend exports, adds tests for the new bootstrap flows, and migrates ~30 example projects from Justfile to Taskfile with supporting Taskfile orchestration and docs updates.

Changes

Cohort / File(s) Summary
Bootstrap API Additions
packages/stem/lib/src/bootstrap/stem_app.dart, packages/stem/lib/src/bootstrap/stem_client.dart, packages/stem/lib/src/bootstrap/workflow_app.dart
Add public fromUrl(...) factory methods to create StemApp/StemClient/StemWorkflowApp from a single URL with adapter wiring, auto-provisioning of lock/revoke stores, and lifecycle disposal hooks.
Stack & Adapter Guards
packages/stem/lib/src/bootstrap/stem_stack.dart
Add runtime validation and fail-fast errors for unsupported sqlite-backed defaults; improve error messages with toggle hints and adapter capability guidance.
Tests for Bootstrapping
packages/stem/test/bootstrap/...
stem_app_test.dart, stem_client_test.dart, stem_stack_test.dart
New/expanded tests validating fromUrl bootstrap, adapter-based factory resolution, auto-provisioning/disposal of stores, and precise error messages for missing/incompatible stores.
Examples: fromUrl Migration
packages/stem/example/.../docs_snippets/lib/*.dart, stack_autowire.dart, workflows/*.dart
Update example code to use fromUrl constructors (StemApp/Client/WorkflowApp.fromUrl) and adapter-driven wiring; remove prior explicit broker/backend/storeFactory usage.
Examples: Taskfile Migration
packages/stem/example/**/Taskfile.yml (30+), packages/stem/example/**/justfile (deletions)
Replace Justfile automation with Taskfile.yml across many examples; add new Taskfiles implementing deps/build/run/compose tasks and delete legacy Justfiles.
Example Aggregation & Includes
packages/stem/Taskfile.yml, packages/stem/example/Taskfile.yml
Add includes and aggregator Taskfiles to orchestrate example builds and runs centrally.
Docs & READMEs
README.md, packages/stem/README.md, packages/stem_memory/README.md, packages/stem_adapter_tests/README.md, packages/*/CHANGELOG.md
Document fromUrl usage, Taskfile migration, capability flags for adapter tests, and changelog/readme updates (including stem_memory usage and renamed factories).
Adapter Factory/Export Renames
packages/stem_memory/lib/src/memory_factories.dart, packages/stem_memory/lib/stem_memory.dart, packages/stem_postgres/lib/src/workflow/postgres_factories.dart, packages/stem_postgres/lib/src/stack/postgres_adapter.dart
Rename memoryBackendFactorymemoryResultBackendFactory, update exports; change postgresResultBackendFactory signature to take a positional URI and update callsites.
New Example Docker/Compose Files
packages/stem/example/postgres_tls/docker-compose.yml
Add docker-compose for Postgres TLS + Redis used by Taskfile-managed examples.
Adapter Contract Tests & Docs
packages/stem_adapter_tests/README.md, CHANGELOG.md
Expand adapter test README with capability flags, skip semantics, and recipes for adapter configurations.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Caller
    participant App as StemApp.fromUrl()
    participant Stack as StemStack.fromUrl()
    participant Adapter as AdapterRegistry
    participant Factory as StoreFactory
    participant Store as Broker/Backend/Lock/Revoke

    Client->>App: call fromUrl(url, adapters, ...)
    activate App
    App->>Stack: StemStack.fromUrl(url, adapters, overrides)
    activate Stack
    Stack->>Adapter: resolve adapter for scheme
    Adapter-->>Stack: provide broker/backend/lock/revoke factories
    Stack->>Factory: invoke selected factory(...) 
    Factory-->>Store: return store instance
    alt uniqueTasks enabled
        Stack->>Factory: create lock store
        Factory-->>Store: lock store
    end
    alt requireRevokeStore true
        Stack->>Factory: create revoke store
        Factory-->>Store: revoke store
    end
    Stack-->>App: return resolved stores/adapters
    App->>Store: initialize app with stores
    deactivate Stack
    App-->>Client: StemApp (ready)
    deactivate App
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through code and found a key,

From URLs the stacks now spring free.
Just stepped aside for Taskfile cheer,
Adapters hum and tests appear —
A carrot-toast for bootstrap glee! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: URL-based stack bootstrapping and migration of example runners from justfile to Taskfile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/dx-api-improvements

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fa9cce857

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 31

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/stem/example/progress_heartbeat/README.md (1)

35-41: ⚠️ Potential issue | 🟡 Minor

Add blank lines around the fenced block.
markdownlint MD031 indicates the fence isn’t surrounded by blank lines.

✍️ Minimal formatting fix
-```bash
+ 
+```bash
 export STEM_BROKER_URL=redis://localhost:6379/0
 export STEM_RESULT_BACKEND_URL=redis://localhost:6379/1

 task build-cli
 task stem observe workers
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @packages/stem/example/progress_heartbeat/README.md around lines 35 - 41, The
fenced bash code block (the triple backticks starting with "bash") in README.md is not surrounded by blank lines; add a single blank line before the opening bash fence and a single blank line after the closing ``` fence so the
block is separated from surrounding text, ensuring markdownlint MD031 is
satisfied.


</details>

</blockquote></details>
<details>
<summary>packages/stem_memory/lib/src/memory_factories.dart (1)</summary><blockquote>

`23-39`: _🧹 Nitpick_ | _🔵 Trivial_

**Consider a deprecated alias to ease migration.**

Renaming the public factory is a breaking change. A deprecated wrapper can preserve compatibility while guiding users to the new name.  


<details>
<summary>♻️ Suggested compatibility alias</summary>

```diff
+@Deprecated('Use memoryResultBackendFactory instead.')
+StemBackendFactory memoryBackendFactory({
+  Duration defaultTtl = const Duration(days: 1),
+  Duration groupDefaultTtl = const Duration(days: 1),
+  Duration heartbeatTtl = const Duration(minutes: 1),
+}) {
+  return memoryResultBackendFactory(
+    defaultTtl: defaultTtl,
+    groupDefaultTtl: groupDefaultTtl,
+    heartbeatTtl: heartbeatTtl,
+  );
+}
+
 /// Creates a [StemBackendFactory] backed by [InMemoryResultBackend].
 StemBackendFactory memoryResultBackendFactory({
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@packages/stem_memory/lib/src/memory_factories.dart` around lines 23 - 39, Add
a deprecated compatibility alias for the renamed factory so existing callers
keep working: create a top-level function with the old public name (e.g., the
previous factory identifier) annotated with `@Deprecated` and forwarding to
memoryResultBackendFactory(...) (passing through defaultTtl, groupDefaultTtl,
heartbeatTtl), and include a deprecation message pointing users to
memoryResultBackendFactory; update any doc comment to mention the alias is
deprecated and will be removed in a future release.
```

</details>

</blockquote></details>
<details>
<summary>packages/stem/test/bootstrap/stem_stack_test.dart (1)</summary><blockquote>

`277-323`: _🧹 Nitpick_ | _🔵 Trivial_

**`_TestAdapter.name` is hardcoded to `'test'` regardless of the `scheme` argument.**

In multi-adapter tests (e.g. `'honors overrides for specific stores'`), two adapters with different schemes (`'foo'`, `'bar'`) both report `name == 'test'`. If `StemStack.fromUrl` ever uses `name` for adapter deduplication, conflict detection, or diagnostic messages, this silently produces misleading output.

<details>
<summary>♻️ Proposed fix</summary>

```diff
 class _TestAdapter implements StemStoreAdapter {
   _TestAdapter({
     required this.scheme,
     ...
   });

   final String scheme;
   ...

   `@override`
-  String get name => 'test';
+  String get name => scheme;
   ...
 }
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/test/bootstrap/stem_stack_test.dart` around lines 277 - 323,
The _TestAdapter.name getter is hardcoded to 'test' which hides the adapter's
actual scheme; change the name implementation in _TestAdapter to return a value
derived from the instance's scheme (e.g., return scheme or 'test-$scheme') so
each adapter created with different scheme values (constructor field scheme)
exposes a unique name; update the getter for name in the _TestAdapter class
(symbol: _TestAdapter.name) to use the instance field scheme instead of the
literal 'test'.
```

</details>

</blockquote></details>
<details>
<summary>packages/stem/example/docs_snippets/lib/workflows.dart (1)</summary><blockquote>

`234-253`: _🧹 Nitpick_ | _🔵 Trivial_

**`main()` still uses `StemWorkflowApp.inMemory()` — inconsistent with the rest of the file's `fromUrl` migration.**

Every other call site in this file has been migrated to `fromUrl`-based constructors, but `main()` at line 242 still uses the `inMemory()` factory. For documentation consistency, update it to use `StemWorkflowApp.fromUrl('memory://', flows: [demoFlow])`.

<details>
<summary>♻️ Proposed update</summary>

```diff
-  final app = await StemWorkflowApp.inMemory(flows: [demoFlow]);
+  final app = await StemWorkflowApp.fromUrl('memory://', flows: [demoFlow]);
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/example/docs_snippets/lib/workflows.dart` around lines 234 -
253, The main() function still constructs the app with
StemWorkflowApp.inMemory(); replace that call with the fromUrl factory so it
matches other examples — use StemWorkflowApp.fromUrl('memory://', flows:
[demoFlow]) when creating app in main(), keep all other logic (start,
startWorkflow, waitForCompletion, close) unchanged and ensure the variable name
(app) and awaited creation remain the same.
```

</details>

</blockquote></details>
<details>
<summary>packages/stem/example/stack_autowire.dart (1)</summary><blockquote>

`26-55`: _⚠️ Potential issue_ | _🟡 Minor_

**Remove the const concern; clarify the dual-stack pattern as potentially wasteful.**

1. **`const redisAdapters`** is not an issue — `StemRedisAdapter` has a valid `const` constructor.

2. **Dual-stack pattern** (lines 27–55): `StemStack.fromUrl` and `StemApp.fromUrl` both target the same URL. `StemApp.fromUrl` creates its own internal `StemStack` regardless of the external one. The stores extracted from the first stack (`scheduleStore`/`lockStore`) are then unused since `StemApp.fromUrl` with `uniqueTasks: true` and `requireRevokeStore: true` creates fresh stores from its internal stack. To reuse stores, pass them via `StemWorkerConfig` to `StemApp.fromUrl`, or remove the redundant manual stack creation.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/example/stack_autowire.dart` around lines 26 - 55, The example
unnecessarily creates a separate StemStack via StemStack.fromUrl and extracts
scheduleFactory/lockFactory/scheduleStore/lockStore which are never used because
StemApp.fromUrl creates its own internal StemStack when called with uniqueTasks
and requireRevokeStore; either remove the redundant StemStack.fromUrl block and
related scheduleFactory/lockFactory/scheduleStore/lockStore code, or instead
pass the created stores into StemApp.fromUrl using a StemWorkerConfig so the app
reuses the existing stores; note that const redisAdapters is fine because
StemRedisAdapter has a const ctor.
```

</details>

</blockquote></details>

</blockquote></details>
♻️ Duplicate comments (3)
packages/stem/example/ops_health_suite/Taskfile.yml (1)

30-60: Same binary glob concern as in progress_heartbeat Taskfile.
Consider resolving a single binary before execution to avoid ambiguous matches.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/example/ops_health_suite/Taskfile.yml` around lines 30 - 60,
The run-worker and run-producer tasks use a bare glob
("$root/build/worker/bundle/bin/"* and "$root/build/producer/bundle/bin/"*)
which can match multiple files or none; change each task to resolve exactly one
binary before exec (e.g., expand the glob into an array, validate there is
exactly one match, error if zero or >1, then exec that single path) and update
the run-worker and run-producer command blocks to use that resolved single
binary path instead of the raw glob.
packages/stem/example/dlq_sandbox/Taskfile.yml (1)

30-60: Same binary glob concern as in progress_heartbeat Taskfile.
Consider resolving a single binary before execution to avoid ambiguous matches.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/example/dlq_sandbox/Taskfile.yml` around lines 30 - 60, The
run-worker and run-producer Taskfile commands use a glob
("$root/build/worker/bundle/bin/"* and "$root/build/producer/bundle/bin/"*)
which can match multiple files; change each task to resolve the glob before
execution, validate that exactly one binary was found (or fail with a clear
error), and then exec that single path (e.g., collect matches into an array,
check length, and use the first/only entry) so the tasks deterministically run a
single binary instead of an ambiguous glob.
packages/stem/example/signals_demo/Taskfile.yml (1)

30-58: Same binary glob concern as in progress_heartbeat Taskfile.
Consider resolving a single binary before execution to avoid ambiguous matches.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/example/signals_demo/Taskfile.yml` around lines 30 - 58, The
run-worker and run-producer tasks currently execute a glob
("$root/build/worker/bundle/bin/"* and "$root/build/producer/bundle/bin/"*)
which can match multiple files; change each task to resolve the glob into a
single binary before exec: expand the glob into an array/variable (e.g., bins=(
"$root/build/.../bin/"* )), validate that exactly one match exists (or pick a
deterministic one) and fail with a clear error if ambiguous, then exec that
single path (replace the direct glob invocation in both run-worker and
run-producer).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/dashboard/CHANGELOG.md`:
- Around line 1-3: Add a top-level H1 heading above the existing "## Unreleased"
entry to satisfy markdownlint MD041; for example insert a single-line "#
Changelog" (or "# stem_dashboard Changelog") before the "## Unreleased" heading
so the file begins with an H1 and retains the existing "## Unreleased" section
and package note (`stem_dashboard`).

In `@packages/stem_adapter_tests/CHANGELOG.md`:
- Line 1: The top-level heading in CHANGELOG.md is currently an H2 ("##
Unreleased") which violates MD041; change that first line to an H1 by replacing
"## Unreleased" with "# Unreleased" so the file starts with a top-level H1 (keep
the rest of the file unchanged).

In `@packages/stem_cli/CHANGELOG.md`:
- Around line 1-3: The changelog currently starts with an H2 which triggers
markdownlint MD041; add a top-level H1 heading (for example "Changelog" or
"CHANGELOG") as the very first line of packages/stem_cli/CHANGELOG.md so the
existing "## Unreleased" becomes a valid secondary heading and MD041 is
resolved.

In `@packages/stem_memory/CHANGELOG.md`:
- Around line 1-6: Add a top-level H1 heading above the existing "## Unreleased"
section in the changelog so the file begins with a single H1 (for example "#
Changelog") to satisfy markdownlint MD041; edit the current "Unreleased" section
header (the "## Unreleased" line) by inserting the H1 before it and keep the
existing bullet entries and renamed notes intact.

In `@packages/stem_sqlite/CHANGELOG.md`:
- Line 1: Add a top-level H1 heading above the existing "## Unreleased" heading
to satisfy markdownlint MD041; edit CHANGELOG.md and insert a line such as "#
Changelog" (or "# Stem SQLite Changelog") immediately before the "## Unreleased"
line so the file begins with an H1 instead of an H2.

In `@packages/stem/example/autoscaling_demo/README.md`:
- Around line 23-29: The README mentions a non-existent task "task tmux"; either
remove that line from README.md or add a corresponding tmux task to the
project's Taskfile. If you choose to implement it, create a Taskfile entry named
"tmux" that launches the demo in a tmux session (or calls existing tasks like
"run-worker" and "run-producer" inside tmux), ensuring the task name is exactly
"tmux" so the README command works; otherwise delete the `task tmux` reference
from README.md and keep the documented alternatives ("task run-worker" / "task
run-producer").

In `@packages/stem/example/canvas_patterns/Taskfile.yml`:
- Around line 12-49: The three tasks run-chain, run-chord, and run-group
duplicate the same shell block; create a parameterised internal task (e.g.,
run-canvas-demo with a parameter like example_path) that contains the shared
bash script and accepts the final dart file as an argument, then make run-chain,
run-chord, and run-group call that internal task with example_path set to
"example/canvas_patterns/chain_example.dart",
"example/canvas_patterns/chord_example.dart", and
"example/canvas_patterns/group_example.dart" respectively; also fix the .env
resolution inside the shared script to prefer the Taskfile root path (use
"$root/$env_file" first) to avoid CWD-relative ambiguity before falling back to
a top-level .env.

In `@packages/stem/example/docs_snippets/lib/workflows.dart`:
- Around line 11-22: The docs snippet for StemWorkflowApp.fromUrl hardcodes DB
credentials in StemStoreOverrides.workflow
('postgresql://postgres:postgres@127.0.0.1:65432/stem'); update it to remove
literal credentials by using a placeholder URL (e.g.,
'postgresql://<user>:<password>@127.0.0.1:65432/stem') or construct the workflow
URL from environment variables before passing to StemStoreOverrides so no
username/password appear inline in the example.

In `@packages/stem/example/encrypted_payload/Taskfile.yml`:
- Around line 89-165: The three tasks run:worker, run:enqueuer and
run:container-client duplicate the same env-loading preamble and export lines
(env_file loading, REDIS_PORT, STEM_BROKER_URL, STEM_RESULT_BACKEND_URL,
STEM_DEFAULT_QUEUE, PAYLOAD_SECRET); extract that shared logic into a single
reusable Taskfile task (e.g., dotenv or env:load) or a sourced shell snippet and
make each of the three tasks invoke that precondition before running their
distinct binary paths, updating run:worker, run:enqueuer and
run:container-client to remove the duplicated block and depend on or source the
centralized env setup.
- Line 111: The example Taskfile.yml currently hardcodes a fallback
PAYLOAD_SECRET (e.g. in the export PAYLOAD_SECRET line used by the run:worker
path) which allows accidental use of a committed key; remove the hardcoded
default (don’t use "${PAYLOAD_SECRET:-...}") from all occurrences (the three
export PAYLOAD_SECRET lines) and add a fail-fast guard in the run:worker worker
startup logic that checks PAYLOAD_SECRET and prints a clear error + non-zero
exit if unset (so users must run the init task to generate a key); reference
PAYLOAD_SECRET and the run:worker task when making the change.

In `@packages/stem/example/microservice/README.md`:
- Around line 41-42: Add a blank line after the closing fenced code block (the
triple backticks) so the fence is followed by an empty line before the next
paragraph that starts with "Replace the placeholder secret in `.env`..."; update
the README.md fenced-block to ensure there's a single blank line between the
closing ``` and the following paragraph to satisfy MD031.

In `@packages/stem/example/microservice/Taskfile.yml`:
- Around line 263-266: The clean task currently deletes the repo-root dashboard
build via the path "{{.TASKFILE_DIR}}/../../../dashboard/build"; update the
Taskfile's clean task to avoid removing files outside the example tree by either
(A) removing that dashboard path from the clean task so it only deletes
"{{.TASKFILE_DIR}}/worker/build", "enqueuer/build" and "beat/build", or (B)
extract the dashboard deletion into a separate opt-in task (e.g.,
clean:dashboard) that explicitly targets
"{{.TASKFILE_DIR}}/../../../dashboard/build" so users must run it intentionally;
modify the task named clean (and add clean:dashboard if choosing option B)
accordingly.
- Around line 159-161: Update the Taskfile.yml "build" task description to
clarify that it compiles worker, enqueuer, and beat binaries but intentionally
excludes the dashboard (which is built in a separate package), or alternatively
add build:dashboard as an optional dependency; reference the "build" task and
the "build:dashboard" target so reviewers can decide whether to modify the
description or include the optional dep.

In `@packages/stem/example/monolith_service/Taskfile.yml`:
- Around line 13-21: The env lookup currently sets env_file to ".env" which
makes the first check [[ -f "$env_file" ]] use the caller's CWD; change the
default to be rooted at the Taskfile directory so the lookup is unambiguous by
setting env_file="${ENV_FILE:-${root}/.env}" (or otherwise constructing
"$root/.env" when ENV_FILE is empty) and then source that absolute path (keep
the existing fallback logic only if you want to still support an explicit
ENV_FILE pointing elsewhere); update the references to env_file in the if/elif
so they check the absolute $env_file and $root/$env_file cases consistently.

In `@packages/stem/example/postgres_tls/Taskfile.yml`:
- Around line 70-74: The POSTGRES credentials are hardcoded in the default
STEM_RESULT_BACKEND_URL; introduce and use environment variables for the DB
username and password (e.g., POSTGRES_USER and POSTGRES_PASSWORD) and update the
STEM_RESULT_BACKEND_URL default to interpolate those variables instead of
"postgres:postgres"; do the same change for the duplicate block around lines
96-100 and ensure STEM_RESULT_BACKEND_URL falls back to sensible, non-secret
defaults only for local demo use (or empty) so credentials are not embedded in
the repo.

In `@packages/stem/example/progress_heartbeat/README.md`:
- Around line 45-56: The README references non-existent Taskfile targets
"build-cli" and "tmux"; update the example to use the actual Taskfile targets by
replacing "build-cli" with the correct build tasks (either the aggregate "build"
or the specific "build-worker" and "build-producer") and remove or replace
"tmux" with the real way to run concurrent processes (e.g., run separate
terminals with "task run-worker" and "task run-producer"); ensure the retained
task names match "deps-up", "build" (or "build-worker"/"build-producer"),
"run-worker", and "run-producer" so the instructions align with the Taskfile.

In `@packages/stem/example/progress_heartbeat/Taskfile.yml`:
- Around line 30-60: The tasks run-worker and run-producer use an ambiguous glob
("$root/build/.../bin/"*) which can expand to zero or many files; change each
task to explicitly resolve the glob into a single binary variable (e.g., collect
matches into an array, enable nullglob so empty expands to zero entries), verify
the array length is exactly one and fail with a clear error if not, then exec
that single path (use the variable instead of the raw glob) so the script errors
deterministically when no or multiple binaries are found.

In `@packages/stem/example/rate_limit_delay/Taskfile.yml`:
- Around line 34-45: The glob "$root/build/worker/bundle/bin/"* is fragile
because if the bundle directory contains multiple files the shell will treat
extras as arguments; update the Taskfile.yml worker and producer steps to either
call the explicit binary name produced by your build (replace the glob with the
actual executable filename in "$root/build/worker/bundle/bin/") or robustly
select a single executable (e.g., use a find invocation that filters for a
single -type f -executable and -exec it) so only one file is executed and extras
are not passed as arguments.

In `@packages/stem/example/security/ed25519_tls/Taskfile.yml`:
- Around line 30-33: The sed in-place edit uses the non-portable flag pattern
sed -i -E which fails on BSD/macOS; update the code that builds escaped_value
and edits env_file (the lines referencing escaped_value, env_file, key, value
and the sed -i -E invocation) to use a portable in-place invocation (e.g. sed
-i'' -E ...) or otherwise supply an explicit empty backup suffix so the same
command works on both GNU and BSD sed; make this change consistently across the
example Taskfiles mentioned (signing_key_rotation, security/hmac,
security/hmac_tls, microservice, encrypted_payload).

In `@packages/stem/example/security/hmac_tls/README.md`:
- Around line 9-11: Update the incorrect directory path in the README commands
from "examples/" to "example/": find the two command snippets that say "cd
examples/security/hmac_tls" and "task tls:certs" and change the cd invocation to
"cd example/security/hmac_tls" (leave the task invocation alone), and repeat the
same fix for the second occurrence around lines 16-18 so all example path
references use "example/" not "examples/".

In `@packages/stem/example/security/hmac_tls/Taskfile.yml`:
- Around line 52-56: compose-up currently only runs tls:certs and misses
rotating HMAC keys; update the compose-up task to also invoke keys:rotate before
bringing up containers so both TLS certs and signing keys are ensured fresh,
i.e., add keys:rotate as a prerequisite alongside tls:certs for the compose-up
task (aligning with init and init:hmac-tls behavior used elsewhere).

In `@packages/stem/example/security/hmac/Taskfile.yml`:
- Around line 17-24: The sed -i usage in the STEM_SIGNING_KEYS /
STEM_SIGNING_ACTIVE_KEY update blocks is not portable to BSD/macOS; modify the
Taskfile logic that edits env_file (the code touching STEM_SIGNING_KEYS and
STEM_SIGNING_ACTIVE_KEY and using escaped_secret/secret) to use a portable
approach such as using sed -i.bak -E (and remove the backup after) or add a
runtime detection branch (check sed --version to choose between sed -i -E and
sed -i '' -E) or replace with perl -pi -e; ensure the replacement commands
update STEM_SIGNING_KEYS and STEM_SIGNING_ACTIVE_KEY exactly as before and that
any temporary backup file is cleaned up.

In `@packages/stem/example/signing_key_rotation/Taskfile.yml`:
- Around line 25-37: The sed in-place edits using `sed -i -E` are not portable
to macOS/BSD; update the places that modify STEM_SIGNING_KEYS and
STEM_SIGNING_ACTIVE_KEY (and other similar occurrences like the other
signing/hmac/encrypted_payload Taskfile.yml entries) to detect GNU vs BSD sed
and call sed with the appropriate -i arg (either `-i -E` for GNU or `-i '' -E`
for BSD/macOS) before running the substitution that uses ${escaped_keys} and
${active}; apply the same pattern to each of the ~10 instances across the
Taskfile.yml files so all sed in-place edits are portable.

In `@packages/stem/example/task_context_mixed/README.md`:
- Line 74: The README references a non-existent task "task tmux" which will fail
because the Taskfile.yml only defines build-worker, build-enqueue, build,
run-worker, run-enqueue, run-fail, run-overwrite, run, and clean; either add a
"tmux" task entry to the Taskfile.yml that implements the intended behavior
(e.g., starts the worker/enqueue targets in tmux) or remove/replace the "task
tmux" line in the README with one of the actual tasks (for example "task run" or
a new "tmux" task name you add) so the example matches the Taskfile.yml.

In `@packages/stem/example/task_context_mixed/Taskfile.yml`:
- Around line 31-32: The shell glob "$root/build/worker/bundle/bin/"* is unsafe
because it may expand to multiple files; replace usages (the glob pattern in
Taskfile tasks like run-enqueue, run-fail, run-overwrite and the Taskfiles for
encrypted_payload and microservice) with an explicit binary name when stable, or
else discover a single executable reliably (e.g., use a find invocation
restricted to that directory such as find "$root/build/worker/bundle/bin"
-maxdepth 1 -type f -executable and select the intended file) and execute only
that path instead of the bare glob.
- Around line 39-91: The three Taskfile targets run-enqueue, run-fail, and
run-overwrite duplicate the same env-loading and binary-detection logic;
refactor by extracting the shared setup into a single reusable fragment or
parameterize the differing CLI flag via a variable (e.g., CLI_ARGS) and have one
target (or a helper include) reuse the common block and append CLI_ARGS (empty,
"--fail", "--overwrite") as needed so the logic in
run-enqueue/run-fail/run-overwrite is replaced with a single DRY invocation that
references the shared helper or variable.

In `@packages/stem/example/unique_tasks/Taskfile.yml`:
- Around line 12-21: The Taskfile's env-file lookup currently uses
env_file="${ENV_FILE:-.env}" and checks the CWD first, which can load an
ancestor .env when task is run elsewhere; update the conditional so it prefers
the repository-relative path by testing "$root/$env_file" before "$env_file"
(i.e., check if [[ -f "$root/$env_file" ]] then source that, elif [[ -f
"$env_file" ]] then source that), leaving the env_file, root and stem_root
variables and the rest of the script (including cd "$stem_root" and dart run
unique_task_example.dart) unchanged.

In `@packages/stem/lib/src/bootstrap/stem_app.dart`:
- Around line 298-302: The positional call app._disposers.insertAll(1,
autoDisposers) is fragile because it relies on create() always producing a
specific ordering; change the API so disposers are placed explicitly: add a new
parameter (e.g., preBackendDisposers) to create() or convert app._disposers into
named phases (e.g., app._preBackendDisposers, app._backendDisposers,
app._postBackendDisposers) and append autoDisposers to the appropriate named
phase instead of using insertAll(1,...); update all call sites of create() and
any code that iterates _disposers to respect the new phased structure and ensure
shutdown order is explicit via the new symbol names rather than positional
indices.

In `@packages/stem/lib/src/bootstrap/workflow_app.dart`:
- Around line 338-407: The code double-resolves adapters by calling
StemStack.fromUrl and StemApp.fromUrl with the same url/adapters/overrides;
change the flow so only one stack is built and reused: either (A) add an
overload/parameter to StemApp.fromUrl to accept a pre-built StemStack (or
StemStore factory) and call StemApp.fromUrl(stack: stack, ...) from fromUrl, or
(B) have StemApp.fromUrl return or expose its built StemStack (e.g., a getter or
field) and use that stack.workflowStore for the storeFactory instead of calling
StemStack.fromUrl here; also remove or avoid forwarding
encoderRegistry/resultEncoder/argsEncoder/additionalEncoders redundantly to
create when passing an existing stemApp (ensure create only receives encoder
params when it will construct a new StemApp). Reference:
StemWorkflowApp.fromUrl, StemStack.fromUrl, StemApp.fromUrl, create.

In `@packages/stem/test/bootstrap/stem_client_test.dart`:
- Around line 64-98: Extract the duplicated test adapter implementations into a
single shared test helper: create a common test class (e.g., TestStoreAdapter)
that implements StemStoreAdapter and exposes constructor parameters for scheme,
broker (StemBrokerFactory?), and backend (StemBackendFactory?), and implements
the same methods used in both _ClientAdapter and _BootstrapAdapter; then replace
both _ClientAdapter and _BootstrapAdapter usages with the new TestStoreAdapter
to centralize scheme-based matching and optional factory fields so future
changes to StemStoreAdapter only need one update.

In `@packages/stem/test/bootstrap/stem_stack_test.dart`:
- Around line 224-273: Add a symmetric sqlite guardrail test for workflows by
following the existing pattern: add a test that calls
StemStack.fromUrl('sqlite:///tmp/stem.db', workflows: true) and expects a
StateError whose message contains both "do not provide a workflow store" and
"Disable `workflows`"; mirror the structure and matchers used in the
scheduling/uniqueTasks/requireRevokeStore tests so it fits alongside them in
stem_stack_test.dart.

---

Outside diff comments:
In `@packages/stem_memory/lib/src/memory_factories.dart`:
- Around line 23-39: Add a deprecated compatibility alias for the renamed
factory so existing callers keep working: create a top-level function with the
old public name (e.g., the previous factory identifier) annotated with
`@Deprecated` and forwarding to memoryResultBackendFactory(...) (passing through
defaultTtl, groupDefaultTtl, heartbeatTtl), and include a deprecation message
pointing users to memoryResultBackendFactory; update any doc comment to mention
the alias is deprecated and will be removed in a future release.

In `@packages/stem/example/docs_snippets/lib/workflows.dart`:
- Around line 234-253: The main() function still constructs the app with
StemWorkflowApp.inMemory(); replace that call with the fromUrl factory so it
matches other examples — use StemWorkflowApp.fromUrl('memory://', flows:
[demoFlow]) when creating app in main(), keep all other logic (start,
startWorkflow, waitForCompletion, close) unchanged and ensure the variable name
(app) and awaited creation remain the same.

In `@packages/stem/example/progress_heartbeat/README.md`:
- Around line 35-41: The fenced bash code block (the triple backticks starting
with "```bash") in README.md is not surrounded by blank lines; add a single
blank line before the opening ```bash fence and a single blank line after the
closing ``` fence so the block is separated from surrounding text, ensuring
markdownlint MD031 is satisfied.

In `@packages/stem/example/stack_autowire.dart`:
- Around line 26-55: The example unnecessarily creates a separate StemStack via
StemStack.fromUrl and extracts
scheduleFactory/lockFactory/scheduleStore/lockStore which are never used because
StemApp.fromUrl creates its own internal StemStack when called with uniqueTasks
and requireRevokeStore; either remove the redundant StemStack.fromUrl block and
related scheduleFactory/lockFactory/scheduleStore/lockStore code, or instead
pass the created stores into StemApp.fromUrl using a StemWorkerConfig so the app
reuses the existing stores; note that const redisAdapters is fine because
StemRedisAdapter has a const ctor.

In `@packages/stem/test/bootstrap/stem_stack_test.dart`:
- Around line 277-323: The _TestAdapter.name getter is hardcoded to 'test' which
hides the adapter's actual scheme; change the name implementation in
_TestAdapter to return a value derived from the instance's scheme (e.g., return
scheme or 'test-$scheme') so each adapter created with different scheme values
(constructor field scheme) exposes a unique name; update the getter for name in
the _TestAdapter class (symbol: _TestAdapter.name) to use the instance field
scheme instead of the literal 'test'.

---

Duplicate comments:
In `@packages/stem/example/dlq_sandbox/Taskfile.yml`:
- Around line 30-60: The run-worker and run-producer Taskfile commands use a
glob ("$root/build/worker/bundle/bin/"* and "$root/build/producer/bundle/bin/"*)
which can match multiple files; change each task to resolve the glob before
execution, validate that exactly one binary was found (or fail with a clear
error), and then exec that single path (e.g., collect matches into an array,
check length, and use the first/only entry) so the tasks deterministically run a
single binary instead of an ambiguous glob.

In `@packages/stem/example/ops_health_suite/Taskfile.yml`:
- Around line 30-60: The run-worker and run-producer tasks use a bare glob
("$root/build/worker/bundle/bin/"* and "$root/build/producer/bundle/bin/"*)
which can match multiple files or none; change each task to resolve exactly one
binary before exec (e.g., expand the glob into an array, validate there is
exactly one match, error if zero or >1, then exec that single path) and update
the run-worker and run-producer command blocks to use that resolved single
binary path instead of the raw glob.

In `@packages/stem/example/signals_demo/Taskfile.yml`:
- Around line 30-58: The run-worker and run-producer tasks currently execute a
glob ("$root/build/worker/bundle/bin/"* and "$root/build/producer/bundle/bin/"*)
which can match multiple files; change each task to resolve the glob into a
single binary before exec: expand the glob into an array/variable (e.g., bins=(
"$root/build/.../bin/"* )), validate that exactly one match exists (or pick a
deterministic one) and fail with a clear error if ambiguous, then exec that
single path (replace the direct glob invocation in both run-worker and
run-producer).

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b33068 and 4fa9cce.

📒 Files selected for processing (92)
  • README.md
  • Taskfile.yml
  • packages/dashboard/CHANGELOG.md
  • packages/stem/CHANGELOG.md
  • packages/stem/README.md
  • packages/stem/Taskfile.yml
  • packages/stem/example/Taskfile.yml
  • packages/stem/example/autoscaling_demo/README.md
  • packages/stem/example/autoscaling_demo/Taskfile.yml
  • packages/stem/example/autoscaling_demo/justfile
  • packages/stem/example/canvas_patterns/Taskfile.yml
  • packages/stem/example/canvas_patterns/justfile
  • packages/stem/example/daemonized_worker/Taskfile.yml
  • packages/stem/example/daemonized_worker/justfile
  • packages/stem/example/dlq_sandbox/README.md
  • packages/stem/example/dlq_sandbox/Taskfile.yml
  • packages/stem/example/dlq_sandbox/justfile
  • packages/stem/example/docs_snippets/lib/signals.dart
  • packages/stem/example/docs_snippets/lib/uniqueness.dart
  • packages/stem/example/docs_snippets/lib/workflows.dart
  • packages/stem/example/encrypted_payload/README.md
  • packages/stem/example/encrypted_payload/Taskfile.yml
  • packages/stem/example/encrypted_payload/justfile
  • packages/stem/example/microservice/README.md
  • packages/stem/example/microservice/Taskfile.yml
  • packages/stem/example/microservice/justfile
  • packages/stem/example/monolith_service/Taskfile.yml
  • packages/stem/example/monolith_service/justfile
  • packages/stem/example/ops_health_suite/README.md
  • packages/stem/example/ops_health_suite/Taskfile.yml
  • packages/stem/example/ops_health_suite/justfile
  • packages/stem/example/postgres_tls/README.md
  • packages/stem/example/postgres_tls/Taskfile.yml
  • packages/stem/example/postgres_tls/docker-compose.yml
  • packages/stem/example/postgres_tls/justfile
  • packages/stem/example/progress_heartbeat/README.md
  • packages/stem/example/progress_heartbeat/Taskfile.yml
  • packages/stem/example/progress_heartbeat/justfile
  • packages/stem/example/rate_limit_delay/README.md
  • packages/stem/example/rate_limit_delay/Taskfile.yml
  • packages/stem/example/rate_limit_delay/justfile
  • packages/stem/example/retry_task/README.md
  • packages/stem/example/retry_task/Taskfile.yml
  • packages/stem/example/retry_task/justfile
  • packages/stem/example/security/ed25519_tls/README.md
  • packages/stem/example/security/ed25519_tls/Taskfile.yml
  • packages/stem/example/security/ed25519_tls/justfile
  • packages/stem/example/security/hmac/README.md
  • packages/stem/example/security/hmac/Taskfile.yml
  • packages/stem/example/security/hmac/justfile
  • packages/stem/example/security/hmac_tls/README.md
  • packages/stem/example/security/hmac_tls/Taskfile.yml
  • packages/stem/example/security/hmac_tls/justfile
  • packages/stem/example/signals_demo/README.md
  • packages/stem/example/signals_demo/Taskfile.yml
  • packages/stem/example/signals_demo/justfile
  • packages/stem/example/signing_key_rotation/README.md
  • packages/stem/example/signing_key_rotation/Taskfile.yml
  • packages/stem/example/signing_key_rotation/justfile
  • packages/stem/example/stack_autowire.dart
  • packages/stem/example/task_context_mixed/README.md
  • packages/stem/example/task_context_mixed/Taskfile.yml
  • packages/stem/example/task_context_mixed/justfile
  • packages/stem/example/unique_tasks/Taskfile.yml
  • packages/stem/example/unique_tasks/justfile
  • packages/stem/example/worker_control_lab/README.md
  • packages/stem/example/worker_control_lab/Taskfile.yml
  • packages/stem/example/worker_control_lab/justfile
  • packages/stem/example/workflows/Taskfile.yml
  • packages/stem/example/workflows/custom_factories.dart
  • packages/stem/example/workflows/justfile
  • packages/stem/example/workflows/sqlite_store.dart
  • packages/stem/lib/src/bootstrap/stem_app.dart
  • packages/stem/lib/src/bootstrap/stem_client.dart
  • packages/stem/lib/src/bootstrap/stem_stack.dart
  • packages/stem/lib/src/bootstrap/workflow_app.dart
  • packages/stem/test/bootstrap/stem_app_test.dart
  • packages/stem/test/bootstrap/stem_client_test.dart
  • packages/stem/test/bootstrap/stem_stack_test.dart
  • packages/stem_adapter_tests/CHANGELOG.md
  • packages/stem_adapter_tests/README.md
  • packages/stem_builder/CHANGELOG.md
  • packages/stem_cli/CHANGELOG.md
  • packages/stem_memory/CHANGELOG.md
  • packages/stem_memory/README.md
  • packages/stem_memory/lib/src/memory_factories.dart
  • packages/stem_memory/lib/stem_memory.dart
  • packages/stem_postgres/CHANGELOG.md
  • packages/stem_postgres/lib/src/stack/postgres_adapter.dart
  • packages/stem_postgres/lib/src/workflow/postgres_factories.dart
  • packages/stem_redis/CHANGELOG.md
  • packages/stem_sqlite/CHANGELOG.md
💤 Files with no reviewable changes (21)
  • packages/stem/example/signing_key_rotation/justfile
  • packages/stem/example/progress_heartbeat/justfile
  • packages/stem/example/signals_demo/justfile
  • packages/stem/example/workflows/justfile
  • packages/stem/example/canvas_patterns/justfile
  • packages/stem/example/security/ed25519_tls/justfile
  • packages/stem/example/task_context_mixed/justfile
  • packages/stem/example/rate_limit_delay/justfile
  • packages/stem/example/daemonized_worker/justfile
  • packages/stem/example/monolith_service/justfile
  • packages/stem/example/postgres_tls/justfile
  • packages/stem/example/encrypted_payload/justfile
  • packages/stem/example/autoscaling_demo/justfile
  • packages/stem/example/retry_task/justfile
  • packages/stem/example/microservice/justfile
  • packages/stem/example/security/hmac_tls/justfile
  • packages/stem/example/worker_control_lab/justfile
  • packages/stem/example/dlq_sandbox/justfile
  • packages/stem/example/unique_tasks/justfile
  • packages/stem/example/security/hmac/justfile
  • packages/stem/example/ops_health_suite/justfile
📜 Review details
🧰 Additional context used
🪛 Checkov (3.2.334)
packages/stem/example/postgres_tls/Taskfile.yml

[medium] 73-74: Basic Auth Credentials

(CKV_SECRET_4)

🪛 markdownlint-cli2 (0.21.0)
packages/stem/example/postgres_tls/README.md

[warning] 16-16: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 18-18: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 20-20: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 24-24: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 26-26: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 28-28: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 30-30: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 32-32: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 34-34: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 36-36: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 41-41: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

packages/stem_sqlite/CHANGELOG.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

packages/stem/example/progress_heartbeat/README.md

[warning] 41-41: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

packages/stem_adapter_tests/CHANGELOG.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

packages/dashboard/CHANGELOG.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

packages/stem_cli/CHANGELOG.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

packages/stem_memory/CHANGELOG.md

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

packages/stem/example/microservice/README.md

[warning] 42-42: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🔇 Additional comments (60)
packages/stem_builder/CHANGELOG.md (1)

1-6: Changelog update looks good.

packages/stem/Taskfile.yml (1)

6-10: Include block looks correct.

packages/stem_redis/CHANGELOG.md (1)

1-4: Changelog update looks good.

packages/stem/example/ops_health_suite/README.md (1)

33-44: Use just instead of task for CLI health checks, or add missing tasks to the Taskfile.

The commands shown use task build-cli and task stem ..., but neither build-cli nor stem tasks are defined in the ops_health_suite/Taskfile.yml. The Justfile.common defines both, so either:

  1. Change task to just (preferred if using justfile like other examples), or
  2. Add wrapper tasks to the Taskfile that invoke the compiled stem CLI binary.

Likely an incorrect or invalid review comment.

packages/stem/example/worker_control_lab/README.md (2)

37-60: Task-based CLI examples look consistent.

The updated command examples align with the Taskfile migration.


69-80: Local workflow commands updated cleanly.

The local build/run section reads correctly with Taskfile targets.

packages/stem/example/signals_demo/README.md (1)

32-42: Taskfile-based local build steps are clear.

The updated commands are consistent and easy to follow.

packages/stem/example/dlq_sandbox/README.md (1)

104-113: Local Taskfile workflow update is consistent.

The commands match the Taskfile-based setup described elsewhere.

packages/stem/example/retry_task/README.md (1)

51-60: Task-based local workflow is documented clearly.

No issues with the updated commands.

packages/stem/example/daemonized_worker/Taskfile.yml (1)

1-31: Taskfile setup is solid and consistent.

The task definitions and env loading pattern look good.

packages/stem/example/security/ed25519_tls/README.md (2)

10-14: Key/cert generation steps updated cleanly.

The Taskfile commands are straightforward.


25-36: Local Taskfile workflow reads well.

No issues with the updated local build/run guidance.

packages/stem/example/rate_limit_delay/README.md (1)

89-98: Task-based local workflow is consistent.

The updated commands align with the Taskfile migration.

packages/stem/example/postgres_tls/docker-compose.yml (1)

1-45: The TLS certificates are properly baked into the postgres image. The Dockerfile at packages/stem_cli/docker/testing/postgres/Dockerfile explicitly copies root.crt, server.crt, and server.key to /etc/postgres/certs/ with correct ownership and permissions set. No changes needed.

packages/stem/example/security/hmac/README.md (1)

20-30: LGTM!

The migration from Justfile to Taskfile command references is clean. The new section correctly leads with key rotation before dep startup.

packages/stem/CHANGELOG.md (1)

1-16: LGTM!

Correctly promotes the in-progress section to ## Unreleased rather than carrying a premature 0.1.1 tag, and the new bullets accurately describe the fail-fast bootstrap improvements and Taskfile migration.

packages/stem_postgres/lib/src/stack/postgres_adapter.dart (1)

132-139: LGTM!

The call site correctly migrates to the new positional argument, making backendFactory consistent with all other factory method calls in this adapter (brokerFactory, workflowStoreFactory, etc.).

packages/stem_postgres/CHANGELOG.md (1)

1-5: LGTM!

The entry accurately documents the breaking signature change and the downstream adapter wiring update.

packages/stem_postgres/lib/src/workflow/postgres_factories.dart (1)

29-38: Verify no remaining callers use the old named connectionString: parameter

The signature change from an optional/named connectionString to a required positional uri is a breaking public API change. Verification confirms only one call site exists (postgres_adapter.dart line 133), and it has been correctly updated to use the positional argument. No test files reference the old API style.

Within this repository, the migration is complete. External consumers of the stem_postgres package depending on the old named-parameter API will need to update their code.

packages/stem/example/workflows/Taskfile.yml (1)

1-53: Solid Taskfile migration.
Tasks and env-loading patterns are consistent and clear.

README.md (3)

31-61: Quick Start snippet looks consistent.
The client/worker lifecycle and enqueue/wait flow are clear.


135-145: Package list update looks good.


269-290: Targeted adapter task guidance is clear.

packages/stem/lib/src/bootstrap/stem_stack.dart (4)

157-177: Fail-fast sqlite guardrails look solid.


193-235: Toggle-aware factory resolution wiring looks correct.


310-337: Improved adapter error messaging is clear.


354-365: Helper centralizes sqlite guard logic cleanly.

packages/stem/example/signing_key_rotation/README.md (1)

15-47: Docs update looks consistent with Taskfile migration.

packages/stem/example/autoscaling_demo/Taskfile.yml (1)

14-71: Task orchestration looks good.

packages/stem/example/Taskfile.yml (1)

68-188: Central orchestration wiring looks solid.

packages/stem_adapter_tests/README.md (1)

13-140: README revisions are clear and comprehensive.

packages/stem_memory/lib/stem_memory.dart (1)

14-21: Export rename aligns with the new factory name.

packages/stem_memory/README.md (1)

13-35: Updated quick‑start flow reads well and matches the new API.

Also applies to: 41-44

packages/stem/example/retry_task/Taskfile.yml (1)

1-68: Taskfile workflow is cohesive and self‑contained.

packages/stem/example/postgres_tls/README.md (1)

15-36: Taskfile‑based run instructions are clear and consistent.

Also applies to: 40-42

packages/stem/lib/src/bootstrap/stem_client.dart (1)

79-122: fromUrl wiring is clean and consistent with the bootstrap stack.

packages/stem/example/security/hmac_tls/Taskfile.yml (1)

1-86: LGTM — clean Taskfile structure with consistent shell hygiene.

Tasks use set -euo pipefail, template {{.TASKFILE_DIR}} for path resolution, and the sed escaping for &/| is correct for the |-delimited substitution (base64 output won't contain other sed-special replacement characters).

packages/stem/lib/src/bootstrap/stem_app.dart (1)

206-305: Overall fromUrl logic is well-structured and correct.

The conditional auto-provisioning of lock stores and revoke stores, the guard checks against workerConfig fields, and the delegation to create() are all sound. Parameter resolution correctly avoids double-wrapping when the caller already provides a coordinator or revoke store.

packages/stem/example/encrypted_payload/README.md (1)

110-122: LGTM — README correctly references all defined Taskfile tasks.

All listed commands (task init, task deps-up, task build, task run:worker, task run:enqueuer, task compose-up) have corresponding task definitions in the new Taskfile.yml.

packages/stem/example/microservice/Taskfile.yml (1)

1-266: Overall structure is solid — consistent shell hygiene and well-described tasks.

The init/secrets/TLS/keys workflow is well-organized, and the task descriptions make the intended usage clear.

packages/stem/example/microservice/README.md (1)

153-177: LGTM — local build section accurately reflects the Taskfile workflow.

All referenced task names (init:hmac, init:hmac-tls, init:ed25519-tls, deps-up, build, run:worker, run:enqueuer, run:beat) have corresponding definitions in the new Taskfile.yml.

packages/stem/lib/src/bootstrap/workflow_app.dart (1)

1-36: LGTM on imports and constructor.

New imports for StemStack, RevokeStore, and UniqueTaskCoordinator are needed by the fromUrl factory and correctly added.

packages/stem/example/worker_control_lab/Taskfile.yml (1)

1-73: LGTM — consistent with the other example Taskfiles.

Structure, env-loading logic, and task definitions follow the same conventions as the other migrated examples. The additional STEM_REVOKE_STORE_URL, WORKER_NAME, and WORKER_CONCURRENCY environment variables in run-worker are appropriate for the worker-control-lab scenario.

Taskfile.yml (2)

33-65: Well-structured centralized env bootstrap with clear error messaging.

The test:with-env internal task cleanly encapsulates the pattern of checking required env vars → auto-sourcing the init script → re-checking → failing with actionable guidance. This eliminates duplication across test, test:contract, test:redis, test:postgres, and coverage.


89-101: Multi-line RUN in test:contract — verify Taskfile template interpolation preserves newlines.

The RUN value (lines 96-101) is a multi-line YAML block that gets interpolated into the bash script via {{.RUN}}. Taskfile's Go template engine should preserve newlines in block scalars, but it's worth a quick smoke test to ensure all five task invocations execute sequentially rather than being concatenated into one line.

packages/stem/test/bootstrap/stem_client_test.dart (1)

29-61: LGTM — good end-to-end coverage of the fromUrl adapter resolution path.

The test correctly exercises StemClient.fromUrl with a custom adapter, verifying that the adapter-backed broker/backend are wired and a task can execute to completion. Resource cleanup via try/finally is properly structured.

packages/stem/test/bootstrap/stem_app_test.dart (3)

123-152: LGTM — solid adapter-backed StemApp.fromUrl test.

Correctly validates that an adapter-backed broker/backend are resolved from the URL, and a task runs to completion. Clean resource management via try/finally.


154-193: Good lifecycle verification for auto-wired stores.

This test is particularly valuable — it validates that uniqueTasks: true and requireRevokeStore: true trigger automatic provisioning of the lock/revoke stores from the adapter, and that shutdown() correctly invokes the dispose callbacks on both. The boolean-flag pattern for verifying disposal is clean and sufficient.


315-348: LGTM — end-to-end StemWorkflowApp.fromUrl test.

Exercises the full fromUrl → workflow execution → completion path with an adapter-backed stack. Provides confidence that the new workflow_app.dart:fromUrl factory wires broker, backend, and workflow store correctly.

packages/stem/README.md (2)

62-62: Good simplification of the Quick Start to StemClient.inMemory.

Removing the dependency on external services from the first code sample lowers the barrier to entry. Users who need persistent adapters are correctly directed to the new fromUrl section immediately below.


75-103: Clear progressive disclosure: explicit factories → URL helper.

The two-example pattern (explicit StemClient.create with factory functions, then the lower-boilerplate StemClient.fromUrl) gives users both the full-control and convenience paths. The StemStoreOverrides usage for directing the backend to a different Redis DB is a practical example.

packages/stem/example/workflows/sqlite_store.dart (1)

11-13: The code is correct. The StemSqliteAdapter explicitly handles the two-slash URI format in its _fileFromUri function: when uri.path is empty (which occurs with sqlite://workflow.sqlite), it falls back to using uri.host to construct the file path. The adapter supports both sqlite://filename and sqlite:///path/to/file formats intentionally, making the example code functional and appropriate.

packages/stem/example/docs_snippets/lib/signals.dart (1)

100-115: LGTM.

Clean migration from StemApp.create to StemApp.fromUrl; resource lifecycle (start → enqueue → close → cancel) is correct.

packages/stem/test/bootstrap/stem_stack_test.dart (2)

104-113: LGTM.

Error message assertions for uniqueTasks are correctly updated with allOf(contains(...), contains(...)).


139-201: LGTM on new revoke/workflow/broker tests; note the intentional asymmetry in broker's error assertion.

The revoke store and workflow store tests correctly pair two contains matchers (error message + "Disable" hint). The broker test (line 193) uses only one contains matcher — appropriate, since there's no "Disable X" option for a required broker.

packages/stem/example/stack_autowire.dart (1)

10-11: LGTM — metadata getter correctly fulfills the TaskHandler interface contract.

packages/stem/example/docs_snippets/lib/uniqueness.dart (1)

101-110: LGTM.

Clean migration; uniqueTasks: true with uniqueTaskDefaultTtl correctly replaces the explicit coordinator wiring, and the stem_redis import is still justified by buildRedisCoordinator.

packages/stem/example/docs_snippets/lib/workflows.dart (2)

33-33: LGTM — StemClient.fromUrl('memory://') cleanly replaces StemClient.inMemory().


131-136: LGTM.

StemWorkflowApp.fromUrl('memory://', ...) with encoder configuration is consistent with the file's migration pattern; GzipPayloadEncoder's inline const constructor is valid.

packages/stem/example/workflows/custom_factories.dart (1)

8-23: No action needed — both StemRedisAdapter and StemStoreOverrides properly declare const constructors.

StemRedisAdapter declares const StemRedisAdapter({...}) at packages/stem_redis/lib/src/stack/redis_adapter.dart:74, and StemStoreOverrides declares const StemStoreOverrides({...}) at packages/stem/lib/src/bootstrap/stem_stack.dart:32. The const usage in the example code is valid.

Likely an incorrect or invalid review comment.

Comment on lines 1 to 3
## Unreleased

- Initial release of the `stem_dashboard` package.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix markdownlint MD041 by adding a top-level heading.
The first line is an H2, which violates the configured lint rule.

Proposed fix
-## Unreleased
+# Changelog
+
+## Unreleased
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Unreleased
- Initial release of the `stem_dashboard` package.
# Changelog
## Unreleased
- Initial release of the `stem_dashboard` package.
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/dashboard/CHANGELOG.md` around lines 1 - 3, Add a top-level H1
heading above the existing "## Unreleased" entry to satisfy markdownlint MD041;
for example insert a single-line "# Changelog" (or "# stem_dashboard Changelog")
before the "## Unreleased" heading so the file begins with an H1 and retains the
existing "## Unreleased" section and package note (`stem_dashboard`).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (2)
packages/stem/lib/src/bootstrap/stem_app.dart (1)

299-302: Fragile positional insertion into the disposers list.

This was already raised in prior review. insertAll(1, autoDisposers) relies on create() always producing [workerShutdown, backendDispose, brokerDispose] at indices 0, 1, 2.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/lib/src/bootstrap/stem_app.dart` around lines 299 - 302, The
code is fragile because app._disposers.insertAll(1, autoDisposers) assumes
create() always returns [workerShutdown, backendDispose, brokerDispose]; instead
locate the intended insertion point dynamically and insert there: find the index
of the existing backend/broker disposal entry (e.g., by matching the
backendDispose/brokerDispose callback or a unique marker in app._disposers using
indexWhere) and call insertAll(foundIndex, autoDisposers); if neither is found,
append autoDisposers to the end. Update the logic around app._disposers,
autoDisposers and the create() consumers to use this index lookup rather than
hard-coded 1.
packages/stem/lib/src/bootstrap/workflow_app.dart (1)

366-388: Redundant adapter resolution: StemStack.fromUrl and StemApp.fromUrl both resolve from the same URL/adapters.

This was already raised in prior review. StemStack.fromUrl (line 366) and StemApp.fromUrl (line 373) both perform full adapter resolution against the same URL, creating two separate stacks. Similarly, encoder parameters on lines 403-406 are silently ignored by create() when stemApp is already provided.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/stem/lib/src/bootstrap/stem_app.dart`:
- Around line 306-317: The catch clause is shadowing the local StemStack
variable named stack; rename the catch's StackTrace variable from stack to
stackTrace in the try/catch that cleans up autoDisposers so it no longer hides
the StemStack, and update the subsequent Error.throwWithStackTrace call to pass
stackTrace (ensure autoDisposers.reversed loop and
Error.throwWithStackTrace(error, stackTrace) are adjusted accordingly).

In `@packages/stem/lib/src/bootstrap/stem_stack.dart`:
- Around line 372-379: _hasResolvedFactory currently duplicates work done by
_requireFactory by re-iterating adapters and calling the resolver twice; fix
this by changing the pre-check to return (and optionally cache) the resolved
factory instead of a boolean. Concretely, replace or augment _hasResolvedFactory
to call _optionalFactory(adapters, kind, uri, resolver) and return the resolved
T? (or a wrapper with the value) so callers can reuse that instance rather than
calling _requireFactory again; alternatively, refactor _requireFactory to accept
an optional pre-resolved factory or a toggle so it performs the sqlite/toggle
check internally. Update all callers (those using _hasResolvedFactory,
_optionalFactory, and _requireFactory) to consume the returned resolved factory
and avoid the second resolution loop.
- Around line 157-195: Add the same SQLite pre-check used for
scheduling/uniqueTasks/requireRevokeStore for workflows: check if workflows is
true and !_hasResolvedFactory<WorkflowStoreFactory>(registered,
StemStoreKind.workflow, workflowUri, (adapter) =>
adapter.workflowStoreFactory(workflowUri)) then call
_failIfSqliteStoreUnsupported(kind: StemStoreKind.workflow, uri: workflowUri,
toggle: 'workflows'); place this guard in the same block sequence (before the
subsequent _requireFactory/_requireFactory error for workflows) so users get the
sqlite-specific guidance when no workflow adapter is provided.

In `@packages/stem/lib/src/bootstrap/workflow_app.dart`:
- Around line 408-417: The catch clause `on Object catch (error, stack)` is
shadowing the earlier `StemStack stack` variable (declared above), hurting
readability; rename the catch's `stack` to e.g. `trace` (so `on Object catch
(error, trace)`) and update the subsequent call
`Error.throwWithStackTrace(error, stack)` to `Error.throwWithStackTrace(error,
trace)` to avoid the name collision while preserving behavior; leave the
`StemStack stack` identifier unchanged.

In `@packages/stem/test/bootstrap/stem_app_test.dart`:
- Around line 493-533: The _BootstrapAdapter currently always returns null from
scheduleStoreFactory; add an optional ScheduleStoreFactory? schedule field to
the _BootstrapAdapter constructor (mirroring
broker/backend/workflow/lock/revoke), store it as a final member, and return it
from the scheduleStoreFactory(Uri uri) override so fromUrl can support
scheduling when provided; update the constructor parameter list and the class
fields accordingly, referencing _BootstrapAdapter, scheduleStoreFactory, and
ScheduleStoreFactory.

In `@packages/stem/test/bootstrap/stem_stack_test.dart`:
- Line 315: There is an extra two-space indentation on the expect call asserting
stack.revokeStore is same(revokeFactory); adjust the line containing
expect(stack.revokeStore, same(revokeFactory)); to match the surrounding expect
calls (use the same 6-space indentation) so it aligns with the other assertions
in the test (symbols: expect, stack.revokeStore, revokeFactory).

---

Duplicate comments:
In `@packages/stem/lib/src/bootstrap/stem_app.dart`:
- Around line 299-302: The code is fragile because app._disposers.insertAll(1,
autoDisposers) assumes create() always returns [workerShutdown, backendDispose,
brokerDispose]; instead locate the intended insertion point dynamically and
insert there: find the index of the existing backend/broker disposal entry
(e.g., by matching the backendDispose/brokerDispose callback or a unique marker
in app._disposers using indexWhere) and call insertAll(foundIndex,
autoDisposers); if neither is found, append autoDisposers to the end. Update the
logic around app._disposers, autoDisposers and the create() consumers to use
this index lookup rather than hard-coded 1.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa9cce and f4a4cc0.

📒 Files selected for processing (5)
  • packages/stem/lib/src/bootstrap/stem_app.dart
  • packages/stem/lib/src/bootstrap/stem_stack.dart
  • packages/stem/lib/src/bootstrap/workflow_app.dart
  • packages/stem/test/bootstrap/stem_app_test.dart
  • packages/stem/test/bootstrap/stem_stack_test.dart
📜 Review details
🔇 Additional comments (12)
packages/stem/lib/src/bootstrap/stem_stack.dart (2)

328-356: Improved error messages in _requireFactory — LGTM.

The split between "adapter matched but didn't provide the store" and "no adapter registered at all" with toggle-specific hints is a nice UX improvement for bootstrap error diagnostics.


381-393: _failIfSqliteStoreUnsupported only checks sqlite and file schemes.

This is reasonable for now, but note that other file-backed database URLs (e.g., file+sqlite, custom scheme wrappers) would bypass this check silently. If additional schemes emerge, this will need updating.

packages/stem/lib/src/bootstrap/workflow_app.dart (1)

390-407: Error cleanup correctly shuts down the app on workflow bootstrap failure — LGTM.

The try/catch with swallowed shutdown errors ensures the original error surfaces while still cleaning up the auto-provisioned StemApp.

packages/stem/lib/src/bootstrap/stem_app.dart (3)

232-247: needsUniqueLockStore / needsRevokeStore guard logic is sound.

The conditions correctly avoid auto-provisioning when a coordinator or revoke store is already supplied by the caller or worker config.


249-278: Defensive null checks on stack.lockStore and stack.revokeStore are unreachable but acceptable.

Since StemStack.fromUrl with uniqueTasks: true or requireRevokeStore: true already throws if the factory can't be resolved, these null checks (lines 255 and 272) are effectively dead code. They're reasonable as defensive guards against future refactors of StemStack.


280-317: Error cleanup on bootstrap failure properly disposes auto-provisioned stores in reverse order — LGTM.

The reversed iteration and swallowed cleanup errors ensure orderly teardown while preserving the original failure.

packages/stem/test/bootstrap/stem_stack_test.dart (3)

224-273: Sqlite guardrail tests cover scheduling, lock, and revoke — good coverage.

These tests align well with the _failIfSqliteStoreUnsupported pre-checks in production code. Note that a symmetric test for workflows: true with a sqlite URL is still absent (related to the missing sqlite pre-check in StemStack.fromUrl for workflows).


275-317: Positive test for sqlite with custom adapter providing all toggle factories — LGTM.

This test validates that the sqlite guardrails don't block legitimate adapters that explicitly handle sqlite stores.


152-200: New tests for missing workflow store and missing broker — LGTM.

Good coverage of the enhanced _requireFactory error paths, asserting both the store-kind-specific message and the toggle hint.

packages/stem/test/bootstrap/stem_app_test.dart (3)

123-152: fromUrl resolution test — LGTM.

Good basic coverage verifying adapter-backed broker/backend resolution and task execution through the URL-based bootstrap path.


154-238: Auto-wiring and disposal tests — thorough and well-structured.

Both the happy-path disposal on shutdown and the error-path disposal on bootstrap failure are covered with proper tracking flags. This validates the resource lifecycle guarantees of fromUrl.


360-441: StemWorkflowApp.fromUrl end-to-end and error cleanup tests — LGTM.

The workflow completion test validates the full URL-based workflow bootstrap path, and the error cleanup test confirms that StemApp auto-provisioned stores are properly disposed when downstream StemWorkflowApp bootstrap fails (via the app.shutdown() in the catch block).

Comment on lines 493 to 533
class _BootstrapAdapter implements StemStoreAdapter {
_BootstrapAdapter({
required this.scheme,
this.broker,
this.backend,
this.workflow,
this.lock,
this.revoke,
});

final String scheme;
final StemBrokerFactory? broker;
final StemBackendFactory? backend;
final WorkflowStoreFactory? workflow;
final LockStoreFactory? lock;
final RevokeStoreFactory? revoke;

@override
String get name => 'bootstrap-test-adapter';

@override
bool supports(Uri uri, StemStoreKind kind) => uri.scheme == scheme;

@override
StemBrokerFactory? brokerFactory(Uri uri) => broker;

@override
StemBackendFactory? backendFactory(Uri uri) => backend;

@override
WorkflowStoreFactory? workflowStoreFactory(Uri uri) => workflow;

@override
ScheduleStoreFactory? scheduleStoreFactory(Uri uri) => null;

@override
LockStoreFactory? lockStoreFactory(Uri uri) => lock;

@override
RevokeStoreFactory? revokeStoreFactory(Uri uri) => revoke;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

_BootstrapAdapter.scheduleStoreFactory always returns null.

This is fine for current tests, but if future tests need scheduling support through fromUrl, this adapter will need extending. Consider adding an optional schedule parameter for symmetry with the other store kinds.

Proposed improvement
 class _BootstrapAdapter implements StemStoreAdapter {
   _BootstrapAdapter({
     required this.scheme,
     this.broker,
     this.backend,
     this.workflow,
     this.lock,
     this.revoke,
+    this.schedule,
   });

   final String scheme;
   final StemBrokerFactory? broker;
   final StemBackendFactory? backend;
   final WorkflowStoreFactory? workflow;
   final LockStoreFactory? lock;
   final RevokeStoreFactory? revoke;
+  final ScheduleStoreFactory? schedule;

   `@override`
-  ScheduleStoreFactory? scheduleStoreFactory(Uri uri) => null;
+  ScheduleStoreFactory? scheduleStoreFactory(Uri uri) => schedule;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/stem/test/bootstrap/stem_app_test.dart` around lines 493 - 533, The
_BootstrapAdapter currently always returns null from scheduleStoreFactory; add
an optional ScheduleStoreFactory? schedule field to the _BootstrapAdapter
constructor (mirroring broker/backend/workflow/lock/revoke), store it as a final
member, and return it from the scheduleStoreFactory(Uri uri) override so fromUrl
can support scheduling when provided; update the constructor parameter list and
the class fields accordingly, referencing _BootstrapAdapter,
scheduleStoreFactory, and ScheduleStoreFactory.

@github-actions
Copy link

Package publishing

Package Version Status Publish tag (post-merge)
package:stem 0.1.1 ready to publish stem-v0.1.1
package:stem_adapter_tests 0.1.1 ready to publish stem_adapter_tests-v0.1.1
package:stem_builder 0.1.0 ready to publish stem_builder-v0.1.0
package:stem_cli 0.1.0 already published at pub.dev
package:stem_memory 0.1.0 ready to publish stem_memory-v0.1.0
package:stem_postgres 0.1.0 already published at pub.dev
package:stem_redis 0.1.1 ready to publish stem_redis-v0.1.1
package:stem_sqlite 0.1.1 ready to publish stem_sqlite-v0.1.1

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

@kingwill101 kingwill101 merged commit 359eb2b into master Feb 24, 2026
10 checks passed
@kingwill101 kingwill101 deleted the feature/dx-api-improvements branch February 24, 2026 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant