Publication note. The application captures in this article contain demonstration and test data, not real customer, member, patient, claim, provider, user, or production-record information. Environment, host, database, and server identifiers were removed where present.
The Architectural Problem
Long-running enterprise work rarely fits a single status column. A claim can be received, reviewed, adjudicated, paid, appealed, reopened, and archived. Some of those facts describe the present; others describe a durable milestone. Several tracks can advance independently. What a user may do next depends on a combination of facts rather than one enumerated state name.
An enumerative state machine attempts to name every valid combination. With n independent Boolean statuses, however, the potential state space contains 2n combinations. Even a modest catalogue quickly makes a hand-authored graph incomplete, repetitive, and difficult to govern.
The I.T.S. Framework takes the opposite approach:
- Define a finite catalogue of meaningful statuses.
- Represent an entity's current state as the subset of those statuses currently true.
- Define actions as transformations that assert some statuses and retract others.
- Define applicability as predicates over the current state and relevant related states.
- Store the declarations as data and let the framework compile and execute them.
The engine does not know what Approved, Archived, or Carrier Paid means. It knows how to evaluate sets, guards, and transformations. Business meaning remains in configuration.
Operating Context and Architectural Boundary
The production I.T.S. Framework desktop runtime and its desktop modules target .NET 10 for Windows. The stack includes Windows Forms, ADO.NET, DataSet/DataRow, and SQL Server 2025. The database is the authoritative contract; the WinForms interface binds directly to relational runtime objects and obtains workflow configuration through the shared data runtime.
Deployments can run on premises, in a private cloud, or on AWS or Azure. SQL Server can be local, hosted on a cloud virtual machine, or supplied through a managed cloud database service when its latency, integration, security, operational, and feature-compatibility characteristics fit the deployment.
In the principal operating model, application servers remain close to SQL Server and users connect through RDP or RDS. The remote client receives pixels. The internal desktop architecture therefore does not require an HTTP/JSON boundary between every WinForms module and the database.
The Formal State Space
Fix one workflow W. Let its status universe be the finite set
UW = {u0, u1, …, un-1}, 0 ≤ n ≤ 63.A workflow state is a subset of that universe:
S(W) = ℘(UW) ≅ {0,1}n.The set reading and the vector reading describe the same object. In the set reading, a status is either a member of the current state or it is not. In the vector reading, the statuses are the multiple Boolean dimensions of the state space, and each individual status supplies one coordinate:
s = (b0, b1, …, bn-1), bi ∈ {0,1}.A status is therefore not an enumerated name for the entire state. It is one independent dimension along which that state can vary. The complete state is the multidimensional Boolean vector formed by all status coordinates in the selected typed universe.
| Reading | Formal object | Framework representation |
|---|---|---|
| Set | s ⊆ UW | The named statuses currently true |
| Vector | s ∈ {0,1}n | The individual bits of flg |
| Scalar encoding | φW(s) | One nonnegative BIGINT |
The potential state space contains 2n combinations. That is not the same as saying every combination is reachable. Initial conditions, mutual-exclusion rules, guards, and the configured action catalogue determine a reachable subset RW ⊆ S(W). This distinction matters: the algebra defines what can be represented; configuration defines what the deployed process can actually produce.
flg represents the statuses currently true. It is not the complete historical record. The append-only log and the monotonic acc_flg field preserve history separately.Encoding State as One Integer
Assign each status ui a stable bit index i. The encoding is
φW(s) = Σi=0n-1 χs(ui) · 2i,with φW : ℘(UW) → {0,1,…,2n-1}.
Here χs is the indicator function: it returns 1 when the status belongs to the state and 0 otherwise. The codomain is the interval of representable masks, not all integers. Within that interval, the encoding is bijective: every subset has exactly one mask and every valid mask decodes to exactly one subset.
More precisely, φW is an isomorphism between the Boolean algebra of subsets and the algebra of n-bit masks under bitwise operations:
| Set operation | Mask operation | Meaning |
|---|---|---|
| s ∪ t | s | t | Statuses present in either set |
| s ∩ t | s & t | Statuses present in both sets |
| s \ t | s & ~t | Statuses in s but not t |
| m ⊆ s | (s & m) = m | The state contains every required bit |
| s ∩ m ≠ ∅ | (s & m) > 0 | The state contains at least one selected bit |
The cost of each mask expression is bounded by a small, fixed number of scalar operations; it does not grow with the number of set bits inside the mask. That does not make an entire SQL query constant-time. Row count, joins, memory, I/O, cardinality estimation, and access paths still determine query cost.
The complement requires a universe
Set complement is always relative to UW. A SQL Server BIGINT has 64 physical bits, while a valid workflow uses only indices 0 through 62. Therefore ~m by itself flips bits outside the workflow universe and may produce a negative integer. Expressions such as s & ~r remain safe because s contains only valid state bits; a standalone complement must be intersected with the workflow's universe mask.
Index and value are different contracts
| Value | Purpose | Example |
|---|---|---|
ix | Readable, stable bit position used while authoring | 39 |
flg | Computed value used by the runtime | 549755813888 |
CASE
WHEN [ix] > 62 THEN -1
ELSE POWER(CONVERT(BIGINT, 2), [ix])
END
ITS_MLWFFlg.flg is computed from ix, so the authoring index and runtime value cannot drift independently.
1546 has
bits 1, 3 and 9 raised: it has been reviewed, approved and archived.Actions as Guarded State Operators
An action declares two sets: statuses to assert, a, and statuses to retract, r. Its state operator is
T(a,r)(s) = (s \ r) ∪ a≅
(s & ~r) | a.
An action is therefore an assert/retract status operator over a typed state universe. Its masks identify the status dimensions to make true and the dimensions to make false; they do not replace the state with one enumerated label.
The operator T(a,r) is a total function on the representable state space. The business transition is not necessarily total, because the action may be legal only when a guard holds. With guard g, the configured transition is the partial function
τ(a,r,g)(s) = T(a,r)(s) when g(s)=true;τ(a,r,g)(s) is undefined otherwise.
This separation is fundamental. The operator answers what would the state become? The guard answers may this operator be applied here? Confusing effect with restriction is one of the most dangerous configuration errors in a workflow engine.
Current state s
|
v
Evaluate guard g(s) ---- false ----> refuse the action
|
true
|
v
Apply T(a,r) ----> new current state
Algebraic Properties and Their Limits
The closed form makes several properties provable rather than anecdotal.
Idempotence of the state transformation.
T(T(s)) = (((s \ r) ∪ a) \ r) ∪ a= (s \ r) ∪ (a \ r) ∪ a
= (s \ r) ∪ a = T(s).
No condition a ∩ r = ∅ is required. If the same bit appears in both masks, the final assertion wins and repeated application still reaches the same state.
This proves that repeating the pure state calculation makes no further state change. It does not prove that replaying an entire business action is harmless. Audit inserts, notifications, external calls, financial postings, and other side effects require their own transaction and idempotency controls.
Assertion dominates retraction. Within one operator, union is applied after difference. Therefore a bit present in both masks remains set:
a ∩ r ≠ ∅ ⇒ assertion wins on the overlap.This permits the useful form “clear every status in this exclusive group, then assert this one.” A canonical representation can normalize the retraction set to r \ a without changing the function.
Closure under composition. Applying T1 and then T2 still produces an operator from the same family:
T(a2,r2) ∘ T(a1,r1)= T(a',r'),
a'=(a1 \ r2) ∪ a2, r'=r1 ∪ r2.
A sequence can therefore be summarized by another assert/retract pair. Derived effects such as snflg can be folded into the retraction mask before execution without creating a richer operator type.
General non-commutativity, not universal non-commutativity. Some operators commute, but conflicting operators generally do not:
T2 ∘ T1 ≠ T1 ∘ T2 in general.If one action asserts a bit that another retracts, the last action normally determines that bit. Independent actions over disjoint status sets do commute. Because order can matter, the runtime preserves the transition sequence in an append-only log.
Monotonicity with respect to input state. For a fixed action, if s ⊆ t, then T(s) ⊆ T(t). Retraction and assertion do not reverse the subset order. A sequence can still appear to move “backward” in business terms because its configured retraction set can remove a progress status.
The Four Canonical Guard Polarities
The engine's guard grammar combines four quantified relationships between current state s and a configured mask m:
| Clause | Set form | Mask form | Reads as |
|---|---|---|---|
| Require all | m ⊆ s | (s & m) = m | Must have every selected status |
| Require any | s ∩ m ≠ ∅ | (s & m) > 0 | Must have at least one |
| Forbid any | s ∩ m = ∅ | (s & m) = 0 | Must have none |
| Forbid all | m ⊈ s | (s & m) ≠ m | Must be missing at least one |
IF (@sflg <> 0 AND (@flg & @sflg) <> @sflg) RETURN 0; -- require all
IF (@soflg <> 0 AND (@flg & @soflg) = 0) RETURN 0; -- require any
IF (@snflg <> 0 AND (@flg & @snflg) <> 0) RETURN 0; -- forbid any
IF (@sonflg <> 0 AND (@flg & @sonflg) = @sonflg) RETURN 0; -- forbid all
The four clauses arise from two quantifiers—all and any—crossed with two polarities—require and forbid. A guard row can combine the clauses by conjunction.
The empty mask disables an optional clause
The empty set is not naturally true for every primitive. “Require any element of the empty set” is false. The engine therefore guards each optional branch with m <> 0. In the configuration language, zero means this clause is absent, so the enclosing guard treats it as neutral.
A precise expressiveness boundary
These clauses are complete for the engine's chosen four-polarity mask grammar. They are not functionally complete for every Boolean predicate over n bits. A condition such as “at least two of these three statuses,” exclusive-or, or an arbitrary disjunction of conjunctions cannot always be represented by one row containing four masks. Such requirements need multiple configured expressions, a composed group, a checklist, or a specialized validator.
Typed Workflows, Status Dimensions, and Threads
Each workflow owns a separate status universe. Reusing bit index 8 in two workflows does not make the statuses equivalent. The integer alone is therefore not the complete type of a state; the meaningful value is the pair (workflow_id, flg). The workflow_id selects the universe in which the mask must be interpreted.
Universes contain thread-specific spaces
Within one workflow universe UW, each thread j selects a set of status dimensions DW,j ⊆ UW. Those dimensions induce the thread's own Boolean state space:
S(W,j) = ℘(DW,j) ≅ {0,1}|DW,j|.The hierarchy is therefore explicit: the workflow identifies a typed universe; statuses supply its Boolean dimensions; and threads organize selected dimensions into distinct business spaces. Different workflow universes can contain different status catalogues and different collections of thread spaces.
When the configured threads form independent, disjoint tracks, their dimensions partition the workflow universe:
UW = DW,1 ⊎ DW,2 ⊎ … ⊎ DW,m,S(W) ≅ S(W,1) × S(W,2) × … × S(W,m).
If a deployment uses threads as overlapping classifications instead, each thread still identifies a valid subspace, but the product expression is no longer an independent decomposition. The configuration determines which interpretation applies.
Across independent workflows, the total application state is another typed Cartesian product:
Stotal = S(W1) × S(W2) × … × S(Wk).For finite Boolean spaces, direct-sum and product constructions are isomorphic, but “product of typed states” expresses the implementation more accurately: every universe retains its own catalogue, thread spaces, encoding, and identity. The framework defines no business comparison between equal numeric masks from different universes.
Threads provide a local progress coordinate
A thread can impose a configured step order over the status dimensions assigned to its space. The runtime may then derive a progress summary for thread DW,j:
This is an ordinal summary function, not a linear projection in the strict algebraic sense. Across several threads, progress becomes the tuple
pW(s) = (pW,1(s), pW,2(s), …, pW,m(s)).Two entities can therefore be ahead on different tracks without either being globally “farther along.” That partial ordering is the formal reason the framework does not force all workflow progress into one scalar.
The Schema as an Authoring Language
The physical engine is driven by two principal catalogues and a normalized authoring surface.
ITS_MLWFFlg: the status catalogue
| Column | Role |
|---|---|
workflow_id | Selects the typed status universe. |
ix | Stable bit index from 0 through 62. |
flg | Computed value 2ix. |
step | Optional ordinal position within a configured thread. |
step_thread | Identifies the track to which the status belongs. |
nflg | Statuses automatically retracted whenever this status is asserted. |
pplcbl* | Predicates that govern asserting this status. |
rmvpplcbl* | Predicates that govern retracting this status. |
ITS_MLWFActn: the operator catalogue
A row represents a reusable expression. Historical naming calls it an action, but its configured masks can be consumed as an effect, a guard, or a filter according to context.
| Column | Meaning | Role |
|---|---|---|
flg | Statuses explicitly asserted | Effect |
nflg | Statuses explicitly retracted | Effect |
snflg | Retractions derived from asserted statuses | Derived effect |
npflg | Negative propagation to related entities | Effect |
pplcblflg | Require all selected statuses | Applicability |
pplcblorflg | Require at least one selected status | Applicability |
pplcblnflg | Forbid every selected status individually | Applicability |
pplcblprvflg | Require statuses on a related or previous entity | Applicability |
pplcblprvnflg | Forbid statuses on a related or previous entity | Applicability |
chkflg | Require checklist items | Applicability |
chknflg | Forbid blocking checklist items | Applicability |
oflg | Filter rows that have all selected statuses | Query |
onflg | Filter rows that have none of the selected statuses | Query |
ITS_MLWFActnFlg: the normalized declaration
Administrators do not need to calculate decimal masks or decide which of thirteen columns receives a bit. They author normalized statements:
(actn_id, flg_ix, mode_id)
Example:
(Approve, Approved, Assert)
(Approve, Reviewed, Require all)
(Approve, Archived, Forbid any)
The action-flag compiler validates the declaration, routes it to the correct semantic role, and recomputes the denormalized masks used by the execution path. The wide mask row is therefore a compiled projection; the normalized rows are the authoring contract.
(action, bit, role);
the action-flag compiler validates the statement, routes it to the right column, and recomputes the
derived masks — including snflg (§9).
This distinction is what makes a collection of visually indistinguishable BIGINT columns governable. A naked integer has no semantic role. The normalized row supplies that role before compilation.
Three Roles for the Same Mask Vocabulary
The stem flg means “a set of statuses.” Prefixes describe how that set is interpreted. The same compact vocabulary participates in three different operations.
| Context | Positive mask | Negative mask | Result |
|---|---|---|---|
| Effect | Bits to assert | Bits to retract | A new state |
| Applicability | Statuses required | Statuses forbidden | Allowed or refused |
| Filter | Rows must have these | Rows must not have these | A selected work set |
Role 1: effect
new_flg = (old_flg & res_nflg) | actn_flg
res_nflg = ~(snflg | nflg)
actn_flg asserts statuses. snflg | nflg identifies statuses to retract. The engine inverts that retraction set into the preservation mask res_nflg, so one expression clears and sets bits.
Role 2: applicability
The pplcbl* columns feed the guard grammar. A positive mask can require all or any; a negative mask can forbid any or all. These expressions decide whether an operator is offered and whether execution is valid.
Role 3: filter
oflg and onflg select entities for a work queue. The predicate is mathematically the same kind of relation used by a guard; its result is lifted from one Boolean decision to a set of matching rows.
A mask has no complete meaning without its role. The value
256can mean “assert Denied,” “retract Denied,” “require Denied,” or “exclude Denied.” Establish the consumer before interpreting the number.
Groups as Binding Points
An action group is not merely a folder. It is a binding point that mounts reusable expressions on a particular surface. The consuming surface determines how the expression is read.
| Mounted on | Expression is consumed as |
|---|---|
| Command list or dropdown | A transition: apply assert and retract masks |
| Work queue or saved filter | A predicate: select matching entity states |
| Classifier or status display | A named interpretation of a state pattern |
| Composite group | A reusable part of a larger surface |
Security subscriptions intersect with group membership. An expression can exist, be valid for the current state, and still remain invisible because the effective security group does not grant access to the surface on which it is mounted.
This reuse is sometimes described as polymorphism. It is not language-level subtype polymorphism; it is controlled semantic reuse. A configured row supplies masks, and a typed consumer selects the operation those masks participate in.
Derived Effects and Status-Level Invariants
ITS_MLWFActn contains both nflg and snflg, but they have different ownership.
nflgis authored: the action explicitly retracts the selected statuses.snflgis derived: the statuses being asserted contribute their own configured retractions.
Suppose Approved and Rejected are mutually exclusive. The invariant belongs to the status catalogue, not to every action that might assert one of those statuses. If Approved.nflg contains Rejected, then every current or future action that asserts Approved automatically inherits the retraction.
The union symbol here means bitwise aggregation. The save procedure recomputes that union when declarations change. Action authors do not edit snflg directly.
Why the invariant belongs to the protected status
If every action had to repeat the exclusion rule, correctness would depend on remembering all existing actions and every future action. Attaching the invariant to the status that owns it changes the maintenance problem from “update every consumer” to “declare the rule once.”
Approved.nflg includes Rejected
|
+-- Approve action -----------+
+-- Supervisor Approve -------+-- derive the same retraction
+-- Batch Approve ------------+
+-- actions added years later +
Effect is not restriction
nflg is an effect. It means “when this status is asserted, retract those statuses.” It does not mean “refuse this status when those statuses are present.” Refusal belongs in an applicability mask or another validator. Confusing the two can remove data instead of producing an error.Evaluate real deltas
Status-level rules should be evaluated only for bits that actually change:
set_bits = a_flg & ~flg; -- off before, on after
rmv_bits = a_nflg & flg; -- on before, off after
Testing every bit named by a broad action would revalidate statuses that are already true or already absent. Delta evaluation aligns validation with the idempotent state operator: when a repeated operator changes no bit, there is no new status transition for a status-level rule to approve.
State, History, and Audit
The runtime preserves three related but distinct facts:
| Value | Meaning | Behavior |
|---|---|---|
flg | Statuses currently true | Can assert and retract bits |
acc_flg | Statuses that have ever been true | Monotonic; bits never clear |
| Log rows | Ordered transition history | Append-only sequence with actor, time, action, and resulting state |
The current state is calculated once inside the persistence statement:
INSERT INTO dbo.WorkflowEntityLog
(..., ltst, flg, acc_flg, actn_flg, actn_nflg, ...)
SELECT
...
,1
,E.flg
,E.flg | ISNULL(L.acc_flg, 0)
,A.flg
,A.res_nflg
,...
FROM ...
CROSS APPLY
(
SELECT (ISNULL(L.flg, 0) & A.res_nflg) | A.flg AS flg
) E;
ITS_ActnGet supplies the preservation mask already derived from explicit and status-level retractions. The persistence procedure therefore cannot accidentally apply nflg while omitting snflg.
The latest log row is marked with ltst = 1. The prior latest row is retired in the same transactional operation. Recording actn_flg and the effective preservation or retraction information allows an auditor to distinguish two transitions that happen to produce the same final mask.
flganswers “where is the entity now?”acc_flganswers “which milestones has it ever reached?” The log answers “in what order, by whom, and through which configured actions did it move?”
ltst = 1 row is the present; every other row is
the audit trail.Related Video: The Runtime Log in Motion
This short excerpt shows the Action Log inside a complete application built with the I.T.S. Framework. The user-facing workspace remains visible while the log exposes the ordered actions beneath it, connecting configured operators to the append-only history described above.
What to watch: Action Log selected at 00:00 · ordered history visible at 00:03 · configured action catalogue at 00:06 · return to the complete log at 00:09. All displayed values are demonstration and test data.
Work Queues, Filtering, and Query Performance
A configured work queue reads an expression as a predicate rather than an effect:
SELECT TOP (1)
@sflg = flg,
@snflg = nflg,
@soflg = oflg,
@sonflg = onflg
FROM dbo.ITS_MLWFActn
WHERE id = @workqueue_id;
SELECT L.*
FROM dbo.WorkflowEntityLog AS L
WHERE L.ltst = 1
AND L.env = @env
AND (@sflg = 0 OR (L.flg & @sflg) = @sflg)
AND (@snflg = 0 OR (L.flg & @snflg) = 0)
AND (@soflg = 0 OR (L.flg & @soflg) > 0)
AND (@sonflg = 0 OR (L.flg & @sonflg) <> @sonflg);
The predicate should be applied after selective relational conditions such as current-row marker, environment, tenant, owner, date range, or entity key. A dynamic expression such as (flg & @mask) = @mask is not normally seekable through an ordinary B-tree index on flg; SQL Server must evaluate it for each candidate row that reaches that stage.
| Preferred execution shape | Risky execution shape |
|---|---|
| Seek or narrow by tenant, environment, current-row marker, owner, and date | Begin with a dynamic bitwise test across the entire log |
| Evaluate masks over the already-scoped rows | Assume the compact expression automatically makes the query selective |
| Use computed indexed columns only for stable, high-value fixed predicates | Create many speculative indexes for arbitrary runtime masks |
An index on flg can still serve exact-equality workloads, and an indexed computed column can serve a fixed mask expression when justified. The limitation is specifically the expectation that one ordinary index can seek efficiently for arbitrary masks supplied at runtime.
A bitmask is a cheap test on a row already in scope. It is an expensive way to discover candidate rows without another selective predicate.
The -1 Sentinel and Practical Hazards
-1 means all physical bits, not a valid workflow state
In two's-complement BIGINT, -1 has every physical bit set. The engine uses it as an “all bits” sentinel in helpers and optional mask parameters. It lies outside the valid nonnegative state encoding, which uses bit positions 0 through 62.
- An index above 62 produces the sentinel rather than overflowing into the sign bit.
- Rendering helpers can interpret
-1as “all configured statuses.” - An optional check mask can default to
-1, makingchk_flg & flgpreserve every valid state bit.
The sentinel must never be persisted as an entity's current state. Treating it as an ordinary state would collapse the distinction between every configured status, unused physical bits, and the reserved sign position.
Never add or sum masks
Set union is bitwise OR, not arithmetic addition. If two masks overlap, addition carries into another bit. For example, 12 and 24 both contain bit 8; 12 + 24 = 36 clears the shared bit through carry and asserts a bit nobody declared. Use | or aggregate normalized single-bit rows through a union-safe method.
Cast large literals explicitly
Large integer-looking constants do not always enter a T-SQL expression as BIGINT. Cast high-bit values explicitly before bitwise operations:
CAST(549755813888 AS BIGINT)
Use parentheses even when precedence is defined
In T-SQL, bitwise AND/OR have higher precedence than comparison operators, and comparisons have higher precedence than logical AND. Therefore flg & m = m evaluates the bitwise expression before equality. Parentheses such as (flg & m) = m should still be used because they make the intended grouping explicit. The ordering is documented in Microsoft Learn's T-SQL operator-precedence reference.
Do not assume a dense catalogue
Bit index i need not have a configured status row. Helpers that walk the physical bit range must tolerate sparse catalogues. A missing catalogue row should not silently eliminate an entity from a result.
Do not edit compiled masks directly
The masks on ITS_MLWFActn are projections maintained from ITS_MLWFActnFlg. Direct updates bypass validation, semantic typing, derivation, and audit. The next legitimate save can overwrite the manual change because the normalized declarations remain authoritative.
Where the Framework Ends
The framework owns the algebra, catalogues, normalized authoring contract, compilation procedures, operator execution, guard grammar, rendering helpers, group composition, and security-aware presentation. Those objects can be deployed without knowing any specific claim, invoice, order, document, or approval process.
A solution owns its workflow catalogue, status names, transitions, applicability rules, group bindings, security subscriptions, checklists, and the entity log that carries state. Those are solution data, even when the framework supplies the tables and procedures that govern them.
The database half and client half are both necessary. SQL Server validates declarations, derives masks, applies state transitions, and preserves audit history. WinForms turns named groups into usable surfaces, hides actions the user may not execute, resolves work queues, and displays status names instead of opaque integers.
- Solutions do not fork the engine. A new business restriction normally becomes a configured predicate or validator.
- The engine does not learn business statuses. Literal masks with domain meaning belong in catalogue rows, never framework code.
- Escape boundaries remain explicit. Cardinality rules, cross-aggregate constraints, external approvals, and distributed side effects may require validators or orchestration beyond the four-polarity grammar.
Object Map
The following objects form the conceptual engine. CRUD procedures, audit triggers, and solution-specific tables are intentionally omitted.
| Object | Kind | Responsibility |
|---|---|---|
ITS_MLWorkFlow | Table | Workflow definition and typed isolation boundary |
ITS_MLWFFlg | Table | Status catalogue, bit index, thread, effects, and status-level rules |
ITS_MLWFActn | Table | Compiled operator and predicate masks |
ITS_MLWFThread | Table | Named workflow tracks |
ITS_MLWFActnThread | Table | Action-to-thread assignment |
ITS_MLWFActnGrp | Table | Binding surface for transitions, filters, and classifications |
ITS_MLWFActnGrpActn | Table | Expression-to-group binding |
ITS_MLWFActnGrpGrp | Table | Composition of groups from other groups |
ITS_MLWFActnGrpThread | Table | Group scope by thread or stage |
ITS_MLWFSGrpAGrpSubscription | Table | Security-group access to an action surface |
ITS_MLWFActnFlg | Table | Normalized (action, bit, mode) authoring contract |
ITS_MLFlgMode | Table | Semantic type catalogue for flag declarations |
| Action-flag compiler | Database contract | Validates declarations and recompiles masks; implementation name intentionally omitted |
ITS_ActnGet | TVF | Reads an expression as an effect and derives res_nflg |
ITSWF_GetFlgActnGrp | TVF | Reads grouped expressions as predicates |
ITSWF_GetActnGrps | TVF | Resolves the surfaces on which an expression is mounted |
ITS_FnWFEvalFlgFltr | TVF | Set-based evaluation of the guard grammar |
ITS_FnWFEvalFlgFltrScalar | Function | Procedural evaluation of the same grammar |
ITSWF_EvalFlgApplicability | TVF | Status-level validation; one row per violation |
ITSWF_FlgApplicabilityMsg | TVF | Renders violations as human-readable messages |
ITSWF_GetStatus | TVF | Converts masks to status names |
ITSWF_GetStatusStep | TVF | Derives the furthest configured step per thread |
ITSWF_GetFlgStr | TVF | Renders present and absent status names |
ITS_GetTallyFlg | TVF | Supplies the physical bit index/value sequence |
Inline table-valued functions are preferred where their relational definitions can be incorporated into the calling plan. Validators return a set of violations: zero rows means success. That convention composes naturally with EXISTS, NOT EXISTS, and APPLY.
Software Engineering Views of the Engine
The algebra describes the engine precisely, but no single diagram can expose every engineering concern. The following views apply complementary notations to the same implementation: orthogonal state regions for concurrency, a data model for authoring and compilation, a sequence diagram for execution order, a Petri net for open intervals, a marker projection for temporal queries, a data-flow pipeline for performance, and a component diagram for authority and trust.
The diagrams preserve the structure of the implemented engine while normalizing solution-specific database, table, trigger, and procedure names. They document the architecture without identifying a client or exposing a solution-specific persistence contract.
Which diagrams apply, and which do not
Most standard state-machine notations break down on this engine for one specific reason: the state is not a label; it is a 63-bit vector. A diagram that assumes one state at a time cannot describe it. The notation must match the question being asked.
| Notation | Verdict | Why |
|---|---|---|
| Harel statechart with orthogonal regions | Use | Each bit is an independent concurrent region. This notation expresses simultaneity honestly. |
| Entity model of the metadata tables | Use | The authoring surface and the derived projection are separate tables; the distinction is invisible without a structural view. |
| Sequence diagram | Use | A single save crosses validation, insertion, marker maintenance, and dependent operations. Ordering is the point. |
| Petri net | Use | Transitions consume and produce facts. Tokens model pending cycles better than arrows between named states. |
| Data-flow or query pipeline | Use | Performance is governed by predicate order, which is a flow property rather than a structural one. |
| Component and trust boundary | Use | The engine spans database and client; authority must be drawn explicitly. |
| Flat finite-state machine, one bubble per state | Reject | Sixty-three independent bits allow up to 263 representable combinations. A flat graph is not merely large; it represents the model incorrectly. |
| UML class diagram of workflow domain objects | Reject | There is no parallel workflow domain-class model. Behavior lives in metadata rows and relational runtime contracts. |
| Use-case diagram | Reject | It adds no structural information that the configured action catalogue and authorization model do not already carry. |
Orthogonal State Regions
This is the central software-engineering view. An entity does not sit in one named state; it occupies one Boolean sub-state in every applicable region at once. The composite state is the product of those regions, encoded as one BIGINT.
Domain and Data Model
The important structural fact is that the normalized authoring surface and the executable form are different tables. Editors write typed rows; the compilation procedure derives the bitmask columns. Hand-editing the derived side corrupts the contract because the source declaration and executable projection no longer agree.
SESSION_CONTEXT. An administrative script must establish the required session context before making changes or the update must fail.State-Advance Sequence
One user action crosses six participants. Ordering is explicit: validation occurs before the insert, and latest-marker projections are recomputed after the append by the database-maintained projection path.
-- the state operator inside the normalized workflow save path
CROSS APPLY
(
SELECT (ISNULL(previous_row.flg, 0) & action.res_nflg)
| action.flg AS flg
) AS next_state;
-- retract first, then assert: T(s) = (s \ r) ∪ a
Petri Net: The External-Response Cycle
A pending condition is not one state name. It is an open interval between two status events. A Petri net expresses that directly: a token resides in the pending place until the acknowledging transition fires.
actn_flg asserted the request bit. That bitmask scan is non-sargable, which makes the query pipeline below essential.Latest-Marker Projection
Each marker applies the same windowed idiom to a different predicate: select the highest log identity within an entity partition that satisfies a condition. Placing the markers side by side explains how an append-only history can answer several current-state questions with narrow indexed access.
*_ltst column is a materialized argmax over the partition. The opening side of the pending cycle has no equivalent marker.Query Pipeline: Narrow, Materialize, Scan
The index topology determines the mandatory evaluation order. Current-row, environment, entity, workflow, owner, and date predicates are sargable. A runtime test against an arbitrary bitmask is not. The correct plan narrows through indexed relational columns, materializes the candidate set when useful, and evaluates the mask only over that smaller relation.
| Generic filtered-index role | Predicate |
|---|---|
| Current row by entity, workflow, and environment | WHERE ltst = 1 |
| Latest status change by entity and scope | WHERE stts_ltst = 1 |
| Latest action by entity and scope | WHERE actn_ltst = 1 |
Component and Trust Boundary
The engine is neither the database alone nor the client alone. Both halves participate, but only one side is authoritative. The client improves usability; the database preserves correctness regardless of the caller.
Final Principle
The engine is the implementation of a small, explicit algebra:
- A workflow state is a subset of a finite, typed status universe.
- Statuses are the Boolean dimensions of that state space.
- A mask is a lossless scalar encoding of that subset.
- An action is an assert/retract status operator.
- A legal transition is that operator restricted by a configured guard.
- A work queue applies related predicates across a scoped relation of current states.
- A thread selects status dimensions within its universe, defines a business state space, and yields a derived ordinal progress summary.
- The append-only log preserves ordering, while
acc_flgpreserves milestone reachability.
The mathematical structure does not replace the enterprise details. It gives those details a stable language. Statuses, actions, rules, groups, permissions, and work queues can change without changing the mechanism that evaluates them.
Configure the business vocabulary. Compile it into masks. Execute one rigorously defined engine.