Quarry Pattern — content pool, three mutability tiers, deterministic identity

The quarry pattern is CareerVector's core document generation idea. The user maintains a single content pool (the "quarry") containing every CV or cover letter fragment they might ever want to show. The LLM picks and adapts fragments from that pool for a specific job. The rendered document is always a subset of the quarry, never an extension of it.

This shape is the reason cv_profile.<lang>.tree and cl_profile.<lang>.tree are deliberately larger than any single rendered document.

Three mutability tiers

Every node in the tree carries a tier that controls what the LLM is allowed to do with its content:

Tier What the LLM must do Sent to the LLM at all?
FIXED Copy the content verbatim. No rephrasing. No — passed through.
HYBRID Select the most relevant entries from the pool. May rephrase Yes — pool only, no other facts.
lightly. Must not invent.
OPEN Rewrite for the specific job, staying factually accurate. Yes — with job context.

The tier of each section is design, not LLM judgement. Identity, education, employer dates, and salutation formalities are FIXED. Free prose, summaries, and intros are OPEN. Bullet pools and skill lists are HYBRID.

Why tiers matter

FIXED is a safety-critical contract. The tailoring pipeline in lib/domain/src/tailor/ walks the canonical Node tree and never sends FIXED nodes to the LLM. Identity fields are not at risk of hallucination, regardless of what model is chosen, because the model never sees a prompt that could write them.

HYBRID gives the LLM enough rope to choose between candidate bullets without giving it room to make claims that aren't in the user's quarry. The pool is the universe of allowable claims for that section.

OPEN gives the LLM rewriting power for prose that genuinely needs to adapt to the job — summary, cover letter intro and close — but the model still cannot add a degree, a certification, or a job that does not exist in the quarry.

Section tier mapping (CV)

Section Tier
Identity / personal info nodes FIXED
Education FIXED
Experience headers (company, dates) FIXED
Experience bullets pool HYBRID
Skills lists HYBRID
Projects, narrative blocks HYBRID or OPEN
Summary OPEN

Section tier mapping (CL)

Section Tier
Recipient block FIXED
Greeting (locale-driven) FIXED
Sign-off (locale-driven) FIXED
Subject line FIXED (locale-driven) or OPEN
Body hero / key argument HYBRID
Intro and closing prose OPEN
Format and style notes (guidance only)

Tailor pipeline

lib/domain/src/tailor/ is the Node-direct tailor pipeline. It walks the canonical tree once per render target (CV or CL), partitions nodes by tier, and:

  1. Passes FIXED nodes through untouched. They are serialized exactly as they appear in the quarry.
  2. Calls the HYBRID selector to choose selection.active[] from each HYBRID-tier pool node, given the job context.
  3. Calls the OPEN writer to generate new text for OPEN-tier nodes, given the job context and the surrounding quarry as evidence.
  4. Snapshots the resulting tree into jobs.<jobId>.tailored_cv or tailored_cl. The original quarry tree is never mutated by tailoring; accepted edits get promoted back as new variant candidates so history survives.

All LLM calls inside the pipeline route through the cascade (resolveChaincallWithChain). No tailor stage imports a provider SDK directly. See LLM Cascade.

Why this beats "just have the LLM write it"

  • Quality: a curated pool is consistently stronger than freshly generated prose, because the user has already approved the wording.
  • Safety: FIXED guarantees identity fields cannot drift.
  • Auditability: every rendered fragment links back to a node in the quarry, which lets reviewers verify the document is grounded in real facts.
  • Iteration: the user improves the quarry once and benefits across every future job application.

Anti-patterns

  • Sending a FIXED node to the LLM "for consistency" — defeats the safety contract.
  • Treating HYBRID nodes as OPEN — the LLM will hallucinate facts not in the quarry.
  • Storing tailored output back into the quarry tree without going through the promote-as-variant flow — destroys history and conflates "what I keep" with "what I shipped to job X."

The quarry pattern is the reason the document tree is intentionally not normalised into relational rows: the document is read whole, tailored whole, and rendered whole.

Source: wiki/content/canon/quarry-pattern.md