Altinn/altinn-studioGitHubLast refreshed Oct 3, 2026
This is a public, read-only report. Striff reads this repository's docs, turns each sentence that makes a claim about the code into a rule, and checks the rule against the code on the default branch. How this works
Names these docs write that the code no longer has2
Each sentence below names a type the default branch doesn't declare, or declares somewhere else. Edit the doc so it matches the code, or bring the type back.
GoneSaveProcessStateToStorage
**Enqueue-at-commit, one workflow per side effect.** A critical EnqueueSideEffectsWorkflow step runs immediately after SaveProcessStateToStorage and enqueues the side-effect commands as **separate single-step sibling workflows — one per side effect** — submitted as one atomic batch, where each sibling is:
The repository once held src/App/backend/src/Altinn.App.Core/Internal/WorkflowEngine/Commands/SaveProcessStateToStorage.cs. It doesn't now.
**Prerequisites shipped separately** (each valuable alone): AppCommand passes the HTTP status code into ExecutionResult so app-callback error entries carry it (today only WebhookCommand does), and the retry delay calculation gains jitter so retry waves de-synchronize with or without a breaker.
AppCommand depends on ExecutionResult
Holds
Read Oct 2
**Prerequisites shipped separately** (each valuable alone): AppCommand passes the HTTP status code into ExecutionResult so app-callback error entries carry it (today only WebhookCommand does), and the retry delay calculation gains jitter so retry waves de-synchronize with or without a breaker.
WebhookCommand depends on ExecutionResult
Holds
Read Oct 2
A task that does one thing implements IServiceTask and only writes Execute;
IServiceTask has Execute
Holds
Read Oct 2
a task with more than one durable step implements IPipelineServiceTask and composes its pipeline in Define:
IPipelineServiceTask has Define
Holds
Read Oct 2
A composition is zero or more Stage(...) calls and HandleReplies(...) handlers, in any order, ended by exactly one terminal — Finally(...) for work that finishes by itself or by polling, or ConcludeOnReplies(...) for work answered by a message.
ServiceTaskPipelineBuilder has a Stage method
Holds
Read Oct 2
A composition is zero or more Stage(...) calls and HandleReplies(...) handlers, in any order, ended by exactly one terminal — Finally(...) for work that finishes by itself or by polling, or ConcludeOnReplies(...) for work answered by a message.
ServiceTaskPipelineBuilder has a Finally method
Holds
Read Oct 2
**Every stage may be retried on failure, so its work MUST be idempotent.** Use ServiceTaskContext.StepId as the idempotency key for an outbound call the stage must not repeat — it is stable across retries of the same step and covers the crash window between sending and completing.
ServiceTaskStageResult has a FailedPermanent method
Holds
Read Oct 2
The total wait is bounded by ProcessStepOptions.WaitBudget (or the engine default);
ProcessStepOptions has WaitBudget
Holds
Read Oct 2
Read ServiceTaskContext.Wait (DeferCount, StartedAt, Deadline, and the derived Remaining/IsFinalCheck) to pace the wait or give up early with a message that names what never arrived.
ServiceTaskContext has Wait
Holds
Read Oct 2
Id is the reply address, Deadline is when the mailbox stops accepting answers.
ServiceTaskMailbox has Id
Holds
Read Oct 2
Id is the reply address, Deadline is when the mailbox stops accepting answers.
ServiceTaskMailbox has Deadline
Holds
Read Oct 2
MailboxOptions.Timeout runs from the mint, and the deadline is absolute — no message re-arms it.
MailboxOptions has Timeout
Holds
Read Oct 2
the stage members, plus Conclude(ServiceTaskResult) for the send whose failure already settles the task — a recipient address that does not exist — where waiting out the exchange would only delay the same verdict.
ServiceTaskOpeningStageResult has a Conclude method
Holds
Read Oct 2
ConcludeOnReplies(handle, onMessage, onClosed) — the exchange the task **ends** on.
ServiceTaskPipelineBuilder has a ConcludeOnReplies method
Holds
Read Oct 2
HandleReplies(handle, onMessage, onClosed) — an exchange the pipeline **carries on past**.
ServiceTaskPipelineBuilder has a HandleReplies method
Holds
Read Oct 2
the channel that receives it (a queue subscriber, a webhook endpoint) reads the echoed mailbox id and calls ForwardReply(mailboxId, serviceTaskType, payload, idempotencyKey), doing no work of its own beyond decoding enough to forward.
IServiceTaskReplyForwarder has a ForwardReply method
Holds
Read Oct 2
FiksArkivServiceTask publishes the mailbox id as the outbound message's klientKorrelasjonsId, and FiksArkivSubscriber.IncomingMessageListener reads the echo, decrypts, and forwards.
FiksArkivSubscriber has IncomingMessageListener
Holds
Read Oct 2
It contains common properties such as Id, Type, DataModelBindings, and TextResourceBindings.
BaseComponent has Id
Holds
Read Oct 2
It contains common properties such as Id, Type, DataModelBindings, and TextResourceBindings.
BaseComponent has Type
Holds
Read Oct 2
It contains common properties such as Id, Type, DataModelBindings, and TextResourceBindings.
BaseComponent has DataModelBindings
Holds
Read Oct 2
It contains common properties such as Id, Type, DataModelBindings, and TextResourceBindings.
BaseComponent has TextResourceBindings
Holds
Read Oct 2
The CommandRegistry maps type strings to ICommand singletons.
CommandRegistry depends on ICommand
Holds
Read Oct 2
The engine stores it as the step's StateOut, and each step's StateOut becomes the next step's StateIn:
Step has StateOut
Holds
Read Oct 2
Step marked Failed with error details recorded in ErrorHistory
Step has ErrorHistory
Holds
Read Oct 2
command.waitBudget (default EngineSettings.DefaultStepWaitBudget = 24h, rejected at enqueue above MaxStepWaitBudget = 14d) caps total waiting, measured from the step's **first** deferral (Step.FirstDeferredAt, persisted), so it survives restarts and re-fetches.
EngineSettings has DefaultStepWaitBudget
Holds
Read Oct 2
command.waitBudget (default EngineSettings.DefaultStepWaitBudget = 24h, rejected at enqueue above MaxStepWaitBudget = 14d) caps total waiting, measured from the step's **first** deferral (Step.FirstDeferredAt, persisted), so it survives restarts and re-fetches.
EngineSettings has MaxStepWaitBudget
Holds
Read Oct 2
A command reads DeferCount from CommandExecutionContext.Step and WaitDeadline from the context itself, so it can back off its own cadence adaptively — or give up early, deliberately, instead of being failed anonymously when the budget expires.
CommandExecutionContext has Step
Holds
Read Oct 2
A command reads DeferCount from CommandExecutionContext.Step and WaitDeadline from the context itself, so it can back off its own cadence adaptively — or give up early, deliberately, instead of being failed anonymously when the budget expires.
CommandExecutionContext has WaitDeadline
Holds
Read Oct 2
EngineSettings.MaxMailboxTimeout caps it — the derivation is written on the setting itself and pinned by CallbackTokenLifetimeInvariantTests.
EngineSettings has MaxMailboxTimeout
Holds
33 rules from 4 docs
See these where the change is. The browser extension puts a pull request's doc findings, and a diagram of what it changed, on the GitHub page itself, so the code and what your docs say about it are side by side.