Skip to content

feat(testkit): mocking, tracing, and live debugging, surfaced as agent tool calls - #51

Merged
senamakel merged 90 commits into
mainfrom
testkit
Aug 13, 2026
Merged

feat(testkit): mocking, tracing, and live debugging, surfaced as agent tool calls#51
senamakel merged 90 commits into
mainfrom
testkit

Conversation

@senamakel

Copy link
Copy Markdown
Member

Why

A workflow that runs is not a workflow that works. The engine will happily execute a graph whose every binding resolved to null, whose agent node dispatched with an empty prompt, and whose failure was swallowed by an on_error policy — and report all of it as success, because each of those is a legal value rather than an error. The output of a broken run looks exactly like the output of a correct one.

What was missing was not execution. It was the means to interrogate an execution. Today the whole story is a RunObserver whose callbacks return (), a caps::mock suite of fixed echoes, and a Diagnosis stranded behind the store feature — so every test that needed more wrote its own AtomicUsize-counting double, and there are 15+ such one-offs in this repo's own suite.

Workflows here are written by agents as often as by people, and an agent that cannot debug what it wrote can only guess at why it failed.

What this adds

The engine seam — tinyflows::interception (always compiled, inert unless used)

A RunObserver can watch a run and never change one. A StepInterceptor returns a StepAction the engine obeys — which is what makes breakpoints and output overrides expressible at all. New entry point engine::run_intercepted.

The action vocabulary is deliberately small, and each variant lands the activation back on a path the engine already has: an injected failure enters the node's own on_error policy, a replaced output routes through the same port and lane logic real output does, and a substituted activation is still recorded as a step and reported to the observer. Nothing invents control flow beside the engine.

Placed at the one point a node executor runs, and nowhere else: after the cancellation check and approval gate, after input resolution, outside the retry loop (so a breakpoint fires once per activation, not once per attempt) and outside the per-attempt timeout race (so time parked at a breakpoint is never charged against node_timeout_secs).

Four layers on top — tinyflows::testkit (default-off testkit feature, no new dependencies)

  • mocks — programmable, recording capability doubles. * globs, per-call sequences, injected failures, delays, schema-synthesized answers, per-node scoping. Every call lands in one log across all capabilities and is attributed to the node that made it.
  • trace — each activation's input and output, plus every =-binding with the value it resolved to and, when it resolved to nothing, the upstream node it was reading from. That last field turns "it produced null" into a pointer at the node that should have produced the value.
  • harnessTestHarness and named assertions, notably assert_no_null_bindings.
  • debug — real breakpoints: pause before or after a node, inspect what it was about to receive, override its output, skip it, fail it, patch the run state, or single-step. Conditions cover on-error, the nth activation of a loop, and arbitrary =-expressions.
  • tools — all of the above as 10 named tools with real JSON Schemas and a JSON-in/JSON-out TestkitRegistry::dispatch. tinyflows registers nothing and talks to no model — the same division catalog already draws for the node-kind contracts.

Supporting moves

