01-projects/phdata

CAF Grounding-Asset Storage Pattern — Where Unstructured Supporting Blobs Live at Scale

2026-06-17·status: active
cafstoragearchitecturegrounding-assets

CAF Grounding-Asset Storage Pattern

Answers: where do CAF's unstructured grounding/supporting assets (competitive intel, meeting notes, write-ups — per-company, eventually thousands of companies) live so the system scales past one engineer's laptop to a multi-collaborator, multi-harness team, AND how do those blobs link back to the structured catalog?

Reconciles with the locked decisions in [[2026-06-15-caf-architecture-decisions-and-meta-council]], [[2026-06-15-caf-catalog-data-model-erd]], [[2026-06-14-caf-restructure-organizing-brief]], and the isolation/retention research in [[2026-06-17-multi-tenant-governance-shared-vector-store]].


Recommendation (decision-first)

Adopt the standard "object store as system-of-record + catalog pointer row + in-perimeter retrieval index" pattern, landed on the stack you already locked. Concretely:

  1. Bytes live in a Snowflake internal stage (object store), one flat namespace, not per-client folders. The stage IS the blob system-of-record. This is the Snowflake-native form of S3 — same object-store semantics, but inside the perimeter you already chose, governed by the same RBAC, and reachable by the same MCP data plane. No second cloud to manage.
  2. A thin typed grounding_asset row in the catalog is the pointer + metadata. It holds the stage path, source, sensitivity_tier, retention_class, target_company_id, author, timestamps — and optionally an M:N link to the use_case/citation it grounds. The bytes are in the stage; the catalog row is how everything (UI, MCP, tailoring agent) finds and governs them.
  3. Retrieval is Cortex Search over the staged text, in-perimeter. Embeddings + retrieval stay inside Snowflake (per [[2026-06-17-multi-tenant-governance-shared-vector-store]]); no separate Pinecone/Weaviate to audit independently. The tailoring agent grounds itself by Cortex-searching the asset corpus, then citing the grounding_asset row.
  4. Authoring ergonomics ride Google Drive as the human front door, with a one-way sync into the stage. Engineers keep writing competitive intel and meeting notes in Drive (where collaboration already works); a scheduled/triggered sync lands new/changed files into the stage + upserts the pointer row. Humans never PUT to a stage by hand. Drive is the authoring surface; the stage is the system-of-record; the catalog is the index.

One line: the blobs are Snowflake-staged objects, the catalog carries a typed pointer row, Cortex Search makes them machine-retrievable in-perimeter, and Google Drive stays the human authoring front door via a one-way sync — so engineers never touch object-store plumbing and the machine never reads from a laptop.


The prescribed industry pattern

This is a solved class of problem: unstructured per-entity knowledge assets at scale that must be both human-collaborable AND machine-retrievable. Mature teams converge on a three-layer split, and the failure mode is always trying to make one layer do two jobs:

Layer Job What it is NOT
Object store (system-of-record for bytes) Durable, cheap, infinite blobs. The canonical copy of every file. Not a database. Not searchable on its own. Not where humans author.
Catalog / metadata row (pointer + governance) One queryable row per blob: where it lives, what it grounds, sensitivity, retention, owner. Joins blobs to structured entities. Not the bytes. Don't stuff a 40KB markdown body into a VARIANT cell — that's what the store is for.
Retrieval index (embeddings + search) Makes the blob corpus machine-grounding-ready (semantic + keyword). Not the source of truth — it's derived, rebuildable from the store.

The load-bearing principle: the object store is the system-of-record; the database stores a pointer, not the payload; the index is derived and disposable. Putting blobs in a relational/VARIANT column kills you on cost, bloat, and migration; putting metadata in the object store kills you on queryability and governance; trusting the index as truth kills you when you need to re-embed. The pattern is to keep all three and let each do one job.

This is exactly the shape the CAF catalog already takes for structured data — typed spine + VARIANT payload + (planned) Cortex Search. We're extending the same discipline to unstructured blobs: the stage is to grounding assets what VARIANT is to the modal prose.


Honest evaluation of the four candidates

Judged against two requirements that genuinely pull apart: (a) human authoring/collaboration ergonomics and (b) machine grounding/retrieval at thousands-of-companies scale. No single candidate wins both — which is why the recommendation combines two of them by role.

