Skip to content

None versus Not recorded

An empty answer is two different statements, and they must never share a shape.

  • None — the address bound: the store holds the named attribute somewhere in your visible scope, the count ran, and nothing is at this coordinate. There are none at this spelling. You may stop looking once you have checked the spelling (below).
  • Not recorded — the address did not bind. Nothing was addressed, so nothing is known; the documents may well contain it under a name the store does not hold.

The discriminator is enumeration.bound, and it is decided by the store's vocabulary on the attribute axis alone (clause_type for prose): an address binds when the count found rows, or — when it found none — when any row in your visible scope carries the named attribute. Entity and period are not consulted for binding, and every axis is matched case-sensitively with surrounding whitespace trimmed: Revenue is not revenue; revenue is.

None: bound, and empty

revenue is a known attribute here; no document reports it for FY2021.

r = client.post("/v1/public/facts", json={
    "workspace_id": WS, "question": "revenue", "mode": "enumerate",
    "coordinate": {"attribute": "revenue", "period": "FY2021"}})
body = r.json()
print(body["enumeration"])
print(body["coverage"]["completeness_licensed"], body["coverage"].get("withheld_because"))
{'coordinate': {'attribute': 'revenue', 'period': 'FY2021'}, 'exist': 0, 'delivered': 0, 'truncated': False, 'bound': True}
True None

completeness_licensed: true over an empty set is the answer none, and it is the one an agent can act on.

Not recorded: unbound

net_sales is not a name this store holds (it says revenue), and neither is Revenue — the attribute is matched case-sensitively.

for attribute in ("net_sales", "Revenue"):
    r = client.post("/v1/public/facts", json={
        "workspace_id": WS, "question": "net sales", "mode": "enumerate",
        "coordinate": {"attribute": attribute}})
    body = r.json()
    print(body["enumeration"])
    print(body["coverage"]["completeness_licensed"], body["coverage"]["withheld_because"])
{'coordinate': {'attribute': 'net_sales'}, 'exist': 0, 'delivered': 0, 'truncated': False, 'bound': False}
False unbound
{'coordinate': {'attribute': 'Revenue'}, 'exist': 0, 'delivered': 0, 'truncated': False, 'bound': False}
False unbound

exist: 0 here says nothing about the documents. Discover the name with mode="explore" and enumerate again.

The edge: an unknown entity or period reads as None, not Not recorded

Because binding looks at the attribute only, a coordinate that names an entity or a period the store has never seen is a bound, empty address. This store holds Acme Corp and FY2023; none of the three spellings below is a row, and all three read as none:

for coordinate in ({"entity": "Zzz Nonexistent Corp", "attribute": "revenue"},
                   {"entity": "acme corp", "attribute": "revenue"},
                   {"attribute": "revenue", "period": "FY 2023"}):
    r = client.post("/v1/public/facts", json={
        "workspace_id": WS, "question": "revenue", "mode": "enumerate",
        "coordinate": coordinate})
    body = r.json()
    e = body["enumeration"]
    print(coordinate, "-> bound:", e["bound"], "| exist:", e["exist"],
          "| licensed:", body["coverage"]["completeness_licensed"])
{'entity': 'Zzz Nonexistent Corp', 'attribute': 'revenue'} -> bound: True | exist: 0 | licensed: True
{'entity': 'acme corp', 'attribute': 'revenue'} -> bound: True | exist: 0 | licensed: True
{'attribute': 'revenue', 'period': 'FY 2023'} -> bound: True | exist: 0 | licensed: True

So None on a coordinate that names an entity or a period licenses no row at this exact spelling — not this entity reports no revenue. Before acting on exist: 0 there, read the spellings the store holds off the closed set at the attribute alone (page through it if truncated is true):

r = client.post("/v1/public/facts", json={
    "workspace_id": WS, "question": "revenue", "mode": "enumerate",
    "coordinate": {"attribute": "revenue"}, "output_mode": "compact"})
print(sorted({(f["entity"], f["period"]) for f in r.json()["facts"]}))
[('Acme Corp', 'FY2022'), ('Acme Corp', 'FY2023'), ('Acme Corp', 'Q1 2024')]

That set is closed (exist == delivered), so every entity and period spelling at the attribute is in it. A spelling absent from it is absent from the store, and only then is exist: 0 for it none in the full sense.

The same rule inside limma_verify

An existence check with expect: "absent" is confirmed only where the coordinate bound. An address nothing knows about cannot confirm an absence — and, by the same rule, a bound attribute with an unknown entity confirms one:

r = client.post("/v1/public/verify", json={"workspace_id": WS, "checks": [
    {"kind": "existence", "expect": "absent",
     "coordinate": {"attribute": "revenue", "period": "FY2021"}},
    {"kind": "existence", "expect": "absent",
     "coordinate": {"attribute": "net_sales"}},
    {"kind": "existence", "expect": "absent",
     "coordinate": {"entity": "Zzz Nonexistent Corp", "attribute": "revenue"}},
]})
for check in r.json()["checks"]:
    print(check["verdict"], "|", check["reason"])
