Skip to content

The Network ​

The "network" is the foundational concept Pathorah is built on. Everything else — pathfinding, introductions, company graphs, AI enrichment — exists to traverse and grow this network. This page explains it from the ground up: who's in it, who owns what, how edges form, and how the network composes with the heterogeneous graph.

What Is "The Network"? ​

For any given user, their network is the subgraph of nodes they can reach via a chain of trusted edges. It includes:

  • The user themselves (a User node)
  • Their Contacts — people they know personally (Contact nodes they own)
  • Their personal connections — Connection rows linking them to their contacts and to other users
  • Reachable companies and branches — any Company or Branch node that one of the above is EMPLOYED_AT, or that any reachable company is connected to via a CompanyRelationship
  • Other users they reach transitively through the chain (friends-of-friends-of-employees-of-partners-of...)

Pathorah's job is to find the shortest, warmest chain from the user to any target in this expanding sphere.

Two Kinds of Nodes Live in the Network ​

The network used to be person-only. After the heterogeneous graph launch (2026-04-07), there are four:

Node TypeWhat It RepresentsSource of Truth
userA registered Pathorah userUser collection
contactSomeone in a user's address book who isn't (yet) a userContact collection
companyA canonical organizationCompany collection
branchA physical or virtual location of a companyBranch collection

Both user and contact nodes participate in the network identically. The only difference is contact nodes can't log in or initiate intro requests — they only respond when someone reaches them.

Two Kinds of Edges Form the Fabric ​

Personal edges (the warm-network plane) ​

These live in the Connection collection and are owner-scoped — each row is created and owned by one user. They represent a direct first-degree relationship:

  • OWNS_CONTACT — User has Contact in their address book
  • KNOWS — Mutual personal connection
  • LINKED_TO — Bridge between a Contact and a User who share an identity (used by userLinkAdapter to fold a contact's identity onto a real user when they sign up)

Personal edges carry three quality signals:

  • warmth — how strong the relationship is (0–100), decayed over time by the nightly decayWarmth cron
  • trustScore — how much the owner trusts the contact (0–100, manually set or inferred)
  • lastInteractionAt — used to compute a recency multiplier on every read

The combination is computed in edgeScoring.ts as calculateEdgeScore(warmth, trust, recency, 50). Until the heterogeneous-graph rollout, calculateWarmthDecay was defined in graphUtils.ts but never actually called — that's now fixed and decay is real.

Knowledge edges (the world-graph plane) ​

These live in the Employment, CompanyRelationship, and KnowledgeEdge collections and are globally shared — they aren't scoped to one user's address book. Any user traversing a path can use any knowledge edge.

  • Employment rows produce EMPLOYED_AT, EMPLOYS, REPRESENTS, REPRESENTED_BY, BRANCH_OF edges
  • CompanyRelationship rows produce PARTNERS_WITH, SUPPLIES, CUSTOMER_OF, COMPETES_WITH, ACQUIRED, INVESTED_IN, SUBSIDIARY_OF, JV_WITH
  • KnowledgeEdge is the escape hatch for the future: HAS_INDUSTRY, OFFERS_PRODUCT, CERTIFIED_IN, etc.

This is what makes Pathorah a real graph rather than a contact manager. A user who has no personal connection to the Vodacom CFO might still reach them via:

You → (your contact) Bob → (employed at) MTN → (PARTNERS_WITH) Vodacom → (employs) Vodacom CFO

The first hop is a personal edge from your owner-scoped subgraph. Hops 2–4 are knowledge edges anyone can traverse.

Ownership and Scope: Who Sees What ​

Your Pathorah view:
┌─────────────────────────────────────────────────────────┐
│ Personal plane (yours alone)                             │
│   ├── Your Contacts                                       │
│   ├── Your Connections                                    │
│   └── Your Circles                                        │
├─────────────────────────────────────────────────────────┤
│ Knowledge plane (shared with everyone)                   │
│   ├── All Companies and Branches                          │
│   ├── All Employment edges                                │
│   ├── All CompanyRelationships                            │
│   └── All KnowledgeEdges                                  │
└─────────────────────────────────────────────────────────┘

Two users searching for the same target will get different paths because their personal planes differ. They'll see the same companies, same employments, and same company relationships — but each user's BFS starts from their own root and traverses their own contact set first.

Circles: Grouping the Personal Plane ​

A user can group their contacts into Circles — soft-edge collections like "Family", "Investors", "Eswatini Tech". Circles are not edges themselves; they're filters. Pathfinding can be restricted to "only paths that start through my Investors circle" via the API.

Circles also drive permission-style features:

  • "Share my new post with the Eswatini Tech circle"
  • "Hide my company info from Family circle members"
  • Future: scoped intro request templates per circle

How Edges Are Created ​

EdgeCreated ByLifecycle
Personal Connection (OWNS_CONTACT, KNOWS)User adds a Contact, accepts a connection request, or imports their address bookStays until manually removed; warmth decays nightly
EmploymentUser declares their own job, creates one for a Contact, or backfilled from User.company stringsLifetime tied to start/end dates; goes to isCurrent: false when an end date is set
CompanyRelationshipUser with companyAdmin permission, global admin, AI enrichment, or public-data backfillManually managed; admins can mark isActive: false instead of deleting
KnowledgeEdgeMostly admin/enrichment for now; UI-driven creation coming for taxonomy managementSoft-deletable via isActive
BRANCH_OFImplicit — emitted by employmentAdapter whenever a Branch is expandedAlways exists when a Branch row exists; weight is structural (95)

Network Growth Loops ​

The network grows in three loops, each with a different mechanism and timescale:

  1. Personal loop — users add contacts, accept connections, import their address book. Days to weeks.
  2. Employment loop — users declare their own jobs (and backfill turned existing free-text strings into Employment rows). Hours to days.
  3. Knowledge loop — admins, AI enrichment, and (future) public-data sync expand the company knowledge graph. Continuous, async.

Pathfinding gets stronger from all three. Loop 2 is the highest-leverage one for an individual user — declaring your current employer instantly opens up paths to every coworker, every employee of every partner company, and every customer/supplier on record.

Performance Bounds ​

The network is unbounded in theory, but every BFS run respects:

  • maxDepth — default 5, controls how many hops the search will take
  • maxFanout per node — employmentAdapter caps each company at 200 employees per expansion, ranked verified-rep > rep > current+senior > everyone else, so a 10,000-employee company doesn't blow up the frontier
  • maxPaths — default 10, the BFS stops once it has found N distinct paths
  • timeoutMs — default 8 seconds, hard wall-clock cutoff
  • Per-depth visited cache — prevents re-expanding the same node at the same depth twice

See Pathfinding Engine for the algorithmic details.

What's Not in the Network (Yet) ​

  • Project / Event nodes — would let "we worked together on project X" be a first-class edge
  • Reports-to / org chart edges — currently only the binary "you work here" is captured; "you report to her, she reports to him" isn't
  • Affinity / interest edges — knowing that two people share an interest (cycling, fintech) without a direct relationship
  • Implicit cross-network bridges — when two users both have a Contact with the same email/phone, those Contacts could be inferred as the same person and the networks bridged. Currently only the explicit userLinkAdapter does this

These are all in the backlog and tracked there.