Candidate (a) Human authoring/collab (b) Machine grounding at scale Verdict
Google Drive (locally-mounted + sync) Strong. Real-time co-edit, comments, versioning, zero training, already the team's habit. The locally-mounted trick is a brittle single-user hack, but Drive-the-service is excellent for authoring. Weak as the machine plane. Agents reaching Drive directly = OAuth scope sprawl, rate limits, no in-perimeter embeddings, and retrieval that lives outside Snowflake's governance. Mounting doesn't scale to harnesses/CI. Keep as the authoring front door, not the system-of-record. Sync INTO the stage.
Snowflake stage Weak for humans authoring directly (nobody writes meeting notes by PUT-ing to a stage). Strong. Object-store semantics in-perimeter; same RBAC + MCP plane as the catalog; Cortex Search reads it natively; one cloud to manage; flat namespace fits the tenancy model. The system-of-record for bytes + the retrieval substrate. This is the spine.
AWS S3 Same weak authoring story as the stage, plus a second cloud, second IAM model, second audit boundary. Strong and battle-tested at scale — but it's redundant with the Snowflake stage and adds cross-cloud egress + a separate governance surface for no gain, since Snowflake already gives you object storage. Skip for internal grounding assets. (S3/CloudFront stays in scope only for the external demo host per Decision D — different problem.) Reach for S3 only if blobs must live outside Snowflake's RBAC.
Bitbucket version control Good for engineers, hostile to the 60 salespeople; PRs are wrong for living meeting notes; git is for code + skills, not thousands of companies' intel blobs. Wrong tool. Git chokes on large binaries (pdf/docx), thousands of dirs, and frequent non-code writes; no retrieval; no row-level governance. Skip for grounding assets. Bitbucket stays for the CAF code + skills, not the data plane.

The clean read: Drive and the stage are the two keepers, and they pair as front door (Drive) → system-of-record (stage). S3 and Bitbucket are each right for a different CAF problem (external host; code), wrong for this one.


How it lands on CAF's locked architecture

Nothing here contradicts a locked decision; it slots into the seams already drawn.


Tenancy boundary applied to assets

Apply "open internal, hard-walled external" ([[2026-06-15-caf-architecture-decisions-and-meta-council]]) verbatim — do not invent per-client isolation for grounding assets:


Migration note (forward design — flag the constraint)

This is a forward design, not a migration of a running system. The CAF repo is not even on this machine ([[2026-06-14-caf-restructure-organizing-brief]] standing blocker), and the system isn't live. So "migration" = the build sequence, not a cutover. Don't boil the ocean:

  1. Today / unblock authoring (zero new infra): keep engineers writing intel + notes in the existing flat Google Drive. It already works for humans and is the eventual front door — no wasted motion.
  2. When the catalog schema lands: add the grounding_asset entity (pointer + the three tagging columns) to the Snowflake DDL alongside the use_case spine. Create one internal stage. Add the three MCP asset tools.
  3. Wire the one-way Drive→stage sync: a small scheduled job (or MCP ingest tool) that lands new/changed Drive files into the stage and upserts pointer rows. This is the moment the system stops depending on any laptop.
  4. Add Cortex Search last: stand up the search service over the staged corpus once there's a meaningful asset volume to ground against. It's derived/rebuildable, so it can come online after the store + pointers exist.

Each step is independently useful and reversible; nothing requires the live app or the external-demo fork to be settled first.


Open questions for the founder

  1. Authoring UX: Drive-front-door + sync (recommended) vs author-direct-in-app later? The Drive sync is the lowest-friction unblock now. If the "live app" fork ([[2026-06-15-caf-architecture-decisions-and-meta-council]] Decision D) gives reps an in-UI editor, some authoring may move there over time. Confirm Drive-as-front-door is the v1 authoring surface, or do you want to wait for an in-app editor?
  2. Are meeting notes / write-ups first-class catalog citations, or loose attachments? Two shapes: (a) a grounding asset is just an attachment retrievable by the agent, with citations staying free-text in the use_case VARIANT; or (b) a citation can reference a grounding_asset_id, making the supporting doc a first-class, dedup-able, linkable provenance object. (b) is more powerful for provenance but adds a junction; (a) is leaner. Which level of citation rigor do you want?
  3. Sync trigger + cadence: scheduled poll of Drive, or event-driven (Drive change notifications / a "publish to catalog" action the author takes)? Affects freshness vs simplicity.
  4. Does any grounding asset ever need to leave the internal plane (e.g., a client wants their own intel write-up in a take-home)? Current design says no — raw assets never cross the external wall. Confirm that holds, since it's what keeps the tenancy model simple.
  5. Stage vs S3 — is there a phData reason to prefer S3 (existing data-lake conventions, a partner-stack mandate) over a Snowflake internal stage? Default recommendation is the stage (one cloud, in-perimeter, MCP-reachable); flag if house convention pushes to S3.

Cross-references