Skip to content

Verified: Sequential Function Chart

Each claim the Sequential Function Chart page makes, with the tests that prove it in the last green CI run: 44 of 45 verified. The claims live in docs/claims/sfc.yaml.

Last green CI run 16 Oct 2026, 14:48 UTC on c7618d3 · all runtime claims

SFC-001 verified

An SFC program is a .sfc file: an ST POU whose body is an SFC ... END_SFC block written with INITIAL_STEP, STEP, TRANSITION and ACTION.

where the docs say so

SFC-002 verified

A chart has exactly one INITIAL_STEP, active on the first scan; no initial step, or more than one, is an error.

where the docs say so

  • pass TestCheckMissingInitialStep in lang/sfc
  • pass TestCheckMultipleInitialSteps in lang/sfc
  • pass TestConformance/sfc-sim-div-conv/the initial token waits in Idle in lang/conformance
  • pass TestConformance/sfc-sim-div-conv/divergence activates every target in the same scan and clears the source in lang/conformance

SFC-003 verified

Each step owns a retained BOOL Step.X and an elapsed time Step.T; both are legal in conditions and action bodies.

where the docs say so

  • pass TestConformance/sfc-step-t in lang/conformance (6 of 6 passed)
  • pass TestCheckKnownStepXTRefIsClean in lang/sfc
  • pass TestStepTimerGatesTransition in lang/sfc
  • pass TestStepXRetainedAndStepTInBody in lang/sfc

SFC-004 verified

FROM and TO take one step or a parenthesised list, and the transition name is optional.

where the docs say so

  • pass TestParseSimultaneousDivergenceConvergence in lang/sfc
  • pass TestParseAlternativeDivergence in lang/sfc

SFC-005 verified

An association's IEC form XV201A_Cmd(N); or XV201A_Cmd(D, T#3S); is read as the same association as the keyword form; an omitted qualifier is N.

where the docs say so

  • pass TestIECAssociationForm in lang/sfc

SFC-006 verified

Each scan runs one fixed-order pass: evaluate each transition against the pre-scan activity snapshot, resolve which fire, clear the sources, set the targets, update step timers, compute actions.

where the docs say so

  • pass TestScanTrace in lang/sfc
  • pass TestEnabledNotCondGuard in lang/sfc
  • pass TestScanOrderOneFixedPass in lang/sfc
  • pass TestStepTimerStartsOnActivationScan in lang/sfc

SFC-007 verified

Every transition reads the same snapshot, so a token advances at most one step per scan, though several transitions can fire in one scan when several tokens are live.

where the docs say so

  • pass TestConformance/sfc-alt-priority/the token advances one step per scan (X to Idle to X again) in lang/conformance
  • pass TestConformance/sfc-sim-div-conv/a single token returns and the whole chart is reusable in lang/conformance

SFC-008 verified

Clears run before sets, so a self-loop FROM S TO S leaves S active.

where the docs say so

  • pass TestConformance/sfc-jump-back/a self-loop leaves the step active and does not re-fire its entry pulse in lang/conformance
  • pass TestSetDominatesClear in lang/sfc

SFC-009 verified

A transition is enabled when all its FROM steps are active and its condition is true.

where the docs say so

  • pass TestEnabledNotCondGuard in lang/sfc
  • pass TestConformance/sfc-sim-div-conv/convergence does not fire until every source is active in lang/conformance
  • pass TestConformance/sfc-alt-priority/with no condition true the token waits in Idle in lang/conformance

SFC-010 verified

Alternative divergence: transitions sharing a source step are prioritised by declaration order, first highest.

where the docs say so

  • pass TestConformance/sfc-alt-priority in lang/conformance (8 of 8 passed)
  • pass TestAltPriorityMutualExclusion in lang/sfc
  • pass TestAltDivergenceAbort in lang/sfc
  • pass TestConformance/sfc-jump-back/the jump back outranks the exit declared after it in lang/conformance

SFC-011 verified

