# Source-of-Truth Boundary for User-Facing Content in Career-Ops: The Complete Guide

> Understand the source-of-truth boundary for Career-Ops user-facing content. Learn which six exclusive files govern content generation in this comprehensive guide.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: architecture
- Published: 2026-07-03

---

**The source-of-truth boundary in Career-Ops restricts user-facing content generation to six exclusive files—[`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml), [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md), [`voice-dna.md`](https://github.com/santifer/career-ops/blob/main/voice-dna.md), and select interview-prep files—enforcing a strict separation between immutable user data and auto-updatable system logic.**

The `santifer/career-ops` repository implements a deterministic content generation framework where every candidate-facing artifact is derived from a fixed, auditable set of documents. This architectural principle prevents fabrication by explicitly prohibiting the system from consulting auto-memory, parent directories, or any out-of-scope data when generating CVs, cover letters, or recruiter outreach.

## What Is the Source-of-Truth Boundary?

The **source-of-truth boundary** is a contractual rule set that defines which files may be consulted when producing any candidate-facing output. According to [`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md), this boundary splits the repository into two distinct layers:

- **User Layer**: Files that constitute the exclusive source of truth and are **never** auto-updated
- **System Layer**: All other repository files, including scoring logic and templates, which may be auto-updated

This separation ensures that generated content remains reproducible and factually grounded. The authoritative list of permissible files lives in the **"Sources of Truth (EXCLUSIVE)"** table within [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) (lines 13–24), which explicitly forbids the use of any unlisted files for fabricating claims.

## The Exclusive Source-of-Truth Files

When generating user-facing content, the system may only access the following six file categories:

### 1. [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) (Canonical CV)

Located at the project root, [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) serves as the primary biographical document. It is consulted **always** and is considered mandatory for most generation tasks. If this file is absent, the system must abort or prompt the user for clarification.

### 2. [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md) (Proof Points)

This file contains detailed metrics and achievements. It takes **precedence** over [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) for specific data points, allowing the system to override CV metrics with more detailed evidence from articles or project deep-dives.

### 3. [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) (Identity Configuration)

Stores candidate identity, target roles, compensation ranges, and other personal settings. This YAML file is read **always** and provides the structural parameters for role-specific generation.

### 4. [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) (User Customizations)

Contains user-specific archetypes, narrative voice, negotiation scripts, and optional writing-style caches. This file overrides any default wording in the system layer, ensuring the output matches the user's personal brand.

### 5. [`voice-dna.md`](https://github.com/santifer/career-ops/blob/main/voice-dna.md) (Anti-Slop Guardrails)

