Two Families: Operational Nexus vs. Owner Identity
Watchline connects landlord nodes with six edge types in two families. The
operational-nexus edges (inherited from Who Owns What — shared name, shared office) answer
"who operates through here." The owner-identity edges (Watchline's four) answer
"who actually owns this." They feed different graph layers — which is exactly why the
same graph can over-merge on a shared back-office (the Portfolio) yet resolve owners correctly
(ResolvedEntityV2). Every edge is an undirected pair over
landlords_with_connections nodeids (Actor ACT-LL-<nodeid>).
◆ At a glance — the six edges
| Relationship · method | Family | Signal | Built from | Precision guard |
|---|---|---|---|---|
CONNECTED_BY_NAME | nexus | shared owner name | WoW name_match_info | zip/street gate (WoW) |
CONNECTED_BY_ADDRESS | nexus | shared business office | WoW bizaddr_match_info | aggregator degree cap |
CONNECTED_BY_SPLINK · splink-fellegi-sunter | identity | same person (probabilistic) | Splink model on HPD contacts | aggregator-address mask · name-anchored blocking |
CONNECTED_BY_SPLINK · registered-llc | identity | same DOF owner entity | PLUTO ownername | entity markers · degree cap 100 |
CONNECTED_BY_SPLINK · curated-same-owner | identity | hand-verified same owner | curated table | human evidence required |
CONNECTED_BY_DEED · acris-deed | identity | co-conveyed on one deed | ACRIS deeds | latest-deed · successor · hub cap |
All four owner-identity edges emit weight-100 clique/star groups over the co-owned nodes; the two nexus edges carry Who Owns What's own match weight (name weighted above address).
I. Operational-nexus edges (legacy / WoW)
Materialized by pipeline.py straight from Who Owns What's precomputed match columns on
landlords_with_connections. Deterministic — dropped/rebuilt cheaply via MERGE.
These say two records operate through a shared name or office; that is not proof of
shared ownership (a shared back-office is a nexus, not an owner).
CONNECTED_BY_NAMEoperational nexus
- Source
- WoW's
name_match_infoJSON on eachlandlords_with_connectionsnode — its own head-officer name matches. - How built
pipeline.pyunrolls each node's name-match list into undirected(a)-[:CONNECTED_BY_NAME]-(b)pairs.- Guard
- WoW's rule gates a name match on same zip + street similarity, so it doesn't fuse common names city-wide.
- Weight
- WoW's match weight — weighted above address (a shared name is stronger evidence of common control than a shared office).
- Consumed by
- the Portfolio layer (operational nexus).
CONNECTED_BY_ADDRESSoperational nexus
- Source
- WoW's
bizaddr_match_info— landlords sharing a Geosupport-standardized business address. - How built
- Same unroll as name, into
(a)-[:CONNECTED_BY_ADDRESS]-(b)pairs. - Guard
_aggregator_addressesdrops any office shared by more thanMAX_ADDR_DEGREElandlords (a registered-agent / mail-drop hub) before building edges.- Weight
- WoW's match weight — below name.
- Consumed by
- the Portfolio layer. This is the edge that over-merges when a real shared office slips under the degree cap — the Miller case.
II. Owner-identity edges (Watchline)
Watchline's four owner-identity signals. Each is Neo4j-free — its module returns a
[src, dst, weight] frame that pipeline.py::step_splink loads; each stamps a distinct
method for provenance. Three ride the CONNECTED_BY_SPLINK relationship (with a
separate CONNECTED_BY_DEED for the deed signal).
CONNECTED_BY_SPLINKsplink-fellegi-sunterowner identity
- Source
splink_bridge.pyruns the Splink model (defined insplink_source.py::_settings) full-population;splink-fellegi-sunteris stamped inpipeline.py.- Features
- 5 comparisons:
last_name&first_name(Jaro-Winkler + term-frequency),biz_house(Levenshtein),biz_street_norm(Jaro-Winkler, suffix-normalized),biz_zip(exact + TF). - Guard
- Aggregator-address mask — address fields are blanked for any office shared by >25 landlords, so a shared back-office contributes no match. Name-anchored blocking — a pair is only scored if it shares
last_name+ first initial (the address-only blocking rule was removed as a precision hole). - Weight
- 100 (clique/star over each cluster's nodes).
- Consumed by
- Portfolio · OwnerGroup · ResolvedEntityV2.
CONNECTED_BY_SPLINKregistered-llcowner identity
- Source
llc_edges.py— the DOF owner-of-record (pluto_latest.ownername). Fills the gap WoW misses: it links on the head officer (a person), never the registered owning entity.- How built
- Every entity owning ≥2 buildings emits a clique between those buildings' landlord nodes. Same legal-entity name == same owner, definitionally — precision-1 by construction.
- Guard
- Must match an entity marker (
LLC/CORP/REALTY…, whole-word); institutional owners (HDFC/NYCHA/City) excluded; degree cap of 100 lots (above = placeholder/nominee). - Weight
- 100.
- Consumed by
- Portfolio · OwnerGroup. Not read by ResolvedEntityV2 — a name-only LLC match links co-officers (distinct people) of one entity, so it isn't a same-party signal (only an id+jurisdiction
registered-llc-idwould be). The edges still exist and drive the Portfolio and OwnerGroup layers; ResolvedEntityV2's identity clustering simply ignores them.
CONNECTED_BY_SPLINKcurated-same-ownerowner identity
- Source
curated_owners.py— a hand-maintained table of verified "these nodes are the same real owner," matched by normalized name variants (+ optional BBL disambiguator).- Why
- The residual the model cannot close: an operator whose records share only an exact, rare full name — no shared corp, no shared address — that the model was trained to distrust. Force-emits a clique so WCC merges it. (Croman's ROCKSOLID remnant → CENTENNIAL main.)
- Guard
- Human responsibility. Add only with cited evidence (ownership docs, shared principal); edges only ADD, so it can merge fragments but never split. Seeds stay within one surname.
- Weight
- 100.
- Consumed by
- Portfolio · OwnerGroup · ResolvedEntityV2 (top precedence — a deterministic, human-verified signal).
CONNECTED_BY_DEEDacris-deedowner identity
- Source
deed_edges.py— ACRIS deeds (real_property_master/legals/parties). Buildings conveyed on one deed share a grantee → same owner, regardless of LLC names. The only signal that pierces the shell game.- How built
- Two sources unioned per deed: (A) held-since — buildings whose latest deed is a shared multi-parcel deed (staleness guard); (B) linked-successor — joint purchases the grantee later re-deeded into per-building shell LLCs. One clique per deed.
- Guard
- Latest-deed rule (no stale merges); successor must be a shell (≤3 buildings, else an arms-length sale); 2–25 parcels (mega-deeds excluded); deed-hub cap drops serial co-investors (>20 deeds).
- Weight
- 100.
- Consumed by
- OwnerGroup only — never the Portfolio (a deed is ownership evidence, not an operational nexus), and not read by ResolvedEntityV2 (deed is unioned into identity only in the OwnerGroup layer). The
CONNECTED_BY_DEEDedges remain in the graph; ResolvedEntityV2's identity clustering ignores them.
III. Which layer consumes which
Three layers read these edges, and the differences are the whole architecture. The Portfolio
(GDS WCC+Louvain, algorithms.py) groups by operational nexus. The two ownership
layers group by owner identity — OwnerGroup (current-materialized) and
ResolvedEntityV2 (the newer, method-selective resolution).
| Edge · method | Portfolio name + addr + splink | OwnerGroup splink ∪ deed | ResolvedEntityV2 method precedence |
|---|---|---|---|
CONNECTED_BY_NAME | ✓ | — | — |
CONNECTED_BY_ADDRESS | ✓ | — | — |
SPLINK · splink-fellegi-sunter | ✓ | ✓ | ✓ |
SPLINK · curated-same-owner | ✓ | ✓ | ✓ |
SPLINK · registered-llc | ✓ | ✓ | ✗ name-only excluded |
DEED · acris-deed | ✗ | ✓ | ✗ deed excluded |
CONNECTED_BY_ADDRESS, so a shared office fuses its members
(the Miller over-merge). The owner-identity layers never read the raw address/name edges — they group only on
identity signals — so the same shared office does not merge those owners. Reading owner identity from
the resolved-entity layer, not the Portfolio, is the correction.
curated-same-owner > registered-llc-id (not yet in the
graph) > splink-fellegi-sunter — and deliberately excludes both name-only
registered-llc (it links co-officers, i.e. distinct people, of one LLC) and
CONNECTED_BY_DEED (unioned into identity only in the older OwnerGroup layer). Those edges
stay in the graph and drive the Portfolio/OwnerGroup layers — ResolvedEntityV2's identity clustering
simply doesn't read them. So the same CONNECTED_BY_SPLINK relationship is read
differently depending on its method.
OwnerGroup and ResolvedEntityV2 are owner-identity layers, but they do
not cluster over the same edges. They share only splink-fellegi-sunter +
curated-same-owner. OwnerGroup additionally unions
CONNECTED_BY_DEED (and the name-only registered-llc subtype);
ResolvedEntityV2 reads neither. So the accurate shorthand is
OwnerGroup = SPLINK (all methods) ∪ DEED versus
ResolvedEntityV2 = curated-same-owner + splink-fellegi-sunter only. The
∪ DEED clause belongs to OwnerGroup alone — do not attribute it to
ResolvedEntityV2.
When the two layers happen to agree — e.g. Miller's 7 owners — it is because the deciding signal there is the exclusion of
CONNECTED_BY_ADDRESS, which both layers share,
not because they read identical edges. Deed- and LLC-heavy portfolios are exactly where they diverge:
OwnerGroup merges on the deed/LLC evidence, ResolvedEntityV2 does not — which is
why ResolvedEntityV2 currently shows lower recall on those cases until an id-based
registered-llc-id edge is built.