A lower branch is suppressed only when a higher one sharing a source actually fires, so a convergence waiting on an inactive source cannot deadlock the branch below; overlapping groups resolve to one outcome per scan.

where the docs say so

  • pass TestConformance/sfc-alt-priority/a dead convergence declared first does not starve the branches below it in lang/conformance
  • pass TestSuppressedOnlyByFiringTransition in lang/sfc
  • pass TestNonTransitiveGroupConvergenceFires in lang/sfc

SFC-012 verified

Simultaneous divergence (TO (Heat, Mix)) sets both targets in one scan and splits the token; simultaneous convergence (FROM (Heat, Mix)) is enabled only when both sources are active.

where the docs say so

SFC-013 verified

Every IEC action qualifier compiles: N, S, R, P1, P, P0 and the timed L, D, SD, DS, SL.

where the docs say so

  • pass TestTimedQualifiersParseAndCheckClean in lang/sfc
  • pass TestConformance/sfc-qualifiers in lang/conformance (8 of 8 passed)
  • pass TestConformance/sfc-timed-qualifiers in lang/conformance (13 of 13 passed)

SFC-014 verified

N is active exactly while the step is.

where the docs say so

  • pass TestConformance/sfc-qualifiers/N is high exactly while the step is active in lang/conformance
  • pass TestNDrivesOnlyWhileActive in lang/sfc

SFC-015 verified

S sets the target and R clears it, each once, on the scan their step activates.

where the docs say so

  • pass TestConformance/sfc-qualifiers/S sets once and the chart never clears it in lang/conformance
  • pass TestConformance/sfc-qualifiers/R clears once on activation in lang/conformance
  • pass TestSetActsOnceThenActionMayClear in lang/sfc
  • pass TestResetActsOnceThenActionMaySet in lang/sfc

SFC-016 verified

P1 and P fire once on the rising edge of step activity; P0 fires once on the falling edge.

where the docs say so

  • pass TestConformance/sfc-qualifiers/P1 and P are one scan wide on the rising edge, and fire once per entry in lang/conformance
  • pass TestConformance/sfc-qualifiers/P0 fires on the falling edge only, once, after the step has been left in lang/conformance
  • pass TestConformance/sfc-qualifiers/every re-entry re-fires P1 and P (P0 counts only its own exits) in lang/conformance
  • pass TestP1FiresOncePerActivation in lang/sfc

SFC-017 verified

Timed qualifiers take a duration (a TIME literal or a TIME variable); each association gets its own timer, started when its step activates.

where the docs say so

  • pass TestConformance/sfc-timed-qualifiers in lang/conformance (13 of 13 passed)
  • pass TestTimedLoweringStableSlots in lang/sfc
  • pass TestTimedQualifierTimeVariableDuration in lang/sfc

SFC-018 verified

L is active from activation for the duration (ending early if the step is left first); D is active once the step has been active for the duration and ends when the step is left.

where the docs say so

  • pass TestConformance/sfc-timed-qualifiers/the activation scan — L and SL on, the delayed ones not yet in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/the scan before PT — nothing has changed in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/the scan at PT — L and SL drop, D SD DS rise, the L body runs its final scan in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/leaving before PT — L is cut short, D and DS never come on, SD and SL run on stored in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/after the step leaves — D drops, the stored SD and DS hold in lang/conformance

SFC-019 verified

SD turns on the duration after activation even if the step was left meanwhile; DS turns on once the step has been active for the duration (never, if left sooner); SL runs from activation for the duration, even after the step is left; all three end at an R on the same target.

where the docs say so

  • pass TestConformance/sfc-timed-qualifiers/the scan before PT — nothing has changed in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/the scan at PT — L and SL drop, D SD DS rise, the L body runs its final scan in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/leaving before PT — L is cut short, D and DS never come on, SD and SL run on stored in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/R resets the stored qualifiers in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/R before PT cuts SL short and stops SD from ever coming on in lang/conformance

SFC-020 verified

An R acts once, on its step's activation scan, and clears the SD, DS and SL latches on its target as well as an S; an SL that has run its time stays latched and does not run again on re-activation until an R clears it.

