For data science & analytics teams
You built the customer 360. Half of it, anyway.
Your warehouse unifies everything structured - usage, billing, CRM fields, the outputs of your models. But the customer story is decided in calls, threads, tickets, and forwards - and that half never gets typed in, so it never lands in a table. You already know dark data: everything the business collects, stores and never uses. The missing half is worse than that. It's dark joins - and there is nothing to mine, because it was never captured at all. The relationship isn't in the data. It's in the work.
TL;DR - a dark join is a relationship that is real, load-bearing and actionable in your business, and exists in no schema anywhere in your systems. Where dark data is information you hold and never use, a dark join is one you never held - so it can't be mined, resolved, modelled or piped, and no join key was ever written. Noded is the context plane beside your analytical stack: it reads the action layer - calls, email, Slack, docs, tickets - and assembles a live Context Graph per account from pointers, not copies, with zero pipelines to build. Your team and every agent read it through one governed MCP layer. Keep Snowflake. Keep Looker. Keep Power BI.
Data science · Analytics engineering · BI · RevOps
The problem, precisely
Try writing the model your exec team keeps asking for.
Which renewals are blocked by unresolved support issues? Everyone in the business knows the answer. Nobody can query it.
select o.account_id, o.close_date, c.case_number, c.status from {{ ref('stg_salesforce__opportunities') }} o join {{ ref('stg_gong__calls') }} calls on o.account_id = calls.account_id -- fine join {{ ref('stg_zendesk__cases') }} c on ??? -- there is no key where o.close_date < current_date + 90
The blocker is not a missing staging model, a broken test, or a source you haven't loaded yet. There has never been a key. Not because someone forgot to model it, and not because an integration is misconfigured - but because the fact that this case blocks this renewal was never data. It was said on a Tuesday call, restated in an email, repeated in a Slack thread and written into a shared agenda doc. Four declarations of the same relationship, all of which entered your systems as unindexed strings inside text blobs, hanging off records that couldn't represent them.
This is the case that survives every fix you would reach for. Identity resolution gives you a better account_id; it does not give you blocks. Fuzzy matching and co-occurrence give you correlation, not the labelled relation. And link prediction can only propose edges whose generating process left a trace in the recorded data - here it left none, so the edge is absent from the corpus rather than latent in it.
A relationship that was never recorded cannot be derived from the records. It isn't in the data - it's in the work.
First, the ruling-out
Consolidating your stack? Good. So are we - just a different layer.
There is no second copy of your data.
Noded doesn't store your records - it keeps pointers to where they live, plus rank and relationships. Nothing new to govern, reconcile, or pay to scan. Disconnect tomorrow and everything is exactly where it always was.
There are no pipelines to babysit.
Nothing lands in Noded on a batch cadence, because nothing lands at all - the graph is assembled at ingest, from the work itself, automatically. Zero jobs to schedule, zero DAGs to debug, zero drift to chase.
Aggregate questions stay in your BI.
Noded doesn't do dashboards, and doesn't want to. Looker and Power BI keep answering what happened, on warehouse data - where they belong. Noded answers a different question: what's happening with this account right now, and why?
Not tool #4 in your consolidation - the layer the other three were never built to be.
The architecture
Your stack answers “what happened.” Noded answers “what's happening.”
You run an analytical plane: sources flow through your pipelines into Snowflake, dbt shapes them, your models run on them, and Looker and Power BI read the results. Built for structured data, batch cadence, and aggregate truth - keep all of it.
Every part of it reads the storage layer - schemas, tables, foreign keys, where the data already sits. What no part of it can see is the action layer - the call where the champion changed, the email thread where the eval stalled on SSO, the Slack forward that moved ownership, the comment on the account plan, the ticket blocking the renewal. This is not a transcription problem - calls are simply the most vivid example, and email is the largest neglected relationship store you own. That data is high-intention and perishable, and it never gets typed into the CRM, so your pipelines never see it - a blind spot precisely where the account's fate gets decided. The pair matters more than the usual structured-versus-unstructured split: it isn't that one kind of data is messier, it's that the relationships were declared in one layer and looked for in the other.
Snowflake joins the story.
Noded connects to Snowflake (and Databricks) to weave warehouse data into each account's context - usage signals, health inputs, and the outputs your models already produce. No pipelines to build or maintain. See integrations →
Your warehouse gets better inputs. Free.
As conversations happen, Noded writes high-confidence updates back into your systems of record - opt-in, attributed, reviewable. Your pipelines already read those systems, so the enrichment flows downstream into Snowflake on its own: cleaner dimensions, better features, truer dashboards.
Translation
Ingestion chaining™, in your vocabulary.
The name says “ingestion,” but there's no pipeline here. Ingestion chaining is automated relationship extraction over your event stream - it reads the action layer rather than the storage layer, watching how work moves between systems and building the graph from the trail. If you've built ranking or graph systems, you already know the three mechanisms:
Interaction rank - PageRank, for your enterprise.
Every touch is an edge: a forward, a mention, a status change, even a read. Records the work keeps reaching for climb in rank and earn their way into the graph. No schema mapping, no ontology workshop - the edges are observed, not declared.
Temporal decay - W(t)=W0·e−λt
Importance decays unless renewed. A record nobody touches for a business cycle falls out of the active chain. The graph tracks living work - it is structurally incapable of becoming an archive.
Intent filter - a classifier on the surrounding sentence.
“Blocked by NOD-231” chains the record in. “Closing as duplicate of NOD-231” keeps it out. Same identifier, opposite relationship. Dead ends are probed, marked, and released - so noise never enters the graph in the first place.
The honest version of the tradeoff: naive extraction - regex for anything shaped like a ticket ID - produces a graph so noisy it is worse than nothing, because a wrong edge in a customer graph costs more than a missing one. So we tune heavily toward precision over recall, the intent filter classifies the surrounding language rather than the identifier alone, and every edge carries provenance back to the sentence that created it. That's the right thing to interrogate any vendor on, including us - if nobody can show you the sentence behind an edge, be sceptical of the edge.
The result: a curated, current graph of what matters per account - assembled continuously, at ingest, with zero data engineering. Think of it as the feature-engineering pipeline for customer context that nobody on your team has to build or maintain. The full mechanics →
Your ontology reveals itself in how people work - not in your schemas.
Customer 360
A real customer 360 has two halves. You have one.
Different halves, different questions - you need both to have either.
Identity-resolved, structured, historical. It answers: which accounts fit the churn profile? How does usage trend by segment? What did the cohort do? You've already built this half - and it's the right tool for those questions.
Relationship-resolved, unstructured, live. It answers: why is this account at risk this quarter? Who's the champion now, and what did they say? What's blocking the renewal, and which Jira issue fixes it? No identity resolution recovers this half - the inputs were never captured as data.
The missing half is the dark joins - every relationship that is real and load-bearing in the business and exists in no schema anywhere in your systems. The relationship isn't in the data. It's in the work. The long-form version of this argument, including why MDM and knowledge graphs structurally can't reach it, is in the dark joins post →
The missing half isn't in any table, anywhere. Chain it, and the 360 is finally round.
Your stack
Built to sit beside the tools you chose.
Stays the analytical system of record.
Noded connects to bring warehouse data into each account's story, and enrichment flows back to it through the source systems your pipelines already read. Your warehouse gets better inputs. Nothing about your Snowflake architecture changes.
Stay your reporting layer.
Noded ships no dashboards and competes for none of your BI stack. What changes is upstream: CRM fields that used to depend on humans remembering to type now stay current automatically - so the dimensions your reports slice by finally match reality.
Get a distribution channel.
A churn score is only as valuable as the action it triggers. Piped into the Context Graph, a score becomes a signal - the thing that flags an account or lands in front of the CSM with the full story attached. Your models stop scoring into a dashboard nobody checks and start triggering work.
The precedent
You built a semantic layer so humans don't misread the warehouse. Agents need one too.
You already know why raw tables aren't enough: you built a semantic layer - metrics, definitions, governed joins - so every dashboard means the same thing by “ACV.” Noded is that same move, one layer up, for AI: one governed MCP layer over the whole customer stack, where you define what's exposed, who sees it, and how it's described - in your ontology, not a vendor's.
And answers behave like a materialized view, not a query: derived once, served from cache, invalidated the moment the underlying data changes. Same question, same answer, on every surface - at cache-hit cost. One governed MCP layer for the whole customer stack, and no servers for you to run.
You've made this argument before. You called it the semantic layer - and you were right.
Governance
The part your security review asks about.
Your records stay home.
The graph holds references, rank, and relationships - your records stay in the systems that own them, under those systems' permissions and audit trails.
Nothing changes until you say so.
Every write-back is opt-in, attributed, and reviewable. Exposure is yours to define - per source, per field, per agent.
Your data trains nothing.
Not our models, not anyone else's. SOC 2 audited. It works for you, and only for you. Security →
Honest answers
Questions data teams actually ask us.
Is “ingestion chaining” just ETL with a trademark?
No - nothing moves. ETL copies records into a destination; ingestion chaining observes how work touches records and builds a graph of pointers, rank, and relationships. If you want a lineage: it's closer to PageRank over your event stream, with temporal decay and an intent classifier, than to any pipeline.
Isn't this entity resolution, or relation extraction with a new name?
Entity resolution recovers identity, not relations. It will tell you that Acme Corp and ACME Inc. are the same account; it will never tell you that a case blocks a renewal, because that fact is not a property of either record. Relation extraction is closer, and it is genuinely part of what we do - but the usual framing assumes the relations live in a corpus you already index. Dark joins were declared once, in a sentence, in a tool with no schema for it. The edge is absent from the corpus, not latent in it, which is why link prediction over your warehouse cannot recover it either.
How do I know it isn't inventing edges?
Ask this hard. Three mechanical answers rather than reassuring ones: the intent filter classifies the surrounding language, so “blocked by” separates from “duplicate of”; the system is tuned for precision over recall, because a wrong edge in a customer graph costs more than a missing one; and every edge carries provenance back to the source sentence. If a vendor can't show you the sentence behind an edge, be sceptical of the edge - and that includes us.
We already have a customer 360 in Snowflake. Why isn't that enough?
It unifies everything that was captured as data. The risk to an account mostly isn't - it's in the call where the champion went quiet. That story never gets typed in, so it can't be piped in. The two 360s answer different questions; you need both to have either.
Does this add pipeline or governance load to my team?
No pipelines, no new store of record. Association happens automatically at ingest; the graph keeps pointers, not copies. Governance is subtractive - what isn't exposed doesn't exist as far as any agent is concerned.
Can Noded read from our warehouse?
Yes. Noded connects with Snowflake and Databricks to weave warehouse data - including the outputs of your models - into the story of every account. No pipelines to build or maintain. All integrations →
We're not doing much with LLMs yet. Is this premature?
It's the right order. Agent projects fail because of the mess underneath - fix the data layer once and every agent you ever deploy inherits the fix. Meanwhile the graph pays for itself the boring way: a current CRM, a self-serve account story, cleaner inputs to your warehouse. The agents can come whenever you're ready.
Where does Noded fit less well?
Noded shines when the account story flows through connectable tools - recorders, email, Slack, tickets, CRM. If your customer interactions never touch those systems, you'll get less from day one - though the warehouse connection still brings your structured signals into one account story.
The full argument
The white paper, if you'd rather forward something.
The relationship isn't in the data. It's in the work.
Everything on this page, argued properly and laid out to be read away from a browser - including the parts that are easier to evaluate with a pen than in a scroll.
- The query you cannot write, and why the key never existed
- Why MDM, ETL and knowledge graphs structurally can't find dark joins
- The full ingestion chaining design - rank, decay, intent filter - with its failure modes
- The build-it-yourself spec, in enough detail to actually cost it
- The objections, answered mechanically rather than reassuringly
On its way.
Your download should have started. If it didn't, grab it here - and check your inbox for a copy.
Download the PDF ↓Next step
Measure it on your own systems first.
The relationship isn't in the data. It's in the work. Don't take that on assertion - measure your own dark join rate. One account, thirty artifacts, an afternoon: count the references that point outside the record they're filed against, then check how many exist as an edge you could traverse. A high rate is normal - every environment we have seen scores high, including ours. It's a structural gap, not a hygiene failure, and it's a more useful number to take into a budget conversation than another data-quality score.
Nothing to implement to get started - connect your tools over coffee and start with one seat; reading and asking are always free. Complex environment? We'll run the project with you →