verified | absent_at_bound_coordinate
unverifiable | coordinate_unbound
verified | absent_at_bound_coordinate

verified / absent_at_bound_coordinate is a finding. unverifiable / coordinate_unbound is the verifier saying I could not look — which is a different word from no, on purpose. The third line is the edge above from the other side: the absence it verifies is at this spelling of the entity.

Absence on the relation lane

On the coordinate lane "not recorded" is decided per address, from the attribute vocabulary. A relation query decides it per entity, from a recorded fact: a coverage row — source S was read for relation R on entity E — written by the load that looked. A structured export writes one for every entity it pulls, and a column such as screened can declare one for another relation; a pack says who may write them. Absence is then a row of its own, and relations.absence carries the verdict for each entity:

kind when bound_by denominator licenses
none a coverage row says a load looked, and the entity holds zero rows of the relation the source whose coverage row binds it 0 no row of this relation is recorded for this entity in source bound_by as of the coverage row's as_of — nothing about sources that did not cover it
not_recorded no binding coverage row: nobody declared looking, or every source that did states a row a correction retired (corrected_rows), or a source states a row its loader could not read (the verdict then carries withheld: one {source_id, reason} per such source) null null NOTHING — never none, never clean

An entity that holds rows of the relation gets no verdict (absence.entity is null for it): it is recorded, and its rows are the answer. The examples use roster(client), where the roles export says it checked screenings for everyone but Yusuf, and three screenings exist:

from docs.examples.roster import roster
ws = roster(client).workspace_id
for person in ("halvard_quist", "teodor_brask", "yusuf_alderane"):
    body = client.post("/v1/public/facts", json={
        "workspace_id": ws, "question": "screenings", "mode": "enumerate",
        "relation_query": {"relation": "screening", "entity_id": person}}).json()
    rel = body["relations"]
    verdict = rel["absence"]["entity"]
    print(person, "| bound:", rel["bound"], "| count:", rel["count"],
          "| licensed:", body["coverage"]["completeness_licensed"])
    if verdict is None:
        print("    no verdict: the entity holds rows")
    else:
        print("    kind:", verdict["kind"], "| denominator:", verdict["denominator"],
              "| bound_by is a source:", verdict["bound_by"] is not None,
              "| coverage declared_by:", [c["declared_by"] for c in verdict["coverage"]])
halvard_quist | bound: True | count: 1 | licensed: True
    no verdict: the entity holds rows
teodor_brask | bound: True | count: 0 | licensed: True
    kind: none | denominator: 0 | bound_by is a source: True | coverage declared_by: ['source']
yusuf_alderane | bound: False | count: None | licensed: False
    kind: not_recorded | denominator: None | bound_by is a source: False | coverage declared_by: []

Teodor has no screening recorded — a finding with its evidence (coverage names the source that looked and declared_by: source, the export's own column). Yusuf's screening is not recorded — nobody looked, and a missing screening is not a passed one.

Workspace-wide, without entity_id, absence.split counts every known entity into none / not_recorded / recorded, and absence.none / absence.not_recorded list the verdicts (capped at 200, truncated says so). A count taken while some entity is not recorded withholds the licence — the rows it counted are exact, the claim there are no others is not:

from docs.examples.roster import roster
ws = roster(client).workspace_id
body = client.post("/v1/public/facts", json={
    "workspace_id": ws, "question": "screenings", "mode": "enumerate",
    "relation_query": {"relation": "screening"}}).json()
rel = body["relations"]
print("count:", rel["count"], "| split:", rel["absence"]["split"])
print("none:", [v["entity_id"] for v in rel["absence"]["none"]],
      "| not_recorded:", [v["entity_id"] for v in rel["absence"]["not_recorded"]])
print("licensed:", body["coverage"]["completeness_licensed"], body["coverage"]["narrowed_by"])
print(sorted(rel["absence"]["licenses"]))
count: 3 | split: {'none': 1, 'not_recorded': 1, 'recorded': 3}
none: ['teodor_brask'] | not_recorded: ['yusuf_alderane']
licensed: False ['entities_not_recorded']
['none', 'not_recorded']

absence.licenses states both sentences on the wire, so an agent that reads only the response still has the rule. A third, licenses.withheld, is there only when some verdict in the block lists withheld — a document-store export held a row for that entity that its loader could not read, so the entity is not_recorded and never none while that source is current (the example on that page prints one). none is taken over rows of the RELATION, not rows matching where: an entity whose rows exist and do not match is recorded, not absent — "no failed screening" is a count over rows that exist, never an absence verdict. The search verb reports the same verdict per condition group (search).