API Flow - Summary
Last updated: August 18, 2026
L0 - Stage
L0 - Stage^api summary
Path from L0: Stage^api
Description: Entry point that stages a batch of records (assertions and/or retractions) into %ABR ahead of a later transactional commit by Transact^api. Resolves attribute keys, validates/stages each record via subroutine calls, and enforces all-or-nothing batch atomicity — the first failed record aborts and discards the entire staged batch.
- Purpose
- Take a multi-record input (
Data), resolve each record’s attributes against the schema namespacens, and stage the resulting datoms into%ABRsoTransact^apican later commit them. - Guarantees atomicity at the batch level: any single record failure discards all staging done so far in this call.
- Take a multi-record input (
- Step 1 — Initial guard
- Checks
$DATA(%ABR); if not initialized, logs an error (LOGERROR^logger) stating%ABRwasn’t initialized and thatINIT^apimust be called first, setsok=0, and quits immediately.
- Checks
- Step 2 — Setup / defaults
- Declares working locals:
idx,ReqAttr,AttrCache,recCount,failedIdx. - Defaults
nsto"sandbox"if not supplied. - Defaults
isBulkLoadto0(validation on) if not supplied. - Initializes
recCount=0andfailedIdx="".
- Declares working locals:
- Step 3 — Build required-attributes map
- BuildAttrsRequired^sapiBld — builds the required-attribute map for
nsintoReqAttr, used later by record validation. Unexpanded; body not yet pasted.
- BuildAttrsRequired^sapiBld — builds the required-attribute map for
- Step 4 — Build attribute cache
- BuildAttrsCache^sapiBld — builds the forward/reverse attribute-key cache for
nsintoAttrCache; forward map is used for attribute resolution, reverse map for validation. Unexpanded; body not yet pasted.
- BuildAttrsCache^sapiBld — builds the forward/reverse attribute-key cache for
- Step 5 — Main per-record loop
- Iterates
idx=$ORDER(Data(idx))over all top-level record indices inData. - Loop exits when
idxis exhausted or as soon asok<1(first failure) — remaining records are never attempted. - For each
idx:NEW ResolvedRec; incrementsrecCount.- ResolveRecAttrs^apiRslv — resolves the record’s attribute keys (from
Data(idx,...)) to internal aids usingAttrCache, returningokand populatingResolvedRec. Unexpanded; body not yet pasted. - If resolution fails (
ok=0): setsfailedIdx=idx, logs an error that attribute resolution failed and the batch will be aborted, then exits the inner DO block (loop condition then breaks the FOR). - Otherwise, calls StageRecord^apiWFL — validates (unless
isBulkLoad) and stages the resolved record’s attributes into%ABR, returningok. Unexpanded; body not yet pasted. - If
ok<1after staging, setsfailedIdx=idx.
- Iterates
- Step 6 — Post-loop outcome handling
- If
ok<1(some record failed): kills%ABR, resetsSET %ABR=0, and logs an error summarizing the abort — whichidxfailed, theokvalue, how many records were attempted, andns. Entire batch is discarded, not just the failing record. - Else if
%ABR(defaulted via$GET(%ABR,0)) is0: setsok=2and logs an info line noting a no-op — nothing was staged/committed. - Else (normal success): logs an info line summarizing records attempted, records staged (
%ABRcount),ns, andisBulkLoad. - Logging in this step and throughout uses
LOGERROR^logger/LOGINFO^loggeras inline logging utility calls — not treated as a distinct business-logic level to drill into.
- If
- Step 7 — Quit
- Returns control to caller with
okset per the outcome above.
- Returns control to caller with
L0 - Stage^api diagram
flowchart TD
Start(["Start: 'Stage^api'"]) --> CheckInit{"Is '%ABR' initialized?"}
CheckInit -->|"No"| LogInitErr["Log error:<br/>'%ABR' not initialized"]
LogInitErr --> ReturnFail0(["Return ok = 0"])
CheckInit -->|"Yes"| SetDefaults["Set defaults for<br/>namespace and bulk-load flag;<br/>initialize counters"]
SetDefaults --> BuildReq["'BuildAttrsRequired^sapiBld'<br/>build required-attributes map<br/>(internals not yet verified)"]
BuildReq --> BuildCache["'BuildAttrsCache^sapiBld'<br/>build forward/reverse<br/>attribute cache<br/>(internals not yet verified)"]
BuildCache --> LoopStart{"More records<br/>remaining in input?"}
LoopStart -->|"No"| PostLoop
LoopStart -->|"Yes, and no prior failure"| ResolveAttrs["'ResolveRecAttrs^apiRslv'<br/>resolve record's attribute<br/>keys to internal aids<br/>(internals not yet verified)"]
ResolveAttrs --> ResolveOk{"Resolution<br/>succeeded?"}
ResolveOk -->|"No"| LogResolveErr["Log error:<br/>attribute resolution failed;<br/>record failing index"]
LogResolveErr --> LoopStart
ResolveOk -->|"Yes"| StageRec["'StageRecord^apiWFL'<br/>validate (unless bulk load)<br/>and stage record into '%ABR'<br/>(internals not yet verified)"]
StageRec --> StageOk{"Staging<br/>succeeded?"}
StageOk -->|"No"| MarkFailed["Mark record<br/>as failed index"]
MarkFailed --> LoopStart
StageOk -->|"Yes"| LoopStart
PostLoop{"Did any record<br/>fail during batch?"}
PostLoop -->|"Yes"| Rollback["Discard entire batch:<br/>kill and reset '%ABR'"]
Rollback --> LogAbort["Log error:<br/>batch aborted at failing index;<br/>records attempted count"]
LogAbort --> ReturnFailBatch(["Return ok < 1"])
PostLoop -->|"No"| CheckNoop{"Were any records<br/>actually staged?"}
CheckNoop -->|"No, zero staged"| LogNoop["Log info:<br/>no-op, nothing staged"]
LogNoop --> ReturnNoop(["Return ok = 2"])
CheckNoop -->|"Yes, one or more staged"| LogSuccess["Log info:<br/>records attempted and<br/>records staged summary"]
LogSuccess --> ReturnSuccess(["Return ok = 1"])
L1 - ResolveRecAttrs
L1 - ResolveRecAttrs^apiRslv summary
Path from L0: Stage^api → Step 5 → ResolveRecAttrs^apiRslv
Description: Resolves a single record’s attribute names (from Data(idx,...)) into internal attribute IDs, building ResolvedRec(op,aid)=value for both assertions ("+") and retractions ("-"). Called once per record inside Stage^api’s main loop (Step 5). Fails fast on the first unresolvable attribute.
-
Purpose
- Translate a record’s human-readable attribute names (e.g.
movie.title) into internal attribute IDs (aids), using the namespacensand the pre-builtAttrCache. - Separate assertion values (
ResolvedRec("+",aid)=value) from retraction values (ResolvedRec("-",aid)=value) so downstream staging knows which operation applies to each attribute.
- Translate a record’s human-readable attribute names (e.g.
-
Step 1 — Setup
- Declares locals
akey,aid,ok. - Initializes
akey=""andok=1.
- Declares locals
-
Step 2 — Per-attribute resolution loop
- Iterates
akey=$ORDER(@dataRef@(akey))over all attribute-name subscripts of the record referenced bydataRef. - Loop exits when
akeyis exhausted or as soon asok=0(first unresolvable attribute) — remaining attributes are never attempted. - For each
akey:- Calls ResolveAttr^apiRslv — resolves a single attribute name to its internal aid, trying the namespace-prefixed key first, then a bare key. Unexpanded above this point but shown below (L2).
- If
aid=0(unresolvable): setsok=0and exits the inner DO block, which breaks the FOR loop on the next iteration check. - Otherwise:
- If the record has a direct (non-retraction) value at
@dataRef@(akey)— checked via$DATA(...)#10(data-value-present bit) — stores it as an assertion:ResolvedRec("+",aid)=value. - If the record also has a retraction sub-node at
@dataRef@(akey,"-"), stores it as a retraction:ResolvedRec("-",aid)=value. This means a single attribute key can yield both an assertion and a retraction entry if both forms are present in the input.
- If the record has a direct (non-retraction) value at
- Iterates
-
Step 3 — Quit
- Returns
ok(1if every attribute resolved,0if any attribute could not be resolved) to the caller (Stage^api, Step 5).
- Returns
L2 - ResolveAttr^apiRslv
Path from L0: Stage^api → Step 5 → ResolveRecAttrs^apiRslv → Step 2 → ResolveAttr^apiRslv
Description: Resolves a single attribute name string to its internal attribute ID, first trying it as a namespace-prefixed key, then falling back to a bare (unprefixed) key. Returns 0 if neither lookup succeeds. This is a leaf routine — no further calls deeper than this.
-
Purpose
- Given one attribute name (
akey) and the current namespace (ns), look up the corresponding internal aid inAttrCache, supporting both namespace-scoped attributes and global/bare-keyed attributes (e.g. system attributes likesys.attr.id).
- Given one attribute name (
-
Step 1 — Try namespace-prefixed lookup
- Builds the key
ns_"."_akey(e.g.sandbox.movie.genre) and looks it up inAttrCache, coercing the result to a number via unary+(so a missing/non-numeric entry becomes0).
- Builds the key
-
Step 2 — Fallback to bare-key lookup
- If the prefixed lookup returned
0, triesAttrCache(akey)directly (e.g.sys.attr.id), again coerced to a number via unary+.
- If the prefixed lookup returned
-
Step 3 — Failure logging
- If both lookups returned
0(attribute unresolvable by either method), logs an error (LOGERROR^logger) naming the unresolvable attribute, thens, and noting that record resolution is being aborted. Logging is an inline utility call, not treated as a deeper level.
- If both lookups returned
-
Step 4 — Quit
- Returns
aid— either a resolved internal attribute ID (>0) or0if unresolvable — to the caller (ResolveRecAttrs^apiRslv, Step 2).
- Returns
L1 - ResolveRecAttrs^apiRslv flowchart
flowchart TD
R1Start(["'ResolveRecAttrs^apiRslv' — Step 1:<br/>Setup locals"]) --> R2Loop{"'ResolveRecAttrs^apiRslv' — Step 2:<br/>More attribute keys<br/>remaining in record?"}
R2Loop -->|"No"| R3Return(["'ResolveRecAttrs^apiRslv' — Step 3:<br/>Return ok to Stage^api"])
R2Loop -->|"Yes, and no prior failure"| CallResolveAttr["'ResolveAttr^apiRslv'<br/>resolve one attribute name<br/>to internal aid"]
CallResolveAttr --> RA1["'ResolveAttr^apiRslv' — Step 1:<br/>Try namespace-prefixed<br/>key lookup"]
RA1 --> RA1Check{"Prefixed lookup<br/>resolved?"}
RA1Check -->|"Yes"| RA4Return(["'ResolveAttr^apiRslv' — Step 4:<br/>Return resolved aid"])
RA1Check -->|"No"| RA2["'ResolveAttr^apiRslv' — Step 2:<br/>Try bare-key<br/>fallback lookup"]
RA2 --> RA2Check{"Bare-key lookup<br/>resolved?"}
RA2Check -->|"Yes"| RA4Return
RA2Check -->|"No"| RA3["'ResolveAttr^apiRslv' — Step 3:<br/>Log error —<br/>attribute unresolvable"]
RA3 --> RA4ReturnZero(["'ResolveAttr^apiRslv' — Step 4:<br/>Return aid = 0"])
RA4Return --> R2AfterCall{"'ResolveRecAttrs^apiRslv' — Step 2:<br/>Was aid resolved<br/>(non-zero)?"}
RA4ReturnZero --> R2AfterCall
R2AfterCall -->|"No, aid = 0"| R2SetFail["Set failure flag,<br/>stop processing<br/>remaining attributes"]
R2SetFail --> R3Return
R2AfterCall -->|"Yes"| R2StoreCheck{"Does key have a<br/>direct assertion value?"}
R2StoreCheck -->|"Yes"| R2StoreAssert["Store as assertion in<br/>ResolvedRec plus-branch,<br/>keyed by aid, value"]
R2StoreCheck -->|"No"| R2CheckRetract
R2StoreAssert --> R2CheckRetract{"Does key also have<br/>a retraction sub-node?"}
R2CheckRetract -->|"Yes"| R2StoreRetract["Store as retraction in<br/>ResolvedRec minus-branch,<br/>keyed by aid, value"]
R2CheckRetract -->|"No"| R2Loop
R2StoreRetract --> R2Loop
L1 - StageRecord
L1 - StageRecord^apiWFL summary
Path from L0: Stage^api → Step 5 → StageRecord^apiWFL
Description: Resolves the target entity for a record, validates its facts (unless bulk load), then stages the record’s assertions and retractions as datoms into %ABR. Assertions are processed before retractions so the entity key is staged first. Wraps the staging phase in $ETRAP to contain runtime errors without aborting Stage^api’s outer loop. Called once per record inside Stage^api’s main loop (Step 5), after ResolveRecAttrs^apiRslv succeeds.
- Purpose
- Take one record’s already-resolved attributes (
ResolvedRec), determine/resolve its target entity, validate the record’s facts, and write the resulting assertion/retraction datoms into%ABR. - Distinguish four outcomes for the caller: no-op (
2), staged cleanly (1), controlled failure (0), or uncaught runtime error (-1).
- Take one record’s already-resolved attributes (
- Step 1 — Setup
- Declares locals
eid,isNewEntity,hasChanges,result. - Initializes
eid=0,result=1,hasChanges=0.
- Declares locals
- Step 2 — Resolve target entity
- Calls ResolveTargetEntity^apiRslv — resolves/derives the target entity ID from
ResolvedRec, mutatingResolvedRecin the process (control attributes are consumed here); success/error logging happens inside it. Unexpanded; body not yet pasted. - If
eid=0(resolution failed), quits immediately with0. No transaction is open yet, so this is a direct abort — no rollback needed.
- Calls ResolveTargetEntity^apiRslv — resolves/derives the target entity ID from
- Step 3 — Validate entity facts
- Calls IsEntityRegistered^apiVld — checks whether
eidis a previously registered entity; result is inverted and stored asisNewEntity. Unexpanded; body not yet pasted. - If
isBulkLoadis false:- Calls ValidateRecord^apiVld — validates the record’s facts against
ReqAttrandAttrCache, given whether the entity is new; returnsresult. Unexpanded; body not yet pasted.
- Calls ValidateRecord^apiVld — validates the record’s facts against
- Else (
isBulkLoadtrue):- Skips validation entirely and logs a warning (
LOGWARNING^logger) noting required-attribute checks were bypassed for thiseid.
- Skips validation entirely and logs a warning (
- If
resultis falsy after this: logs an error that entity fact validation failed, and quits with0. Still no transaction open — direct abort.
- Calls IsEntityRegistered^apiVld — checks whether
- Step 4 — Stage datoms into %ABR
- Arms
NEW $ETRAPset toGOTO StageRecordERR^apiWFL, scoping error trapping to this phase only, so an uncaught runtime error here doesn’t propagate up and abortStage^api’s per-record loop uncontrolled — it’s caught locally instead. - Declares
aid(current attribute id being walked) andok(per-attribute staging outcome; only a0stops a loop early). - Sets
ok=1. - Assertions first: iterates
aid=$ORDER(ResolvedRec("+",aid)), calling DatomAssert (local function, same call depth — inline helper) for each, which returns1(staged),2(no-op), or0(failed) per attribute. Loop stops early only whenokbecomes0. - Retractions second, only if assertions succeeded: if
okis still truthy, iteratesaid=$ORDER(ResolvedRec("-",aid)), calling DatomRetract (local function, same call depth — inline helper) for each, same return convention. Loop stops early only whenokbecomes0. - This ordering (assertions before retractions) guarantees the entity key is staged before any retraction is attempted against it.
- Arms
- Step 5 — Determine final result
- Sets
hasChangesfrom$DATA(%ABR(eid))>0— this is what actually distinguishes “wrote something” from “processed cleanly but nothing changed”; the per-attribute 1-vs-2 outcomes fromDatomAssert/DatomRetractaren’t separately tracked. - If
ok=0: setsresult=0(controlled failure — some attribute staging failed). - Else if
hasChanges: setsresult=1(staged cleanly, something changed). - Else: sets
result=2(no-op — processed cleanly but nothing changed).
- Sets
- Step 6 — End
GOTO StageRecordEND— jumps to the routine’s end label (not shown yet) to returnresultto the caller. This is a same-routine control-flow jump, not a deeper call, so it stays inline rather than becoming its own level.- (Implicit, not yet shown:
StageRecordERR^apiWFLis the$ETRAPtarget for Step 4’s runtime-error path, which presumably setsresult=-1before falling through to the same end point — body not yet pasted.)
L1 - StageRecord^apiWFL flowchart
flowchart TD
S1Start(["'StageRecord^apiWFL' — Step 1:<br/>Setup locals"]) --> S2Resolve["'ResolveTargetEntity^apiRslv'<br/>resolve target entity id<br/>(internals not yet verified)"]
S2Resolve --> S2Check{"'StageRecord^apiWFL' — Step 2:<br/>Entity resolved?"}
S2Check -->|"No, eid = 0"| S2ReturnFail(["Return result = 0<br/>(no transaction open,<br/>direct abort)"])
S2Check -->|"Yes"| S3Registered["'IsEntityRegistered^apiVld'<br/>check if entity already<br/>registered<br/>(internals not yet verified)"]
S3Registered --> S3BulkCheck{"'StageRecord^apiWFL' — Step 3:<br/>Is this a bulk load?"}
S3BulkCheck -->|"No"| S3Validate["'ValidateRecord^apiVld'<br/>validate record's facts<br/>against required attrs<br/>(internals not yet verified)"]
S3BulkCheck -->|"Yes"| S3LogWarn["Log warning:<br/>validation skipped,<br/>required-attr checks bypassed"]
S3Validate --> S3ResultCheck{"'StageRecord^apiWFL' — Step 3:<br/>Validation succeeded?"}
S3ResultCheck -->|"No"| S3LogErr["Log error:<br/>entity fact validation failed"]
S3LogErr --> S3ReturnFail(["Return result = 0<br/>(no transaction open,<br/>direct abort)"])
S3ResultCheck -->|"Yes"| S4Arm
S3LogWarn --> S4Arm
S4Arm["'StageRecord^apiWFL' — Step 4:<br/>Arm ETRAP scoped to<br/>this staging phase"] --> S4AssertLoop{"More assertion<br/>attributes remaining?"}
S4AssertLoop -->|"Yes, and no prior failure"| S4DatomAssert["DatomAssert<br/>stage one asserted<br/>attribute value"]
S4DatomAssert --> S4AssertOkCheck{"Attribute staged<br/>(not failed)?"}
S4AssertOkCheck -->|"Yes"| S4AssertLoop
S4AssertOkCheck -->|"No"| S5Determine
S4AssertLoop -->|"No more assertions"| S4RetractGate{"Did all assertions<br/>succeed?"}
S4RetractGate -->|"No"| S5Determine
S4RetractGate -->|"Yes"| S4RetractLoop{"More retraction<br/>attributes remaining?"}
S4RetractLoop -->|"Yes, and no prior failure"| S4DatomRetract["DatomRetract<br/>stage one retracted<br/>attribute value"]
S4DatomRetract --> S4RetractOkCheck{"Attribute staged<br/>(not failed)?"}
S4RetractOkCheck -->|"Yes"| S4RetractLoop
S4RetractOkCheck -->|"No"| S5Determine
S4RetractLoop -->|"No more retractions"| S5Determine
S5Determine{"'StageRecord^apiWFL' — Step 5:<br/>Did any attribute<br/>staging fail?"}
S5Determine -->|"Yes"| S5ResultFail(["Set result = 0<br/>controlled failure"])
S5Determine -->|"No"| S5ChangesCheck{"Did staging produce<br/>an actual change<br/>to percent-ABR?"}
S5ChangesCheck -->|"Yes"| S5ResultChanged(["Set result = 1<br/>staged cleanly"])
S5ChangesCheck -->|"No"| S5ResultNoop(["Set result = 2<br/>no-op, nothing changed"])
S5ResultFail --> S6End(["'StageRecord^apiWFL' — Step 6:<br/>GOTO end label,<br/>return result to Stage^api"])
S5ResultChanged --> S6End
S5ResultNoop --> S6End
S2ReturnFail -.->|"returns to<br/>Stage^api Step 5"| Done(["Back to caller"])
S3ReturnFail -.->|"returns to<br/>Stage^api Step 5"| Done
S6End -.->|"returns to<br/>Stage^api Step 5"| Done
ETrapNote["Note: uncaught runtime error<br/>during Step 4 jumps to<br/>StageRecordERR^apiWFL<br/>(internals not yet verified,<br/>presumably sets result = -1)"]
L2 - ResolveTargetEntity^apiRslv summary
Path from L0: Stage^api → Step 5 → StageRecord^apiWFL → Step 2 → ResolveTargetEntity^apiRslv
Description: Dispatches to one of three entity-resolution strategies based on which control attribute is present in the resolved record (sys.attr.id, sys.attr.key, or neither), returning the resolved/generated entity ID or 0 on failure.
- Purpose
- Determine the target entity that the record’s assertions/retractions apply to, using a strict priority order of control attributes, and mutate
ResolvedRecto consume those control attributes so they don’t leak through as ordinary entity facts.
- Determine the target entity that the record’s assertions/retractions apply to, using a strict priority order of control attributes, and mutate
- Step 1 — Setup
- Declares
eid; initializeseid=0.
- Declares
- Step 2 — Path dispatch (mutually exclusive, priority order)
- Path 0 — explicit raw EID: if
ResolvedRec("+",SYSATTRID)exists, calls ResolveByEID^apiRslv — resolves the entity via an explicit raw EID value. Unexpanded above; drilled into below (L3). - Path 1 — natural key: else if
ResolvedRec("+",AKEYID)exists, calls ResolveByNaturalKey^apiRslv — find-or-create resolution viasys.attr.key. Drilled into below (L3). - Path 2 — unique-attribute resolution: else (neither control attribute present), calls ResolveByUnique^apiRslv — find-or-create resolution via a uniquely-constrained attribute, optionally disambiguated by
sys.attr.resolvedby. Drilled into below (L3).
- Path 0 — explicit raw EID: if
- Step 3 — Quit
- Returns
eid(resolved entity ID, or0on any path’s failure) to the caller (StageRecord^apiWFL, Step 2).
- Returns
L3 - ResolveByEID^apiRslv
Path from L0: … → ResolveTargetEntity^apiRslv → Path 0 → ResolveByEID^apiRslv
Description: Resolves the target entity using an explicit raw EID value supplied via sys.attr.id, after removing that control attribute from ResolvedRec so it doesn’t reach staging as an entity fact.
- Purpose
- Trust the caller-supplied raw entity ID, but only after validating both its structural shape and its existence, delegating that work to
GetEID^apiGet.
- Trust the caller-supplied raw entity ID, but only after validating both its structural shape and its existence, delegating that work to
- Step 1 — Read and consume control attribute
- Reads
idvalfromResolvedRec("+",SYSATTRID). - Kills
ResolvedRec("+",SYSATTRID)immediately — this node must not reachDatomAssertas an entity fact.
- Reads
- Step 2 — Resolve via GetEID
- Calls GetEID^apiGet — validates both the format (structurally valid EID) and existence (must exist) of
idval; logs both success and failure internally. Drilled into below (L4).
- Calls GetEID^apiGet — validates both the format (structurally valid EID) and existence (must exist) of
- Step 3 — Quit
- Returns
eid(resolved ID or0) to the caller (ResolveTargetEntity^apiRslv, Path 0).
- Returns
L4 - GetEID^apiGet
Path from L0: … → ResolveByEID^apiRslv → Step 2 → GetEID^apiGet (Note: also reachable from ResolveByNaturalKey^apiRslv at L4 via a different call path — see below.)
Description: General-purpose entity-reference resolver supporting three resolution paths (strict EID, sys.attr.key, or unique-attribute lookup), tried in order depending on which arguments are supplied. Used by both ResolveByEID^apiRslv (path 0 only, no aid) and ResolveByNaturalKey^apiRslv (paths 0–1, no aid).
-
Purpose
- Resolve any supported entity reference (
val) to an internal entity ID, trying strict EID validation first, thensys.attr.keylookup, then (if anaidis supplied) unique-attribute lookup.
- Resolve any supported entity reference (
-
Step 1 — Guard: empty value
- If
val="", logs an error and quits0immediately — fails fast before touching any globals.
- If
-
Step 2 — Setup and guard: aid shape
- Declares
eid,isEidShaped; initializeseid=0. - Defaults
aidvia$GET(aid). - If
aidis supplied but not numeric, logs an error (must be numeric; directs caller toLookupEID^apiforsys.attr.keystring resolution) and quits0.
- Declares
-
Step 3 — Path 0: strict EID validation + existence check
- Calls IsEID^utils — performs structural validation of
valas an EID shape. Unexpanded; body not yet pasted. - If
valis EID-shaped:- Calls IsEntityRegistered^apiVld — checks whether the raw EID
valis registered/exists. Unexpanded; body not yet pasted (also referenced earlier at L1/StageRecord Step 3, not yet drilled into). - If registered: sets
eid=val, logs debug (resolved via EID). - Else: logs debug (valid EID shape but not registered) —
eidstays0. - Quits immediately after this branch, regardless of outcome — Paths 1 and 2 are unreachable once
valis EID-shaped.
- Calls IsEntityRegistered^apiVld — checks whether the raw EID
- Calls IsEID^utils — performs structural validation of
-
Step 4 — Path 1: sys.attr.key lookup (only if aid omitted, and val not EID-shaped)
- If
aid="":- Calls ResolveLiveEID^apiRslv with
AKEYIDandval— resolves the live entity currently claiming thissys.attr.keyvalue. Unexpanded; body not yet pasted (referenced but not shown in this batch). - Logs debug either way (resolved or not resolvable via
sys.attr.key). - Quits with
eidfrom this path.
- Calls ResolveLiveEID^apiRslv with
- If
-
Step 5 — Path 2: unique-attribute lookup (only reached if aid was supplied)
- Calls ResolveLiveEID^apiRslv with
aidandval. Unexpanded; same subroutine as Step 4, different arguments. - Logs debug either way (resolved or not resolvable via
aid/val).
- Calls ResolveLiveEID^apiRslv with
-
Step 6 — Quit
- Returns
eidto the caller. - Liveness note (from header comment): both Path 1 and Path 2 walk all candidate eids under
^AVET(aid,valkey,candidate)and accept only the one whose most recent transaction foraidis still asserting exactlyvalkey— i.e.,ResolveLiveEID^apiRslvfilters out stale/dead claimants rather than taking the first$ORDERhit.
- Returns
L3 - ResolveByNaturalKey^apiRslv
Path from L0: … → ResolveTargetEntity^apiRslv → Path 1 → ResolveByNaturalKey^apiRslv
Description: Find-or-create resolution via the sys.attr.key control attribute — returns the existing entity if the key is already registered, otherwise generates and returns a brand-new entity ID. Unlike ResolveByEID, this control attribute is not removed from ResolvedRec (it must reach DatomAssert as an entity fact, anchoring the entity to this key going forward).
- Purpose
- Implement find-or-create semantics for natural-key-based entity resolution; this path never fails.
- Step 1 — Read control attribute
- Reads
keyvalfromResolvedRec("+",AKEYID). Note: not killed here (comment explicitly says it must reachDatomAssertas an entity fact).
- Reads
- Step 2 — Attempt resolution
- Calls GetEID^apiGet with
keyval(noaid— so only Paths 0/1 insideGetEIDare reachable; Path 0 is a no-op since a natural key value won’t be EID-shaped in practice, so this effectively resolves via Path 1). Same subroutine as drilled into above (L4).
- Calls GetEID^apiGet with
- Step 3 — Find-or-create branch
- If
eid>0: logs debug (resolved viasys.attr.key). - Else: calls GENID^utils — generates a new time-sorted compact entity ID. Drilled into below (L4). Logs debug (new entity generated).
- If
- Step 4 — Quit
- Returns
eid(always>0— find-or-create never fails) to the caller (ResolveTargetEntity^apiRslv, Path 1).
- Returns
L4 - GENID^utils
Path from L0: … → ResolveByNaturalKey^apiRslv → Step 3 → GENID^utils (Also called from ResolveByUnique^apiRslv and ResolveOwnership^apiRslv at other depths — see below.)
Description: Leaf utility that generates a KSUID-style time-sorted compact ID: a 13-character hex timestamp prefix (via $$EPOCH) followed by a random Base36 suffix of configurable length (default 7).
- Purpose
- Produce a chronologically sortable, effectively-unique identifier for newly created entities.
- Step 1 — Setup
- Declares
CHARSET,RAND,I,POS. - Defaults
RLENto7via$GET(RLEN,7). - Sets
CHARSETto the Base36 alphabet (0-9,a-z). - Initializes
RAND="".
- Declares
- Step 2 — Generate random suffix
- Loops
I=1:1:RLEN, each iteration picking a random character fromCHARSETvia$RANDOMand appending it toRAND.
- Loops
- Step 3 — Quit
- Returns
$$EPOCH_RAND— concatenation of the epoch-derived hex timestamp (from EPOCH, an unexpanded same-routine-or-namespace function per the header comment — not yet pasted) and the random suffix.
- Returns
L3 - ResolveByUnique^apiRslv
Path from L0: … → ResolveTargetEntity^apiRslv → Path 2 → ResolveByUnique^apiRslv
Description: Find-or-create resolution via a uniquely-constrained attribute. Dispatches across four sub-cases based on how many unique attributes are present in the record and whether sys.attr.resolvedby was supplied to disambiguate.
-
Purpose
- Handle entity resolution when the record carries no explicit EID or natural key, instead relying on schema-declared unique attributes (with
sys.attr.resolvedbyrequired when more than one is present).
- Handle entity resolution when the record carries no explicit EID or natural key, instead relying on schema-declared unique attributes (with
-
Step 1 — Setup
- Declares
count,firstAid,eid; initializeseid=0.
- Declares
-
Step 2 — Count unique attributes
- Calls CountUniqueAttributes^apiRslv — single pass over
ResolvedRec’s assertions, counting how many carry a uniqueness constraint and capturing the first one’s aid. Drilled into below (L4).
- Calls CountUniqueAttributes^apiRslv — single pass over
-
Step 3 — Case: resolvedby present but no unique attributes
- If
count=0andResolvedRec("+",RESOLVEDBYID)exists: logs an error (resolvedby specified but no unique attributes supplied) and quits0.
- If
-
Step 4 — Case: no unique attributes, no resolvedby (anonymous entity)
- If
count=0(and resolvedby absent, per Step 3 having already handled the other case): calls GENID^utils to mint a new entity, logs a warning (not debug — anonymous entity creation is flagged more prominently), and quits with thateid.
- If
-
Step 5 — Case: exactly one unique attribute
- If
count=1: quits directly with the result of calling ResolveOwnership^apiRslv(firstAid,.ResolvedRec) — passesfirstAidstraight through. Drilled into below (L5, underResolveDesignatedUnique) — note: this is the same subroutine reached one level shallower here than via the multi-attribute path below (see Open Items).
- If
-
Step 6 — Case: multiple unique attributes, resolvedby required
- If
count>1… (implicitly — this line is reached only whencountis neither0nor1): ifResolvedRec("+",RESOLVEDBYID)is absent, logs an error (multiple unique attributes requiresys.attr.resolvedby) and quits0. - Otherwise, calls ResolveDesignatedUnique^apiRslv — validates and resolves via the caller-designated unique attribute. Drilled into below (L4).
- Kills
ResolvedRec("+",RESOLVEDBYID)if present — this control attribute must not reachDatomAssertas an entity fact.
- If
-
Step 7 — Quit
- Returns
eidto the caller (ResolveTargetEntity^apiRslv, Path 2).
- Returns
L4 - CountUniqueAttributes^apiRslv
Path from L0: … → ResolveByUnique^apiRslv → Step 2 → CountUniqueAttributes^apiRslv
Description: Pure counting pass over ResolvedRec’s assertions — determines how many carry a uniqueness constraint and returns the first one found. Does no resolution, lookup, staging, or validation itself; exists solely to inform ResolveByUnique’s dispatch.
- Purpose
- Single-pass scan to count unique-constrained assertion attributes and capture the first one’s aid, for use in
ResolveByUnique^apiRslv’s branching.
- Single-pass scan to count unique-constrained assertion attributes and capture the first one’s aid, for use in
- Step 1 — Setup
- Declares
aid; initializescount=0,firstAid="".
- Declares
- Step 2 — Scan loop
- Iterates
aid=$ORDER(ResolvedRec("+",aid))over all assertion attributes. - For each: calls GetUniqueMode^sapiGet — returns the attribute’s uniqueness constraint mode (or
0if none). Drilled into below (L5).- If truthy (attribute is unique): increments
count; iffirstAid="", setsfirstAid=aid.
- If truthy (attribute is unique): increments
- Iterates
- Step 3 — Return (procedure, no explicit value)
QUITwith no value —countandfirstAidare returned via pass-by-referenceOUTparameters.
L5 - GetUniqueMode^sapiGet
Path from L0: … → CountUniqueAttributes^apiRslv → Step 2 → GetUniqueMode^sapiGet (Also called directly from ResolveDesignatedUnique^apiRslv — see below.)
Description: Leaf schema lookup that returns an attribute’s uniqueness constraint mode as a schema enumeration EID (UNQINSERTID, UNQUPSERTID, or 0 for none), replacing an older pair of boolean-returning functions.
- Purpose
- Given an attribute ID, report whether — and how — it enforces uniqueness, so callers can compare against schema EIDs directly.
- Step 1 — Check insert-unique
- If
^TBAVET(UNIQUEID,INSERTKEY,aid)exists (double-negated$DATAcheck), quitsUNQINSERTID.
- If
- Step 2 — Check upsert-unique
- Else if
^TBAVET(UNIQUEID,UPSERTKEY,aid)exists, quitsUNQUPSERTID.
- Else if
- Step 3 — No constraint
- Else quits
0.
- Else quits
L4 - ResolveDesignatedUnique^apiRslv
Path from L0: … → ResolveByUnique^apiRslv → Step 6 → ResolveDesignatedUnique^apiRslv
Description: Resolves the target entity when multiple unique attributes are present and the caller has designated which one to use via sys.attr.resolvedby. Runs four sequential validations before delegating to ResolveOwnership^apiRslv; any single failure aborts with 0.
- Purpose
- Ensure the caller-designated attribute is schema-valid, actually unique, present in the record, and non-empty, before applying ownership semantics to it.
- Step 1 — Setup
- Declares
attrkey,aid,val,eid; initializeseid=0. - Reads
attrkeyfromResolvedRec("+",RESOLVEDBYID).
- Declares
- Step 2 — Validation 1: schema existence
- Calls GetEID^sapiGet (note:
sapiGet, distinct fromapiGet’sGetEIDdrilled into at L4 above — unexpanded; body not yet pasted) withattrkeyto resolveaid. - If
aid<1: logs an error (resolvedby attribute not registered in schema) and quits0.
- Calls GetEID^sapiGet (note:
- Step 3 — Validation 2: attribute is unique
- Calls GetUniqueMode^sapiGet (same subroutine drilled into above, L5) with
aid. - If falsy: logs an error (resolvedby attribute is not unique) and quits
0.
- Calls GetUniqueMode^sapiGet (same subroutine drilled into above, L5) with
- Step 4 — Validation 3: attribute present in record
- If
ResolvedRec("+",aid)doesn’t exist: logs an error (resolvedby attribute missing from record) and quits0.
- If
- Step 5 — Validation 4: value non-empty
- Reads
valvia$GET(ResolvedRec("+",aid)). - If
val="": logs an error (resolvedby attribute has empty value) and quits0.
- Reads
- Step 6 — Delegate
- If all four validations pass, quits directly with the result of calling ResolveOwnership^apiRslv(aid,.ResolvedRec). Drilled into below (L5).
L5 - ResolveOwnership^apiRslv
Path from L0: … → ResolveDesignatedUnique^apiRslv → Step 6 → ResolveOwnership^apiRslv (Also reachable directly from ResolveByUnique^apiRslv — Step 5 above — at one call-depth shallower, i.e. L4 via that path; see Open Items.)
Description: Resolves (or generates) the entity ID for a single unique attribute by applying UNQINSERT/UNQUPSERT ownership semantics, distinguishing “live” claimants from stale/dead ones so that released values and released identities are handled correctly rather than defaulting to the first $ORDER match.
- Purpose
- Given one unique attribute and its value, determine the correct entity: an existing live owner, a freshly generated entity (value/identity released), a brand-new entity (value never claimed), or
0(insert-unique violation / internal error).
- Given one unique attribute and its value, determine the correct entity: an existing live owner, a freshly generated entity (value/identity released), a brand-new entity (value never claimed), or
- Step 1 — Setup
- Declares
val,mode,ownereid,ownerIsLive,eid; initializeseid=0. - Reads
valfromResolvedRec("+",aid). - Calls GetUniqueMode^sapiGet (L5, drilled into above) to get
mode.
- Declares
- Step 2 — Guard: empty value
- If
val="": logs an error (internal error — empty value for unique attribute) and quits0.
- If
- Step 3 — Branch: has this value ever been registered?
- Calls IsRangeValue^sapiVld — checks whether
valhas ever been registered foraid. Unexpanded; body not yet pasted. - If yes (value previously registered):
- Calls ResolveLiveEID (same name referenced in
GetEID^apiGetabove, but called here without an explicit^routinetag in the source — presumed sameResolveLiveEID^apiRslv; unexpanded, body not yet pasted) to getownereid. - Sets
ownerIsLive=(ownereid'=0). - UNQINSERT + live owner: sets
eid=0, logs an error (insert-unique violation — already owned). - UNQINSERT + no live owner: value is free again — calls
GENID^utils(drilled into above, L4) to generate a new entity, logs debug. - UNQUPSERT + live owner: claimant is treated as the same real-world identity — sets
eid=ownereid, logs debug (merge into existing EID). - UNQUPSERT + no live owner: prior identity released the value — calls
GENID^utilsto mint a fresh entity (does NOT merge into the dead owner), logs debug.
- Calls ResolveLiveEID (same name referenced in
- If no (value never registered at all):
- Calls
GENID^utilsto generate a new entity regardless of mode, logs debug (new entity).
- Calls
- Calls IsRangeValue^sapiVld — checks whether
- Step 4 — Quit
- Returns
eidto the caller (ResolveByUnique^apiRslvStep 5, orResolveDesignatedUnique^apiRslvStep 6, depending on path).
- Returns
L2 - ResolveTargetEntity^apiRslv flowchart
In HTML format
Mermaid format
flowchart TD
RTEStart(["'ResolveTargetEntity^apiRslv' — Step 1:<br/>Setup, eid = 0"]) --> RTEPathCheck{"'ResolveTargetEntity^apiRslv' — Step 2:<br/>Which control attribute<br/>is present?"}
RTEPathCheck -->|"Path 0: sys.attr.id present"| RBE["'ResolveByEID^apiRslv'<br/>resolve via explicit<br/>raw EID"]
RTEPathCheck -->|"Path 1: sys.attr.key present"| RBNK["'ResolveByNaturalKey^apiRslv'<br/>find-or-create via<br/>natural key"]
RTEPathCheck -->|"Path 2: neither present"| RBU["'ResolveByUnique^apiRslv'<br/>find-or-create via<br/>unique attribute"]
RBE --> RBEStep1["Read raw EID value,<br/>kill sys.attr.id node<br/>from ResolvedRec"]
RBEStep1 --> GetEID1["'GetEID^apiGet'<br/>validate format and<br/>existence of value"]
GetEID1 --> GESetup["Setup, guard empty value,<br/>guard aid must be numeric"]
GESetup --> GEPath0{"Is value<br/>EID-shaped?"}
GEPath0 -->|"Yes"| GERegCheck["'IsEntityRegistered^apiVld'<br/>check if raw EID<br/>is registered"]
GERegCheck --> GERegOutcome{"Registered?"}
GERegOutcome -->|"Yes"| GEReturnEid(["Return resolved eid"])
GERegOutcome -->|"No"| GEReturnZeroA(["Return eid = 0"])
GEPath0 -->|"No, and aid omitted"| GEPath1["'ResolveLiveEID^apiRslv'<br/>lookup live owner via<br/>sys.attr.key"]
GEPath1 --> GEReturnPath1(["Return eid<br/>(resolved or 0)"])
GEPath0 -->|"No, and aid supplied"| GEPath2["'ResolveLiveEID^apiRslv'<br/>lookup live owner via<br/>unique attribute"]
GEPath2 --> GEReturnPath2(["Return eid<br/>(resolved or 0)"])
GEReturnEid --> RBEQuit(["'ResolveByEID^apiRslv'<br/>returns eid to<br/>ResolveTargetEntity"])
GEReturnZeroA --> RBEQuit
GEReturnPath1 --> RBEQuit
GEReturnPath2 --> RBEQuit
RBNK --> RBNKRead["Read sys.attr.key value<br/>(kept in ResolvedRec —<br/>must reach DatomAssert)"]
RBNKRead --> GetEID2["'GetEID^apiGet'<br/>same routine as above,<br/>no aid supplied"]
GetEID2 --> RBNKCheck{"Resolved,<br/>eid greater than 0?"}
RBNKCheck -->|"Yes"| RBNKFound["Log resolved<br/>via sys.attr.key"]
RBNKCheck -->|"No"| GENID1["'GENID^utils'<br/>generate new<br/>time-sorted entity ID"]
RBNKFound --> RBNKQuit(["'ResolveByNaturalKey^apiRslv'<br/>returns eid<br/>(never fails)"])
GENID1 --> RBNKQuit
RBU --> CUA["'CountUniqueAttributes^apiRslv'<br/>count unique-constrained<br/>assertion attributes"]
CUA --> GUM1["'GetUniqueMode^sapiGet'<br/>per attribute:<br/>check uniqueness mode"]
GUM1 --> CUAReturn(["Return count,<br/>first unique aid"])
CUAReturn --> RBUCase0{"count = 0 and<br/>resolvedby present?"}
RBUCase0 -->|"Yes"| RBUErr1["Log error:<br/>resolvedby specified<br/>but no unique attrs"]
RBUErr1 --> RBUReturnZero1(["Return eid = 0"])
RBUCase0 -->|"No"| RBUCase0b{"count = 0<br/>(anonymous entity)?"}
RBUCase0b -->|"Yes"| GENID2["'GENID^utils'<br/>generate new<br/>anonymous entity"]
GENID2 --> RBUReturnAnon(["Return generated eid"])
RBUCase0b -->|"No"| RBUCase1{"count = 1?"}
RBUCase1 -->|"Yes"| RO1["'ResolveOwnership^apiRslv'<br/>apply insert/upsert<br/>semantics for sole<br/>unique attribute"]
RO1 --> RBUReturnRO1(["Return eid from<br/>ResolveOwnership"])
RBUCase1 -->|"No, count greater than 1"| RBUCaseMulti{"sys.attr.resolvedby<br/>present?"}
RBUCaseMulti -->|"No"| RBUErr2["Log error:<br/>multiple unique attrs<br/>require resolvedby"]
RBUErr2 --> RBUReturnZero2(["Return eid = 0"])
RBUCaseMulti -->|"Yes"| RDU["'ResolveDesignatedUnique^apiRslv'<br/>validate and resolve via<br/>caller-designated attribute"]
RDU --> RDUStep1["'GetEID^sapiGet'<br/>validate attribute key<br/>exists in schema"]
RDUStep1 --> RDUCheck1{"Attribute<br/>registered?"}
RDUCheck1 -->|"No"| RDUErr1["Log error:<br/>resolvedby attribute<br/>not registered"]
RDUErr1 --> RDUReturnZero1(["Return eid = 0"])
RDUCheck1 -->|"Yes"| GUM2["'GetUniqueMode^sapiGet'<br/>check attribute<br/>is unique"]
GUM2 --> RDUCheck2{"Attribute<br/>is unique?"}
RDUCheck2 -->|"No"| RDUErr2["Log error:<br/>resolvedby attribute<br/>not unique"]
RDUErr2 --> RDUReturnZero2(["Return eid = 0"])
RDUCheck2 -->|"Yes"| RDUCheck3{"Attribute present<br/>in record?"}
RDUCheck3 -->|"No"| RDUErr3["Log error:<br/>resolvedby attribute<br/>missing from record"]
RDUErr3 --> RDUReturnZero3(["Return eid = 0"])
RDUCheck3 -->|"Yes"| RDUCheck4{"Value<br/>non-empty?"}
RDUCheck4 -->|"No"| RDUErr4["Log error:<br/>resolvedby attribute<br/>empty value"]
RDUErr4 --> RDUReturnZero4(["Return eid = 0"])
RDUCheck4 -->|"Yes"| RO2["'ResolveOwnership^apiRslv'<br/>apply insert/upsert<br/>semantics for<br/>designated attribute"]
RO2 --> RDUReturnRO2(["Return eid from<br/>ResolveOwnership"])
RDUReturnRO2 --> RBUKillNode["Kill sys.attr.resolvedby<br/>node from ResolvedRec"]
RBUKillNode --> RBUQuitFinal(["'ResolveByUnique^apiRslv'<br/>returns eid to<br/>ResolveTargetEntity"])
RBUReturnZero1 --> RBUQuitFinal2(["'ResolveByUnique^apiRslv'<br/>returns eid = 0"])
RBUReturnAnon --> RBUQuitFinal
RBUReturnRO1 --> RBUQuitFinal
RBUReturnZero2 --> RBUQuitFinal2
subgraph RO["ResolveOwnership^apiRslv internals"]
ROStart["Setup: read val,<br/>get uniqueness mode"] --> ROEmptyCheck{"Value<br/>empty?"}
ROEmptyCheck -->|"Yes"| ROErrEmpty["Log error:<br/>internal error,<br/>empty value"]
ROErrEmpty --> ROReturnZero(["Return eid = 0"])
ROEmptyCheck -->|"No"| RORangeCheck{"'IsRangeValue^sapiVld'<br/>has value ever<br/>been registered?"}
RORangeCheck -->|"No, never registered"| ROGenNew["'GENID^utils'<br/>generate new entity"]
ROGenNew --> ROReturnNew(["Return generated eid"])
RORangeCheck -->|"Yes, previously registered"| ROLiveCheck["'ResolveLiveEID'<br/>find current live<br/>owner of value"]
ROLiveCheck --> ROModeCheck{"Mode and<br/>owner liveness?"}
ROModeCheck -->|"UNQINSERT,<br/>owner live"| ROViolation["Log error:<br/>insert-unique<br/>violation"]
ROViolation --> ROReturnViolation(["Return eid = 0"])
ROModeCheck -->|"UNQINSERT,<br/>no live owner"| ROInsertFree["'GENID^utils'<br/>value released,<br/>generate new entity"]
ROInsertFree --> ROReturnInsertFree(["Return generated eid"])
ROModeCheck -->|"UNQUPSERT,<br/>owner live"| ROMerge["Merge into<br/>existing live owner"]
ROMerge --> ROReturnMerge(["Return owner eid"])
ROModeCheck -->|"UNQUPSERT,<br/>no live owner"| ROUpsertFree["'GENID^utils'<br/>identity released,<br/>generate new entity"]
ROUpsertFree --> ROReturnUpsertFree(["Return generated eid"])
end
RO1 -.-> ROStart
RO2 -.-> ROStart