An optional file that enforces anti-AI-slop language rules. When present, it is consulted **only** when generating candidate-facing prose to prevent generic, templated language. It may be overridden by styles defined in [`_profile.md`](https://github.com/santifer/career-ops/blob/main/_profile.md).

### 6. `interview-prep/` (Situational Context)

Files in [`interview-prep/story-bank.md`](https://github.com/santifer/career-ops/blob/main/interview-prep/story-bank.md) and `interview-prep/{company}-{role}.md` are consumed when producing ATS form answers or interview preparation materials. These provide company-specific context and behavioral story banks.

### 7. `writing-samples/` (Style Calibration Only)

Consulted **only** during style calibration and only after checking [`_profile.md`](https://github.com/santifer/career-ops/blob/main/_profile.md) for a cached style block. These samples are never used for factual claims.

## Precedence Rules and Guardrails

The boundary enforces strict precedence to resolve conflicts between sources:

1. **[`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md) overrides [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md)** for metric details and proof points
2. **[`_profile.md`](https://github.com/santifer/career-ops/blob/main/_profile.md) overrides system defaults** for wording and narrative structure
3. **[`voice-dna.md`](https://github.com/santifer/career-ops/blob/main/voice-dna.md) provides guardrails** unless superseded by user-defined styles in [`_profile.md`](https://github.com/santifer/career-ops/blob/main/_profile.md)

The system implements defensive checks: if a required claim cannot be backed by any source-of-truth file, the generation must result in silent omission or a user prompt for clarification. This rule is codified in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) and prevents the LLM from hallucinating experience or skills.

## Implementing the Boundary in Code

The following Node.js implementation demonstrates how modes safely collect source-of-truth data before generating content. This pattern enforces **explicit read-only access** and validates mandatory files before LLM invocation.

```javascript
// utils/getUserData.mjs
import { readFile } from 'fs/promises';
import path from 'path';

// Helper to read a file if it exists; otherwise return an empty string
async function maybeRead(relPath) {
  try {
    const abs = path.resolve(process.cwd(), relPath);
    return await readFile(abs, 'utf8');
  } catch {
    return '';
  }
}

// Gather the source-of-truth artefacts
export async function collectUserData() {
  const cv            = await maybeRead('cv.md');
  const articleDigest = await maybeRead('article-digest.md');
  const profileYml    = await maybeRead('config/profile.yml');
  const profileMd     = await maybeRead('modes/_profile.md');
  const voiceDna      = await maybeRead('voice-dna.md'); // optional

  return { cv, articleDigest, profileYml, profileMd, voiceDna };
}

```

The following example shows how a cover letter generator uses this utility to enforce the boundary at runtime:

```javascript
// example/generateCoverLetter.mjs
import { collectUserData } from '../utils/getUserData.mjs';

async function buildCoverLetter(jdText) {
  const { cv, articleDigest, profileYml, profileMd, voiceDna } = await collectUserData();

  // Simple guard: abort if the mandatory CV is missing
  if (!cv.trim()) throw new Error('cv.md is required to generate a cover letter');

  // Construct prompt that instructs the LLM to only cite facts from inputs
  const prompt = `
    Use the following CV, article digest and profile to write a concise (≤300-word) cover letter that:
    • mirrors the style defined in ${profileMd ? 'modes/_profile.md' : 'the default style'}
    • incorporates any metrics found in article-digest.md (overriding cv.md where they differ)
    • respects anti-AI-slop rules from ${voiceDna ? 'voice-dna.md' : 'none'}
    • directly addresses the job description:\n\n${jdText}
  `;

  // Send `prompt` to the LLM (e.g., via OpenAI or Claude) – omitted for brevity
}

```

These snippets mirror the architectural constraints defined in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md), ensuring that no generation occurs without verified source material.

## Summary

- **The source-of-truth boundary** in Career-Ops restricts user-facing generation to six exclusive files: [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml), [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md), [`voice-dna.md`](https://github.com/santifer/career-ops/blob/main/voice-dna.md), and `interview-prep/` files.
- **User Layer isolation** prevents auto-updates from modifying personal data, while the **System Layer** handles templates and logic.
- **Precedence rules** ensure [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md) overrides [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) for metrics, and [`_profile.md`](https://github.com/santifer/career-ops/blob/main/_profile.md) overrides system defaults.
- **Defensive coding patterns** require mandatory file checks before LLM invocation, preventing fabrication when data is missing.
- All constraints are codified in [`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md) and enforced by the **"Sources of Truth (EXCLUSIVE)"** table in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md).

## Frequently Asked Questions

### What happens if a source-of-truth file is missing?

If a mandatory file like [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) is absent, the system must abort generation and throw an error or prompt the user for clarification. For optional files like [`voice-dna.md`](https://github.com/santifer/career-ops/blob/main/voice-dna.md), the system proceeds with default behavior. This defensive rule prevents the LLM from hallucinating content to fill gaps.

### Can I add custom files to the source-of-truth boundary?

No. The **exclusive** list in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) is fixed to prevent scope creep and maintain auditability. If you need to introduce new data sources, you must either append content to existing approved files (like [`article-digest.md`](https://github.com/santifer/career-ops/blob/main/article-digest.md)) or petition to update the [`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md) and [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) definitions in the repository.

### How does the system prevent AI hallucination or fabrication?

The boundary enforces three guardrails: (1) **File existence checks** validate that claims can be backed by the six source files before generation; (2) **Precedence rules** eliminate ambiguity by defining which file wins in conflicts; (3) **Explicit prohibitions** in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) (lines 13–24) forbid consulting auto-memory, parent directories, or external data. If a claim lacks a citation in the source-of-truth files, it is omitted.

### What is the difference between the User Layer and System Layer?

The **User Layer** contains your immutable personal data—CVs, profiles, and writing samples—that the system treats as read-only and never auto-updates. The **System Layer** includes template logic, scoring algorithms, and shared mode definitions that may be automatically updated by maintenance scripts. This separation ensures that automated improvements to the framework never overwrite your personal career data.