# How CareerOps Handles Derived/Accumulated Sources and Quantified Claims

> Discover how CareerOps manages derived/accumulated sources and quantified claims with a two-tier trust model and four-bucket classification to prevent unverified data propagation. Learn more about santifer/career-ops.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: how-to-guide
- Published: 2026-08-22

---

**CareerOps enforces a two-tier trust model that isolates primary user-authored content from accumulated narrative sources, using a four-bucket classification system in `story-provenance-check.mjs` to ensure unverified quantified claims never propagate as factual data.**

CareerOps (santifer/career-ops) implements a rigorous data governance framework to manage quantified claims originating from derived or accumulated sources. The system distinguishes between authoritative user-authored documents and narrative story banks, ensuring that only verified numeric statements with explicit provenance reach downstream generators like CV renderers and cover letter builders.

## Source-of-Truth Architecture

CareerOps maintains strict **source-of-truth boundaries** defined in `[AGENTS.md]`, segregating content into two distinct trust tiers.

### Primary Tier: Full-Trust Ground Truth

Files in the primary tier are treated as authoritative for all factual content:

- [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) – The canonical curriculum vitae containing verified employment metrics
- [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) – Structured configuration data
- [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) – Profile metadata and constraints

These files represent **user-authored ground truth** where numeric statements carry implicit verification.

### Derived Tier: Accumulated Narratives

