Skip to main content
ConceptDraft · not yet verified

Edge Properties

Agents need to ask memory exact questions — every record about Acme, how many records mention the renewal — that meaning alone cannot answer. Edge properties put label:value pairs on records; every record sharing a value is joined by one edge, with no graph database to run; records are gathered by intersecting or uniting those edges, or walked from one to the next; a lane's source types can hold agents to one vocabulary; and every change to a record's edge properties is kept as a new version.

Challenges addressed: Auditable Decision-Making, Context Window Limits and Lossy Compaction, Tracking Changes Through Time, Point-in-Time Recall, Multi-Agent Coordination.

Concepts​

When two or more records share the same label:value, an edge is imputed: one N-ary edge that touches every record carrying it. The records and their edge properties form the Edge Property Graph.

Every source record carries edge properties: label:value pairs like person:Sarah or topic:database. When two or more records share an edge property, an edge — a grouping — is imputed.

In an ordinary graph an edge joins exactly two nodes. Here a single label like person:Sarah is one N-ary edge that touches every record about Sarah at once — five records, five hundred, it does not matter. One label, one edge, N members.

There is no separate edge table. The shared value is the edge. The records are the vertices and the edge properties are the edges of the Edge Property Graph (EPG). It is a hypergraph: each edge property is a hyperedge joining every record that carries it, held in PostgreSQL without a graph database. See the EPG.

Four records of different source types linked by the shared edge properties org, person and topic

Notice the records in the figure are different source types — a contact, a meeting, a deal, a report — and on their own they're inert. It's the shared labels (person:Sarah, org:Acme, topic:renewal) that weave them into one fabric: each common label is an N-ary edge touching every record that carries it. Common labels connect records across types, sources, and sessions. Stack a second label and you've walked from one set into its intersection.

Two kinds of edge property​

KindWhat it saysWritten byGoverned by
Agent-specified — any label:value, such as org:Acmethe records that share it have something in common: an imputed edgethe agent, with e_ingest, e_update and e_property add / removethe policy: which labels a lane allows, through its source types, and which lanes the agent profile may write
Built-in — the reserved labels e_connect, e_group, e_adjustmentsomeone declared a relation, a membership or an evolution: an asserted edgethe engine, which mints each value: connections (connect / disconnect), groups (group / ungroup), adjustments (adjusts / unadjust)the engine: these labels cannot be written or removed any other way

An imputed edge is an inference: it says records have something in common, not what passed between them. A built-in edge is an assertion. The agent instructions the engine ships keep the two apart: person:John written on Sarah's record reads exactly like a record about John, so a relation between them belongs in a connection.

Idioms​

Several idioms are built on that one mechanism.

IdiomHow it is writtenMembersSee
Agentic annotationThe caller's edge properties, on e_ingest, e_update or e_property addEvery record that carries the valueThis page
Adjustment (linked list)e_ingest with adjusts: the engine mints e_adjustment:<label>_<32 hex> and writes it on the new record and on each record it adjusts. Adjusting the newer record again adds the next linkThe new record and the records it adjusts; a chain of links over timeUpdates and adjustments
Connection (1-to-1)e_property connect: e_connect:<hint>_<32 hex>Exactly twoConnections
Group (membership)e_property group: e_group:<hint>_<32 hex>Two or moreGroups
File hierarchyFolder Intake writes folder_id on the folder's record and each file's record, and file_id on a file's record and each of its partsA folder's records; a file's record and its partsDocuments and files

e_adjustment values do not appear in e_property listings or in intersect and union; e_read shows them under adjustments, and traverse walks them. A correction is not an edge property: it is a separate object attached to its record.

Hygiene, and source types​

Edge properties are the connection construct, so their hygiene matters: it is what lets agents curate, connect and manage records predictably. org:Acme and company:Acme are different edge properties and form no edge.

The optional source type exists for that reason. A lane that declares source types is closed: each source type names the labels a record of that type may carry, and a write with any other label is refused. That keeps the labels from sprawling. Source types and their labels are declared in the policy, not in code.

Queries are set operations​

Each edge property is a set of records. A query can intersect sets (records that carry every one), union them (any one), or run them as a timeline (the same sets, ordered by time). Traverse starts at one record and walks its edges to the records that share them. See the EPG and temporal retrieval.

Where edge properties come from​

SourceHowShown by e_read and e_propertyCrosses to peers, kept in the archive
The callere_ingest properties, e_update, e_property addYesYes
The engineReserved labels: e_connect and e_group from connect and group; e_adjustment from e_ingest adjustse_connect and e_group yes; e_adjustment under adjustmentsYes

An edge property is written as one string. The engine splits it at the first colon. Spaces in the label become underscores. The value is trimmed and otherwise kept as written. A string with no colon is given the label general. Labels that begin with e_ are reserved: e_ingest and e_update refuse a call that passes one, and e_property add skips it and reports it under rejected.

Edge Property Lifecycle​

Declared edge properties — the caller's, and the reserved values for connections, groups and adjustments — are part of each entry in the record's ledger. The edge-property table that retrieval reads is a cache of the latest entry. A declared edge property's id is derived from the fact it states: ep_ and the first 32 hexadecimal characters of a SHA-256 over the record id, schema, label and value, so every engine projecting the same entry gives it the same id. Tags are not in the ledger; they are an index over the content.

A record's edge properties are part of its whole state. Every change to them writes a new version of the record, and every earlier version is kept in the record's history.

ChangeCallWhat it doesAudit
Add, when writtene_ingest propertiesThe first version carries themsr_ingested
Add latere_property addA new version with the added values. Add-only: values already held are reported, not repeatedproperty_added, one per value
Changee_update propertiesA new version. Merged by label: each label named has all its values replaced; labels not named stay as they weresr_updated
Remove a labele_property remove with labelsA new version without that label and its valuesproperty_removed, one per value
Remove valuese_property remove with propertiesA new version without the matching valuesproperty_removed, one per value

An update that changes nothing writes nothing. Earlier versions are read with e_audit inspect on the update's event.

Reserved labels. The e_* labels are written only by the engine: connect, group and e_ingest adjusts write them, and disconnect, ungroup and unadjust remove them. e_ingest, e_update, e_property add and e_property remove refuse them. See connections and groups.

Example​

See which labels exist before inventing one.

e_property {"action": "list"}
{"labels": [{"label": "org", "sr_count": 14}, {"label": "topic", "sr_count": 9}, {"label": "person", "sr_count": 6}]}

Write a record that reuses them, then gather every record on both edges.

e_ingest {"content": "Sarah is the account owner for Acme.", "properties": ["org:Acme", "person:Sarah", "topic:renewal"]}
e_gather {"action": "intersect", "match": ["org:Acme", "topic:renewal"]}

Implications​

add only adds. It never removes an edge property. To replace the values of a label, use e_update; to remove particular values or a whole label, use e_property remove. See the lifecycle above.

A closed lane checks labels at write time. e_ingest and e_update refuse a label or value the record's source type does not allow. e_property add checks only the combined label list of the lane's source types, and does not check values.

Adding an edge property needs write access to the record's lane.

Reference​

The tools, their arguments and their refusals: e_ingest, e_property and e_gather.