What qlane cannot do

qlane is meant to reduce a set of failures, not remove them. These limits are part of the design, and they will be stated in the real documentation too.

  1. At-least-once is unavoidable.

    If a worker dies mid-step, that step runs again. qlane saves finished steps so they are not repeated, but a step that was in progress when the crash hit will run a second time. Anything that must happen only once has to be protected by the ledger and by the receiving system.

  2. Exactly-once needs the outside system.

    The ledger records "about to do it" and "done", reuses idempotency keys and can run your check ("did that happen?"). It cannot make a tool exactly-once if that tool cannot be queried and does not honor an idempotency key. Email is treated as not queryable.

  3. An unknown outcome is resolved by a person.

    When a crash lands between "about to" and "done" and there is no way to check, qlane stops and asks. A person (or your app) says "it happened", "it did not happen" or "check again". It will not guess, and a ticket in this state is not finished until someone answers or it expires. After an hour unresolved (a proposed default) it raises one alert. That alert is a reminder, not a resolution.

  4. Retries hidden inside SDKs are invisible to qlane.

    qlane turns off SDK-level retries only in its own provider adapters, so one layer owns retries. If your step calls a model SDK directly, that SDK may retry silently, and those retries multiply with qlane's: three layers of three retries can turn one failing call into 27 requests, each possibly billed, and qlane sees only a few. The docs would show how to turn SDK retries off.

  5. Spend caps are a cooperative bound, not a hard wall.

    Caps limit spending that goes through qlane. Workers call providers directly, so a call made outside qlane, or one already in flight when a cap is crossed, can overspend. Estimates of output size can be wrong and are corrected after the fact. The overshoot will be measured and published next to this statement; no number exists yet.

  6. Durability is claimed for ext4 only, and only after tests.

    Until the planned crash-and-disk tests have run, the claim will be limited to fsync on the ext4 file system. Power-loss behavior is untested. On a disk error qlane is designed to stop and fail loudly rather than retry the write.

  7. One SQLite file is one machine.

    Embedded and self-hosted modes run on a single node with a single writer. No clustering in the first release. No speed or throughput claims are made, because nothing has been measured.

  8. Backups have a loss window.

    A backup is a snapshot, so anything since the last one can be lost. Continuous backup is not part of the open-source core. Hosted would be better but is not zero, and no figure exists.

  9. Crash tests prove rules in simulation, not in the real world.

    They find bugs; they do not prove there are none. Real disks and the real runtime can behave differently from the simulator.

  10. Saved steps help only for steps that finished and were recorded.

    A step interrupted before its result was saved runs again.

  11. Checks and receipts are the code's own word.

    The default output check only catches an empty result, not a wrong one. A custom check catches only what it was written to catch. A receipt (a short note such as "sent 12 emails") cannot be verified by qlane. A scheduled job that never saves a receipt raises the missing-run alert even if it worked.

  12. Async provider jobs depend on the provider.

    qlane saves the provider's job id before it polls, and never submits again once it has the id. If the answer to the submit was lost and the provider cannot look a job up, the job may be running and billed, and qlane can only say "unknown" and ask. Re-submitting may pay twice.

  13. A suspected poison job is a suspicion.

    A ticket that keeps killing its worker is stopped after three lost leases and flagged. qlane cannot tell it from three unlucky host failures, up to three workers can die before it stops, and a retry starts the count again.

  14. A lost worker is a symptom, not a diagnosis.

    qlane can tell that a worker stopped answering. It cannot tell a crash from an out-of-memory kill, a host failure or a network partition.

  15. Schedules can be late, and an overlap skip is silent unless you watch for it.

    The scheduler runs on a tick, so a run can start late by up to the tick interval, never early. If a schedule fires while its previous run is still going, the new run is skipped on purpose and only an event records it; a slow run can alert as missing for itself. A queue pause or drain is a person's decision and qlane does not undo it. A schedule you disable raises one missing-run alert (case disabled) for each run it skips, so one disabled by mistake is flagged too.

  16. Concurrency caps limit slots, not cost.

    The optional cap on how many tickets one user or queue may run at once stops one user from filling every worker. Use spend caps for money.

  17. The loop guard stops loops, not spend.

    It sees chains of tickets that name their parent. Work that leaves qlane and comes back with no parent is a new chain. It can also refuse a legitimate repeat of identical work in one chain.

  18. Waiting for child tickets has limits.

    In M3 a parent waits for all its children; wait-for-any belongs to the separate milestone M3b. A parent waiting on children, and a ticket waiting on dependencies, ends dead if they never finish within the maximum wait. Inside a parallel branch the same wait limit fails only that branch.

  19. Parallel branches share one lease and one process.

    While any branch is active the ticket runs on one worker under one lease; a parked branch holds neither. A branch that blocks the event loop can stall its siblings and lose the lease for all of them. Budget reserved by a parked branch is not available to others until the branch ends or its maximum wait releases it. The order of side effects between branches is undefined, and a crash with several effects in flight can leave several unknown outcomes, each needing its own decision.

  20. Cancelling the losers of a wait-for-any does not undo them.

    Effects the cancelled children already made stay, and their spend counts. A ticket that depends on another ticket points at one ticket id; if that ticket is retried, the retry is a new ticket and the waiting ticket does not follow it.

  21. The graph editor changes waiting tickets, not running ones.

    It edits dependencies only on scheduled tickets and tickets waiting for dependencies (not queued ones), and runs templates your code defined and the server stored. It cannot fix a running ticket, and a template run is only as safe as the workflows it starts. It is the first thing cut if the dashboard milestone slips.

  22. A changed template under the same version is not picked up.

    If your code registers a different declaration under a version string it already registered, qlane warns and keeps the stored one, so runs started from the dashboard use the old declaration until you register a new version string.

  23. The correlation id only travels through qlane.

    A call your step makes to another system carries the id only if your code passes it on. The id is not hidden or redacted, so it must not hold personal data.

  24. A dropped stream is counted, not billed exactly.

    When a stream breaks, qlane counts the tokens that reached the worker (or the reserved maximum if the amount is unknown) as spent before it retries. That is what qlane saw, not the provider's invoice, which can differ.

  25. Out-of-quota answers depend on each provider's codes.

    qlane treats an out-of-quota answer as its own class and does not retry it. Which answers count is decided by a per-provider code table, built from each provider's own documentation and configurable. A quota answer in a form the table does not list would not be recognized as this class. With one alert per provider, the alert is deduplicated but the requests are not: every ticket that tries still makes its own call and stops.

  26. A cache hit is not a fresh answer.

    The optional result cache returns an answer saved earlier. At a temperature above 0 that changes behavior compared with a new call, which is why it is off by default and needs a maximum age. It stores the model's answer only, not tool results, and it needs an exact pinned model version when the model is an alias, it saves nothing when the provider returns no model version string or one that differs from the pinned version, and is not the provider's prompt-caching discount.

  27. Provider request ids match invoices only when the provider gives one.

    Calls that return no id are matched by time, model and cost, and invoice totals can still differ.

  28. Caps can count a little too much after a crash.

    A call that had started when its worker died stays charged against the cap until its step settles or a person releases it, because the provider may have billed it. The cap is per ticket or step with partial results kept, not per API key, and it works alongside a gateway such as LiteLLM or Portkey rather than replacing one.

  29. A retry sends the same effect key.

    So an effect is not repeated by a retry. A tool that replays a stored failure for a reused key will replay it, and a custom key is the way to get a fresh one. A retried parent finds its existing children by key.

  30. Compensation is effect-specific and can be wrong.

    It runs only when a person or an API call asks, it is itself an effect that can end unknown, and there is no saga engine.

  31. A restart is not counted as a crash.

    A lease that expires while the server is down or stalled is not counted as lost, so a poison ticket can take longer to reach its limit after a restart.

  32. Bundled prices are dated and hand-copied.

    qlane warns when the bundled price table is stale, never fetches prices at run time, and the prices are not verified by a test.

  33. The circuit breaker counts retryable errors only.

    An out-of-quota stop has its own alert and does not trip it. A rate-limit flood can both shrink the learned limit and trip the breaker. Held tickets wait in the queue.

  34. Performance is not the pitch.

    No speed claim is made. If measurements later show qlane is not fast, it will say so rather than compete on speed.

  35. Disk encryption is your host's job.

    qlane would offer optional field-level encryption for marked fields. It does not encrypt your disk.

  36. No security review yet.

    No formal security review or outside audit has happened. There is no code to review.

If something here is wrong or unclear, please tell hello@haldara.com.