The [`interview-prep/story-bank.md`](https://github.com/santifer/career-ops/blob/main/interview-prep/story-bank.md) file operates as an *accumulated* source. It captures STAR-format (Situation, Task, Action, Result) interview stories that frequently contain quantitative claims (percentages, team sizes, performance metrics) but are **not considered authoritative** without additional provenance markers. This separation prevents narrative embellishment from contaminating factual records.

## Four-Bucket Classification System

The `[story-provenance-check.mjs]` script implements a classifier that scans [`story-bank.md`](https://github.com/santifer/career-ops/blob/main/story-bank.md) for numeric patterns—including percentages, "+ noun" constructs, hour ranges, hyphen scales, and noun scales—and assigns each claim to one of four buckets:

**existing** – The exact number or range appears verbatim in [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), *or* the story entry carries a `**Provenance:** user‑stated YYYY‑MM‑DD` marker confirming user verification.

**supportedByResume** – The number does not appear verbatim in [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), but the CV text describes the same fact with sufficient word overlap to deem it plausibly true based on heuristic matching.

**derived‑unverified** – The number appears only in the story-bank entry, lacks traceable CV support, and contains no provenance marker. This is the default safe state for unverified accumulated claims.

**user‑cannot‑confirm** – The story entry’s provenance is explicitly set to `user‑cannot‑confirm`, a durable override that prevents re-classification and marks the claim as unknowable.

## The Provenance Field Convention

Each story block may include a dedicated `**Provenance:**` label distinct from the standard `Source` label. The field accepts one of four values:

- `source: cv.md` – Creates a hard link back to the canonical CV file
- `user‑stated YYYY‑MM‑DD` – Records manual confirmation with an ISO datestamp
- `derived‑unverified` – Explicitly marks the claim as unverified (redundant with absence, but explicit)
- `user‑cannot‑confirm` – Permanently excludes the claim from verification workflows

The absence of any provenance field is interpreted as `derived‑unverified` by default. This convention is implemented in the parsing logic of `[story-provenance-check.mjs]`.

## UX Invariant for Confirmation

When a `derived‑unverified` finding surfaces in the UI, CareerOps enforces a strict **confirmation UX invariant** that presents four unbiased options to prevent accidental verification:

1. Confirm the claim as stated (writes `user‑stated` date)
2. Provide the correct figure (updates value and provenance)
3. Mark the claim as narrative‑only (removes quantified status)
4. Choose "I don’t know" (writes `user‑cannot‑confirm`)

This invariant ensures that user guesses never become implicit verified facts. The requirement is documented in the "Confirmation UX invariant" section of `[AGENTS.md]` and enforced as read-only logic in `[story-provenance-check.mjs]`.

## Pipeline Enforcement and Downstream Usage

Downstream generators—including CV renderers, cover letter builders, and interview prep modules—consult the provenance classification before including quantified data:

- **Allowed for factual rendering**: Claims classified as `existing` or `supportedByResume` may appear in factual tables, negotiation talking points, and quantitative achievement lists.
- **Narrative texture only**: Claims marked `derived‑unverified` or `user‑cannot‑confirm` are treated as qualitative narrative texture and are explicitly omitted from any factual tables, metric summaries, or compensation negotiation data.

This enforcement ensures that only [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md)-verifiable or user-confirmed numbers appear in professional documents generated by the system.

## Running the Provenance Checker

Execute the provenance validation pipeline using Node.js:

```bash

# Default usage – scans the default story-bank and CV

node story-provenance-check.mjs

# Summarize results for CI integration

node story-provenance-check.mjs --summary

# Analyze custom file paths

node story-provenance-check.mjs \
  --story-bank interview-prep/my-company-role.md \
  --cv cv.md

```

### Adding Provenance Markers Manually

Edit [`interview-prep/story-bank.md`](https://github.com/santifer/career-ops/blob/main/interview-prep/story-bank.md) to include a provenance label:

```markdown

### Leadership

**Situation:** Led a team of 8 engineers.  
**Task:** Deliver a new microservice.  
**Action:** Designed the architecture.  
**Result:** Deployed in 2 weeks, **30%** faster than previous releases.  
**Provenance:** user-stated 2026-08-10   <!-- confirms the 30% figure -->

```

### Programmatic Classification Logic

The core classification heuristic from `[story-provenance-check.mjs]` operates as follows:

```javascript
function classifyStoryBank(storyText, cvText) {
  const claims = extractClaims(storyText); // uses CLAIM_PATTERNS
  return claims.map(claim => {
    if (cvText.includes(claim.text)) return 'existing';
    if (hasProvenance(claim, 'user-cannot-confirm')) return 'user-cannot-confirm';
    if (hasProvenance(claim, 'derived-unverified')) return 'derived-unverified';
    return 'supportedByResume';
  });
}

```

## Summary

- CareerOps separates data into **primary** ([`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml)) and **derived** ([`interview-prep/story-bank.md`](https://github.com/santifer/career-ops/blob/main/interview-prep/story-bank.md)) trust tiers to prevent narrative drift.
- The `[story-provenance-check.mjs]` script classifies quantified claims into four buckets: `existing`, `supportedByResume`, `derived‑unverified`, and `user‑cannot‑confirm`.
- The `**Provenance:**` field convention links claims to [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) sources, user confirmation dates, or explicit unknowable states.
- Downstream generators only render claims marked `existing` or `supportedByResume` as factual data; `derived‑unverified` claims remain narrative-only.
- The **confirmation UX invariant** requires explicit user action to upgrade any `derived‑unverified` claim, preventing accidental data pollution.

## Frequently Asked Questions

### How does CareerOps distinguish between primary and derived sources?

Primary sources include [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml), and [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md), which serve as the authoritative ground truth for all factual content. Derived sources like [`interview-prep/story-bank.md`](https://github.com/santifer/career-ops/blob/main/interview-prep/story-bank.md) are accumulated narrative documents that may contain quantified claims but require verification against primary sources or explicit provenance markers before being treated as factual.

### What happens to quantified claims that cannot be verified?

Claims classified as `derived‑unverified` or `user‑cannot‑confirm` are restricted to narrative usage only. Downstream generators will omit these numbers from factual tables, metric summaries, and negotiation talking points, ensuring that unsubstantiated figures never appear in professional documents exported from the system.

### How do I manually confirm a quantified claim in story-bank.md?

Add a `**Provenance:**` line to the story entry with the value `user‑stated YYYY‑MM‑DD` using an ISO date format. Alternatively, ensure the exact number appears in [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), which the `[story-provenance-check.mjs]` script will detect and classify as `existing` automatically during the next validation run.

### Can derived-unverified claims ever appear in exported CVs?

No. The pipeline enforcement rules explicitly prohibit `derived‑unverified` and `user‑cannot‑confirm` claims from appearing in any generated CV, cover letter, or factual summary. Only claims reaching `existing` or `supportedByResume` status through CV-verification or manual confirmation propagate to exported documents.