where the docs say so

  • pass TestConformance/sfc-timed-qualifiers/re-entry restarts L and D; a timed-out SL stays off until an R in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/after an R, SL arms again on the next activation in lang/conformance
  • pass TestConformance/sfc-timed-qualifiers/R resets the stored qualifiers in lang/conformance
  • pass TestResetActsOnceThenActionMaySet in lang/sfc
  • pass TestConformance/sfc-timed-qualifiers/R acts once on its step's activation, not on every scan the step is active in lang/conformance

SFC-021 verified

N, pulse and timed associations targeting the same BOOL are OR-combined: the variable is held TRUE while any is active and written FALSE once, on the scan the last one drops.

where the docs say so

  • pass TestTranspileShape in lang/sfc
  • pass TestAssociationsOROnOneVariable in lang/sfc

SFC-022 verified

An association writes its variable only on the scans it acts; an inactive step never touches it, and between those scans the variable belongs to whoever else writes it.

where the docs say so

  • pass TestNFreeWhenInactive in lang/sfc
  • pass TestResetOnInactiveStepDoesNotClobberActionWrite in lang/sfc
  • pass TestSFCResetOnInactiveStepKeepsActionWrite in acceptance

SFC-023 verified

When an ACTION body assigns the same variable, the association wins while it acts (it is applied after the bodies in the scan); the ACTION owns it the rest of the time, so an R X on an abort step and an ACTION that sets X on a normal step coexist.

where the docs say so

  • pass TestSetActsOnceThenActionMayClear in lang/sfc
  • pass TestResetActsOnceThenActionMaySet in lang/sfc
  • pass TestNDrivesOnlyWhileActive in lang/sfc
  • pass TestSFCResetOnInactiveStepKeepsActionWrite in acceptance
  • pass TestAssociationBeatsActionWrite in lang/sfc (5 of 5 passed)

SFC-024 verified

naut check warns on every association/ACTION-body pair that assigns the same variable.

where the docs say so

  • pass TestCheckAssocVsActionWrite in lang/sfc
  • pass TestCheckAssocVsActionWriteN in lang/sfc
  • pass TestCheckTimedAssocVsActionWrite in lang/sfc
  • pass TestCheckAssocVsActionWriteEveryQualifier in lang/sfc

SFC-025 verified

An action body driven by a level qualifier (any but the pulses; a timed window is a level) runs one extra scan on the falling edge of its active signal, so a body written against step activity shuts its outputs down (a TON called with Hold.X resets). A P1 body has no final scan.

where the docs say so

  • pass TestConformance/sfc-final-scan in lang/conformance (5 of 5 passed)
  • pass TestFinalScanResetsTON in lang/sfc
  • pass TestConformance/sfc-timed-qualifiers/the scan at PT — L and SL drop, D SD DS rise, the L body runs its final scan in lang/conformance
  • pass TestActionBodyFinalScanEveryLevelQualifier in lang/sfc (6 of 6 passed)

SFC-026 verified

Step.T is the step's elapsed time, how long it has been active, and can be read in an ACTION or a condition (Fill.T >= T#3S).

where the docs say so

SFC-027 verified

Step.T compiles to a hidden TON only for steps whose .T is read.

where the docs say so

  • pass TestUnreadStepTimerHasNoHiddenTON in lang/sfc

SFC-028 verified

