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:
- Passes FIXED nodes through untouched. They are serialized exactly as they appear in the quarry.
- Calls the HYBRID selector to choose
selection.active[]from each HYBRID-tier pool node, given the job context. - Calls the OPEN writer to generate new text for OPEN-tier nodes, given the job context and the surrounding quarry as evidence.
- Snapshots the resulting tree into
jobs.<jobId>.tailored_cvortailored_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
(resolveChain → callWithChain). 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.