diagnostics and evidence lifted out from behind the store feature (both are pure functions of engine records; a trace needs them as much as a durable record does), and caps::sample_for_schema out from behind host-caps (the auto-mock shouldn't have to pull in a process runner and an HTTP client to reach 35 dependency-free lines). Both re-exported from their old homes, so no downstream caller breaks.

build_graph/build_and_run now take a private RunConfig params struct instead of 8–9 positional arguments. This removes four #[allow(clippy::too_many_arguments)] and leaves every public signature untouched — a net reduction, and the reason adding the interceptor cost one field rather than fourteen signature edits.

A bug fixed on the way

A node that failed once and then succeeded on retry was reported as failed to observers of an activation's settled state. The engine's retry loop keeps the last failed attempt's error even after a later attempt succeeds; surfacing it unconditionally showed a recovered node as a failed one — and would have fired every on-error breakpoint on it. Fixed, with a regression test.

Design note: why breakpoints are in-process

The engine already knows how to pause — a requires_approval gate raises a real interrupt, checkpoints, and waits. That mechanism is built for waiting on a person, so it ends the run and resumes later by re-running the interrupted node from the top.

A breakpoint needs three things that path structurally cannot do: break after a node (resuming re-runs it, firing side effects twice), override what a node produced (needs the activation still on the stack), and be driven from another task (so an agent can inspect and step across separate tool calls).

So a breakpoint parks the activation in place and a DebugSession owns the run. The honest cost, stated in the docs: a session lives in one process and dies with it. PauseMode::Durable covers the one case where surviving a restart matters more — a break before a node, where nothing has run and the re-run is free — and is refused at registration for after-breakpoints rather than silently doubling side effects.

A paused run cannot wedge. Four independent releases, any one of which frees it: a pause timeout (5 min default), detach(), a dropped release channel, and dropping the session (which detaches → cancels → aborts, in that order). All four are tested. The controller uses a std::sync::Mutex deliberately: its guard is !Send, so holding the lock across the pause await fails to compile rather than being caught in review.

Verification

  • 1312 tests pass, 0 failures (102 new). Clippy clean on --all-targets --all-features, cargo fmt --check clean, cargo publish --dry-run clean.
  • All 8 feature combinations compile: default, store, host-caps, mock, testkit, graph-debug, chrome-extension, --all-features, --no-default-features.
  • The no-cost property is a property test, not a claim. tests/fuzz_interception.rs asserts over generated graphs that a plain run and a run with an inert interceptor produce identical output — and that inspecting every frame, and tracing, are equally free of side effects.
  • tests/interception_e2e.rs asserts an inert interceptor leaves both the outcome and the full observer step record byte-identical, then covers each action.
  • A full debug session is driven entirely over JSON in registry_tests, asserting only on JSON — which is exactly what an agent sees.

Not included

  • recording.rs — record-against-real-capabilities then replay. Respond::Passthrough is not implemented, so the fixture/pinning story is missing.
  • protocol/testkit-v1.schema.json — deliberately skipped. all_tools() already returns real JSON Schemas generated in Rust and tested for closedness; a hand-maintained parallel file would duplicate that and drift. Happy to add one if cross-language consumers need it.
  • Item-level breakpoints inside map_items — node-level covers the debugging need, and pausing one item holds a buffer_unordered slot with a subtle interaction with ItemErrorPolicy::FailFast's lowest-index cancellation. Left out rather than rushed.

The ADR in local/docs/11-decisions.md could not be written — local/ is gitignored and not present in this worktree.

senamakel and others added 30 commits August 14, 2026 00:59
The diagnosis module and its tests were relocated from the store types directory to the top-level src directory, aligning the file structure with the module's broader scope beyond store-specific functionality.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The diagnostic formatter previously omitted a trailing newline when writing
diagnostic messages, causing subsequent output to appear on the same line.
This change restores the newline so each diagnostic is properly terminated.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce the proposal store types module, defining the data structures needed to represent proposals in the application state. This establishes the foundation for proposal-related state management.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce the `run` module under store types to define the data structures used for representing run records. This establishes the foundational types needed for upcoming run-related functionality.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
This change introduces the `types` module to the store crate, providing the necessary type definitions that were previously absent. The new module establishes a clear structure for store-related types, enabling better organization and future extensibility of the codebase.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
This change introduces type definitions that were previously absent from the store module, providing the necessary structure for future functionality. The new types establish the expected shape of data handled by the store, enabling consistent usage across the codebase.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The evidence retrieval logic was inadvertently dropped during a recent restructuring, causing lookups to fail at runtime. This change restores the missing functionality so evidence can be correctly fetched by identifier again.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce the `run` module under store types to define the data structures for run-related state. This establishes the foundational types needed for upcoming run tracking functionality.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Validate that directory entry names fit within the 255-character limit before any truncation logic is applied, preventing silent data loss when creating entries with overly long names.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a new mocks module under the host capability source tree to provide test doubles for host-related functionality. This establishes the scaffolding needed for upcoming unit tests that will exercise host capability behavior in isolation.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Removed an unused import from the capabilities module to keep the codebase clean and avoid compiler warnings.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
This change applies formatting updates to the library source file, ensuring consistent style and readability without altering any behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `use` statement for the unused module was removed to clean up the code and avoid compiler warnings.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce the `run` module under store types to define the data structures for run-related state. This establishes the foundational types needed for upcoming run tracking functionality.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The run module no longer re-exports MAX_EVIDENCE_BYTES, so tests now reference it directly from the evidence module. This removes an unnecessary public re-export and makes the constant's origin clearer.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Introduce the `run` module under store types to define the data structures for run-related state. This establishes the foundational types needed for upcoming run tracking functionality.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an off-by-default `testkit` feature that enables programmable capability mocks, a structured run trace, and live step-debugging driven from another task. It adds no new dependencies since tokio, futures-timer, async-trait, and jaq are already required by the engine, and the interception seam is always compiled but inert without this feature. The feature is always available in the crate's own tests, similar to `store` and `mock`.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The conditional compilation attribute for the ids module was reformatted to fit on a single line, and a long assertion in the store types tests was wrapped for improved readability. No behavior or logic changed.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The interception module was missing a block of logic that had been previously removed, and this change restores it to ensure the intended behavior is preserved.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted the source file to improve readability and consistency without altering any behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The run_config module was no longer referenced by any code in the engine, so it has been removed to keep the codebase clean and avoid dead code.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `use std::collections::HashMap;` import in `src/engine.rs` is no longer needed after recent refactoring, so it has been removed to keep the codebase clean and avoid compiler warnings.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `std::collections::HashMap` import is no longer needed in the engine module, so it has been removed to keep the codebase clean and avoid compiler warnings.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The run state is now restored to its previous value when a command fails, ensuring subsequent operations see a consistent state instead of a partially updated one.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The run state is now restored to its previous value when a command fails, ensuring subsequent operations see a consistent state instead of a partially updated one. This prevents cascading errors from stale state left behind by the failed run.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The build module was no longer referenced by any code in the engine, so it has been removed to keep the codebase clean and avoid dead code.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The build module was no longer referenced by any code in the engine, so it has been removed to keep the codebase clean and avoid dead code.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The build handler for the engine was no longer referenced anywhere in the codebase, so it has been removed to keep the source tree clean and avoid dead code.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The build handler for the removed legacy pipeline was no longer referenced anywhere in the codebase, so it has been deleted to reduce dead code and simplify the engine module.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 28 commits August 14, 2026 01:27
Add the new debug module to the testkit's public interface, making its types and functions available to consumers. This includes re-exporting the module's key items so they can be used directly from the testkit crate without additional imports.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add unit tests for breakpoint specs and their conditions, covering always, on-error, activation, expression, all/any composition, node targeting, and JSON round-tripping. The tests build StepFrame instances by hand to exercise each predicate without driving a full run.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add unit tests covering the debug controller's breakpoint registration rules, listing, clearing, release validation, detach behavior, and pause timeout configuration. These tests verify the controller's refusal and reporting behavior directly, complementing the existing end-to-end session tests.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a comprehensive test suite covering the full lifecycle of debug sessions, including breakpoint handling, stepping, conditional pauses, error recovery, and session cleanup. These tests verify that parked runs can be inspected, overridden, resumed, and safely terminated without hanging.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Added the missing imports for BreakpointSpec and DebugCommand in the session tests to ensure the test module compiles correctly.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now clones the controller handle once and reuses it across breakpoint registration, release, and listing operations, avoiding repeated calls to `session.controller()` and making the test's intent clearer.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The harness was previously missing its initialization step, which caused tests to run without the required environment setup. This change re-adds the setup call to ensure the harness behaves as intended.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Expose the new `harness` module and its `TestHarness` and `TestRun` types from the testkit, making the harness functionality publicly available for use in integration tests.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The retry test now prints the mock call log when the run fails, making it easier to diagnose why a retry did not recover as expected. The explicit match on the run result replaces the previous expect, allowing the call details to be displayed before panicking.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The activation logic previously skipped the check for whether an activation is already present, which could lead to duplicate activations being processed. This change re-adds the missing guard to ensure each activation is only handled once, preventing potential state corruption.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The harness tests now access the `json` field of node outputs instead of comparing the entire output object directly, matching the actual output structure. The retry test also replaces manual error handling with an expect call and removes debug logging, making the test more concise while preserving its verification of recovery behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds an end-to-end test verifying that a node which fails once and then succeeds on retry does not report an error to the interceptor. This guards against the engine's retry loop incorrectly surfacing the last failed attempt's error after a successful recovery.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a test that verifies the contract for tool execution, ensuring that the testkit correctly handles tool calls and their results. This covers the expected behavior for tool invocation and response handling.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The testkit registry tooling has been refreshed to align with current project conventions and improve maintainability. This change updates the registry implementation to reflect the latest expected behavior and structure.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The testkit now exposes a new `tools` module along with its public items, including `TestkitRegistry`, `ToolContract`, `ToolError`, and `all_tools`. This makes the tooling infrastructure available to consumers of the testkit crate, enabling them to use the registry and contract abstractions in their own tests.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The registry now stores the debug controller separately from the session, which is wrapped in an async mutex. This allows breakpoint management and pause release operations to proceed without waiting on a session that may be blocked in a debug wait, preventing deadlocks and improving responsiveness. The session is taken from the mutex on finish, and status reporting now reflects controller state rather than session state.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The StoredRun struct and its conversion from TestRun were no longer used after the trace lookup logic was simplified, so they have been removed along with the now-unnecessary Serialize import.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Added a test suite covering the tool contracts that hosts hand to models, asserting that every tool has complete metadata, input schemas are closed objects with declared properties, required arguments are properly declared, names are unique and namespaced, debug tools take session IDs, mutating flags are correct, lookup works, and contracts survive JSON round-tripping.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a comprehensive test suite for the tool dispatcher registry, covering run execution, error handling, mocks, traces, and the full debug session workflow. These tests verify the JSON-only interface works as expected for agents, including null binding reporting, sequenced mocks, breakpoint management, and pause/release cycles.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformat the testkit source files with rustfmt to normalize line wrapping and indentation across tests, mocks, and the tool registry. No behavior changes are introduced.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace `then(|| ...).flatten()` with `then_some(...).flatten()` when building the error field, since the closure only returns a reference and adds no computation. This makes the intent more direct without changing behavior.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The mock server was incorrectly dropping responses when multiple requests were made in quick succession, causing intermittent test failures. The response queue is now properly drained and reset between requests, ensuring each request receives its intended response.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The mock server's response handling was previously removed, which broke tests relying on mocked responses. This change restores the response logic so that tests can again use the mock server to simulate API responses.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a new test file for fuzz interception, providing coverage for the interception logic under fuzzing scenarios. This helps validate robustness and catch edge cases in the interception handling.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…tions

The changelog now covers the new `testkit` module for testing and debugging workflows, the `interception` hook for execution gating, and the promotion of diagnostics and evidence helpers to always-available features. It also notes the fix for retried nodes being incorrectly reported as failed.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a section to the README covering the `testkit` feature, which provides programmable mocks, structured run traces, and breakpoints for debugging workflows. The documentation explains how to use the test harness to catch null bindings that green runs hide, how to set breakpoints on live runs, and how agents can access these tools through a JSON-in/JSON-out dispatcher.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a new wiki page documenting testing and debugging practices for the project, providing developers with a reference for common workflows and troubleshooting steps.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds the engine's execution-gating hook, the testkit feature set, and the diagnostics and evidence readers to the architecture overview, and links the new Testing and Debugging page from the wiki sidebar.

Auto-committed-on: dragonfly
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@senamakel, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 21 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7deb864a-a4ae-4f74-9efa-1586f88b82e0

📥 Commits

Reviewing files that changed from the base of the PR and between cd39220 and e38ec7e.

📒 Files selected for processing (48)
  • CHANGELOG.md
  • CLAUDE.md
  • Cargo.toml
  • README.md
  • src/caps/host/mocks.rs
  • src/caps/mod.rs
  • src/caps/schema.rs
  • src/diagnostics.rs
  • src/diagnostics_tests.rs
  • src/engine.rs
  • src/engine/api.rs
  • src/engine/build.rs
  • src/engine/build/activation.rs
  • src/engine/build/handlers.rs
  • src/engine/resumable.rs
  • src/engine/run_config.rs
  • src/engine/run_state.rs
  • src/evidence.rs
  • src/interception.rs
  • src/lib.rs
  • src/store/types/mod.rs
  • src/store/types/proposal.rs
  • src/store/types/run.rs
  • src/store/types/types_tests.rs
  • src/testkit/debug/breakpoint.rs
  • src/testkit/debug/breakpoint_tests.rs
  • src/testkit/debug/controller.rs
  • src/testkit/debug/controller_tests.rs
  • src/testkit/debug/mod.rs
  • src/testkit/debug/session.rs
  • src/testkit/debug/session_tests.rs
  • src/testkit/harness.rs
  • src/testkit/harness_tests.rs
  • src/testkit/mocks.rs
  • src/testkit/mocks_tests.rs
  • src/testkit/mod.rs
  • src/testkit/tools/contracts.rs
  • src/testkit/tools/contracts_tests.rs
  • src/testkit/tools/error.rs
  • src/testkit/tools/mod.rs
  • src/testkit/tools/registry.rs
  • src/testkit/tools/registry_tests.rs
  • src/testkit/trace.rs
  • src/testkit/trace_tests.rs
  • tests/fuzz_interception.rs
  • tests/interception_e2e.rs
  • wiki/Testing-and-Debugging.md
  • wiki/_Sidebar.md

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.

@senamakel
senamakel merged commit c77db47 into main Aug 13, 2026
5 checks passed
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