A step supervised with (MAXTIME := T#..) sets its Step.ERR flag one scan after Step.T reaches the limit (active longer than MAXTIME); within the limit nothing is flagged.

where the docs say so

  • pass TestConformance/sfc-step-maxtime/within the limit nothing is flagged in lang/conformance
  • pass TestConformance/sfc-step-maxtime/the scan the step overruns sets the flag; the abort fires the scan after in lang/conformance
  • pass TestConformance/sfc-step-maxtime/leaving in time never sets the flag in lang/conformance
  • pass TestConformance/sfc-step-maxtime/the step's time does not run while it is inactive in lang/conformance

SFC-029 verified

Step.ERR stays set after the step is left, so an abort step can read the cause, and clears on the step's next activation; nothing else happens automatically.

where the docs say so

  • pass TestConformance/sfc-step-maxtime/the flag holds after the step is left, until Fill runs again in lang/conformance
  • pass TestStepOverrunDoesNothingElse in lang/sfc

SFC-030 verified

ERROR := Var names a BOOL variable that mirrors Step.ERR every scan, and an alarm definition bound to that tag annunciates the overrun.

where the docs say so · The sfc-step-maxtime fixture asserts the mirrored tag and the FillOverrun alarm lifecycle (active, unack-rtn, ack).

  • pass TestConformance/sfc-step-maxtime/the scan the step overruns sets the flag; the abort fires the scan after in lang/conformance
  • pass TestConformance/sfc-step-maxtime/the flag holds after the step is left, until Fill runs again in lang/conformance
  • pass TestConformance/sfc-step-maxtime/leaving in time never sets the flag in lang/conformance

SFC-031 verified

MAXTIME takes a TIME literal; a bad step attribute (non-TIME MAXTIME, ERROR not a declared variable, ERROR without MAXTIME) and Step.ERR on a step with no MAXTIME are errors.

where the docs say so

  • pass TestCheckStepAttributes in lang/sfc

SFC-032 verified

naut check structural errors: duplicate step, action or transition names; no or more than one INITIAL_STEP; FROM/TO naming a missing step; an empty condition.

where the docs say so

  • pass TestCheckDuplicateStepName in lang/sfc
  • pass TestCheckDuplicateActionName in lang/sfc
  • pass TestCheckDuplicateTransitionName in lang/sfc
  • pass TestCheckMissingInitialStep in lang/sfc
  • pass TestCheckMultipleInitialSteps in lang/sfc
  • pass TestCheckUnknownFromTo in lang/sfc
  • pass TestCheckEmptyCondition in lang/sfc
  • pass TestCheckSFCDiagnostics/duplicate step in cmd/naut
  • pass TestCheckSFCDiagnostics/duplicate action in cmd/naut
  • pass TestCheckSFCDiagnostics/duplicate transition in cmd/naut
  • pass TestCheckSFCDiagnostics/no initial step in cmd/naut
  • pass TestCheckSFCDiagnostics/two initial steps in cmd/naut
  • pass TestCheckSFCDiagnostics/FROM missing step in cmd/naut
  • pass TestCheckSFCDiagnostics/TO missing step in cmd/naut
  • pass TestCheckSFCDiagnostics/empty condition in cmd/naut

SFC-033 verified

naut check structural errors: an association naming neither an ACTION nor a declared variable; a .X/.T reference to an unknown step.

where the docs say so

  • pass TestCheckUnresolvedActionAssociation in lang/sfc
  • pass TestCheckActionAssociationResolvesToVariable in lang/sfc
  • pass TestCheckUnknownStepXTRef in lang/sfc
  • pass TestCheckUnknownStepTRef in lang/sfc
  • pass TestCheckSFCDiagnostics/association to nothing in cmd/naut
  • pass TestCheckSFCDiagnostics/unknown step X ref in cmd/naut
  • pass TestCheckSFCDiagnostics/unknown step T ref in cmd/naut

SFC-034 verified

naut check structural errors: an unknown qualifier (the message lists every supported one and the Step.T recipe); a timed qualifier with no duration, or an untimed one given one.

where the docs say so

  • pass TestCheckUnsupportedQualifier in lang/sfc
  • pass TestCheckQualifierDiagnostics in lang/sfc
  • pass TestCheckTimeArgumentOnUntimedQualifierIsAnError in lang/sfc
  • pass TestCheckSFCDiagnostics/unknown qualifier in cmd/naut
  • pass TestCheckSFCDiagnostics/timed qualifier without duration in cmd/naut
  • pass TestCheckSFCDiagnostics/untimed qualifier with duration in cmd/naut

SFC-035 verified

naut check warns on an unreachable non-initial step and on a dead-end step (a terminal step may be one on purpose).

where the docs say so

  • pass TestCheckUnreachableStepWarns in lang/sfc
  • pass TestCheckDeadEndStepWarns in lang/sfc
  • pass TestCheckSFCDiagnostics/unreachable step in cmd/naut
  • pass TestCheckSFCDiagnostics/dead-end step in cmd/naut

SFC-036 verified

naut check warns on a simultaneous convergence whose sources are not reachable from a common simultaneous divergence, and not otherwise.

where the docs say so

  • pass TestCheckConvergenceUnreachableWarns in lang/sfc
  • pass TestCheckConvergenceReachableIsClean in lang/sfc
  • pass TestCheckSFCDiagnostics/convergence from alternative branches in cmd/naut
  • pass TestCheckSFCDiagnostics/convergence from a simultaneous divergence in cmd/naut

SFC-037 verified

The chart transpiles to ST and compiles like any program; the line map puts a type error in a condition on its TRANSITION line and one in an action body on the offending statement's own line inside the ACTION block.

where the docs say so

  • pass TestTranspileShape in lang/sfc
  • pass TestCheckSFCTypeErrorLines/condition in cmd/naut
  • pass TestCheckSFCTypeErrorLines/action body in cmd/naut

SFC-038 verified

Step activity, stored flags, pulse edge memories, step timers, timed-qualifier timers and latches, and overrun flags are retained, so an online edit preserves the live token and every timer.

where the docs say so · TestWarmMigration/timers-latches-pulses migrates a chart with ir.MigrateFrame (what SwapWarm runs): the token, Step.T, the MAXTIME flag, the S latch, the P edge memory and the D and SL timers and latch all carry and keep running on the edited program.

  • pass TestWarmMigration in lang/sfc (4 of 4 passed)

SFC-039 verified

Renaming a step resets its token (the renamed step's slot is a new name), listed in the swap report.

where the docs say so · Renaming the active step leaves the renamed step inactive and lists its token in the migration's resets.

  • pass TestWarmMigration/renamed-step-resets in lang/sfc

SFC-040 verified

naut test runs the same *_test.yaml acceptance tests on an SFC program in virtual time.

where the docs say so

SFC-041 verified

Macro steps and charts nested inside a step are not supported; charts are flat.

where the docs say so

  • pass TestCheckRejects/SFC macro step in cmd/naut
  • pass TestCheckSFCNotSupported/step nested in a step in cmd/naut
  • pass TestCheckSFCNotSupported/chart nested in a step in cmd/naut

SFC-042 verified

Explicit numeric transition priorities are not supported; priority is declaration order.

where the docs say so

  • pass TestConformance/sfc-alt-priority/with every condition true the first declared branch wins alone in lang/conformance
  • pass TestCheckSFCNotSupported/numeric priority after TO in cmd/naut
  • pass TestCheckSFCNotSupported/numeric priority attribute in cmd/naut

SFC-043 verified

Instruction List action bodies are not supported; action bodies are ST.

where the docs say so

  • pass TestCheckRejects/SFC IL action in cmd/naut

SFC-044 verified

Indicator variables in an association (Valve(N, Ind);) and on transitions are rejected, and naut check names the forms it does take.

where the docs say so

  • pass TestIECAssociationForm in lang/sfc
  • pass TestParseErrors/indicator on a transition in lang/sfc
  • pass TestCheckSFCNotSupported/indicator in an association in cmd/naut
  • pass TestCheckSFCNotSupported/indicator on a transition in cmd/naut

SFC-045 partly verified

Import of vendor SFC (Rockwell .L5X routines, Siemens GRAPH, CODESYS) is not supported.

where the docs say so · A Logix SFC routine in an L5X is refused by the ladder import, which names it as skipped (Seq/Chart (SFC)). There is no Siemens GRAPH or CODESYS importer in the codebase (the siemens and codesys dialects are reserved names only), so those two clauses hold by absence and have no test.

  • pass TestVendorSFCRoutineIsRefused in lang/l5x