Readiness Methodology

CMMC Readiness, End to End

How a CMMC 2.0 / NIST SP 800-171 readiness engagement runs. The question isn't just where are my gaps — it's am I ready to self-attest in SPRS, or to pass a C3PAO assessment? Finding gaps is one step toward that answer, not the whole of it.

The arc ScaffoldInterviewScope ProveScoreRecommendDeliver
The stack — portable containers on a dedicated host
Dedicated VPS host · Docker
NocoDB n8n runner · runner-ai
Claude API external service

Every piece — the database (NocoDB), the orchestrator (n8n), the script runners — is a Docker container on a dedicated VPS, never a local computer. An action or upload in NocoDB fires a webhook to n8n, which runs a Python script on the host: runner for data work, runner-ai (the one container holding the AI key and internet access) for anything that calls Claude. Because it's all containers, the whole stack is portable — it can be picked up and rehosted elsewhere without re-architecting. The chips under each phase below show that phase's actual path.

The flow

The same process as a decision flow — where a control forks toward evidence or toward remediation, and the loop that turns a gap into coverage. Node colors match the legend below.

no

yes

No or N/A

Yes or Partial

Define

Perform

no

yes

Documentation

Implementation

new evidence

0 Onboard: clone the per-client base, seed it, enter CAGE

1 Scaffold: create assessment, populate controls

2 Interviews: people, tech, data flows

Scope settled? Needs Review = 0

2e Directional triage: claim each control

Claimed status?

Gap: route to remediation, no evidence requested

Open evidence request

Objective type?

3 Document review: AI proposes evidence

Perform evidence: request plus vision auto-check

4 Review queue: verify, judge sufficiency

Verified AND satisfies?

Re-request (still a gap)

5 Mark and recompute: SPRS, POA&M

6 Recommend a fix

Gap kind?

Documentation gap: propose language from the library

Implementation gap: POA&M raised, propose a remediation

Client adopts, produces new evidence

7 Generate the SSP from the assessment

7 Export the package: SSP, POA&M, evidence, SPRS

Ready: self-attest, or hand to a C3PAO

0
Onboarding minutes — mostly the clone job Consultant

Stand up the client's own isolated workspace before any data is entered.

  • Clone the shared reference base into a new per-client base inside the self-hosted NocoDB (on the VPS) — a faithful copy of all the crosswalk reference data (frameworks, controls, standards library) and every view, with the client tables empty. Nothing of one client's data ever touches another's.
  • Fill the engagement record and the client's CAGE codes (plus the parent org's HLO CAGE) in that base.
  • From here every automated step targets this base: the scripts, the runner, and the NocoDB action buttons are all base-aware, so a button in a client base runs the job against that base, with writes isolated to it.
How it works

Onboarding clones the template base (NocoDB's Duplicate Base) into a per-client base — reference data, views, and the empty Client_Profile / CAGE_Codes tables all come along. Every engagement script resolves its tables by title within whichever base it's told to target (NOCODB_BASE_ID), so the same scripts, runner, and n8n buttons drive any client base with no per-client code. When a reference correction lands (a NIST fix, a reworded control), push_reference_data.py propagates it out to every client base — matching rows by business key, dry-run first, and skipping-and-flagging any base that's drifted rather than overwriting it.

RunsNocoDBn8nrunner · VPSclone · base-aware · push
1
Scaffold the assessment minutes Consultant

Declare the scope up front — everything downstream keys off it.

  • Create the assessment, link the applicable framework(s).
  • Run Populate objectives → the full control checklist appears in seconds.
  • Do this first. It reads like an assessment step, but it's really the scope declaration Phase 3 is blocked on.
How it works

populate_gap_assessment_objectives.py reads the linked framework(s) and creates a row for every assessment objective (Gap_Assessment_Objectives) and every control (Gap_Assessment_Requirements). It's idempotent — linking another framework later only adds what's missing, so re-running is always safe.

RunsNocoDBn8nrunner · VPS
2
Interviews the bulk of the human effort ConsultantClient

One long conversation, recorded in five passes — each feeds the next.

  • 2a · People & roles — capture real people, then map the client's own job titles to the standard role taxonomy.
  • 2b · Technology inventory — one row per tool the client runs; capture the scoping inputs in the same conversation.
  • 2c · Data flows — walk each flow forward, then backward (backups & logging are what quietly drag systems into scope).
  • 2d · Compute the scope — sweep the inventory, then work Needs Review down to zero. This is where the boundary is drawn.
  • 2e · Control-directional triage — walk each control and record a Claimed Status: do you actually do this?
Decision · the prune
claimed No / N/A

It's a gap already found. Route to remediation — never request evidence for it.

claimed Yes / Partial

This is what you'll prove. Open an evidence request for it downstream.

Claimed ≠ assessed. A claim is pre-proof; MET / NOT MET is the post-proof finding — separate fields. And a scope-reducing call (CRMA, Out-of-Scope) stays provisional until its control is proven in Phase 5.

How it works — the two computed passes

2d · Scoping engine. recompute_scoping_categories.py sweeps the whole inventory and assigns each asset a category per 32 CFR 170.19 — CUI Asset · Security Protection · CRMA · Specialized · Out-of-Scope · Needs Review. It's fail-closed: an asset with a missing input can never compute to Out-of-Scope — it lands in Needs Review with a Rationale naming the gap. Scope-reducing calls (CRMA, Out-of-Scope) stay provisional until their control is proven MET in Phase 5.

2e · Triage. A plain-language Triage_Questions bank drives the "do you do this?" pass. The claim is pre-seeded from the tool stack (infer_claims_from_stack.py) and any SSP (mine_ssp.py), then check_claim_discrepancies.py flags the tell: claimed done, but you run none of the tools this control needs. Every claim carries a provenance rank — Client-confirmed > Interview > SSP > Tech-stack inferred.

RunsNocoDBn8nrunner · VPSscoping · claim inference
3
Documents in ClientAutomation

Client hands over policies; the machine reads them.

  • Upload each document → text is auto-extracted (spot-check it — no OCR for scanned files).
  • Queue it → AI proposes Evidence as verbatim quotes with a sufficiency judgment, marked AI-proposed.
Split · by objective type
Define objectives

Satisfied by documents → the automated review above proposes candidates.

Perform objectives

Need a screenshot or config export → personalized evidence request → vision auto-check → reconcile.

How it works

Upload fires a webhook → ingest_client_documents.py extracts the text (pdfplumber / python-docx; no OCR, so scanned PDFs come back empty — spot-check). Flip to Queued and review_document.py batches the in-scope Define objectives by control family, asks Claude for verbatim quotes plus a Sufficiency judgment, then mechanically verifies every quote against the source (check_quote_fidelity.py) — a quote not found word-for-word is discarded — and writes Evidence as AI-proposed. The same pass also harvests reusable values from the document (the client's name and the like), so later drafts read with their real details instead of placeholders.

RunsNocoDBn8nrunner-ai · VPSClaude API
4
Work the evidence queue the judgment work — deliberately not automated Consultant

Two independent calls on every candidate artifact — worked from a “Review — start here” console and purpose-built action views that surface only the rows and fields each decision needs, with an action-first Suggested action cue on every row saying what to do next.

  • Verification Status — have I actually looked at this?
  • Sufficiency — does it satisfy the objective, or just point at where the answer lives?
Coverage gate
Human-verifiedANDSatisfies objective → counts as coverage.
anything less→ not coverage. An AI-proposed or "pointer only" quote is a lead, not proof.
How it works
  1. Receive. Client artifacts (screenshots, config exports) arrive as Evidence linked to the personalized Evidence_Request generated back in 2e — generate_evidence_requests.py had resolved {{technology}} to the client's actual tool and led each ask with the plain-language Assessor Intent.
  2. Vision sanity check. check_evidence_vision.py sends each artifact to Claude vision and grades it against the request's What It Must Show — three checks:
    right kind of artifact?named elements present?stale vs. the freshness window?
    It returns a verdict — Likely match · Partial · Likely mismatch — plus notes. Advisory only: it proposes, never decides.
  3. Human gate. You make two independent calls: Verification (have I looked?) and Sufficiency (does it satisfy the objective, or just point at where the answer lives?). Coverage needs both.
  4. Reconcile — auto-fires the moment you set a decision. Setting Accept / Reject on the request triggers reconcile_evidence.py (webhook → n8n → runner, no button to hunt for): it propagates the decision onto the evidence, rolls the request status up, sends rejected or empty ones back to re-request with your Reviewer Feedback attached for the client to fix, and reports which Perform objectives are now ready to mark MET.
RunsNocoDBrunner-ai · VPSClaude APIvision auto-check
5
Mark objectives & recompute ConsultantAutomation

Record the findings; the scoring rolls itself up.

  • Mark each objective MET / NOT MET — and write down why it failed.
  • Recompute fires automatically: one confirmed NOT MET fails the whole requirement; it computes the real DoD SPRS score (points only for what's proven) and opens a POA&M for each new gap — never touching your existing remediation notes.
How it works

Marking an objective fires recompute_gap_assessment.py automatically (webhook → n8n → runner). It rolls objectives up to requirements — one confirmed NOT MET fails the requirement, even with others unassessed — computes the actual DoD SP 800-171 SPRS score — 110 minus the weight of every requirement not proven MET (not-yet-assessed controls count against it, so it's the defensible floor; N/A is deducted only for genuine incapability, never mere absence) — and writes it, with a full audit basis, onto the assessment and into the SSP. It also auto-creates a POA&M for each newly-failing requirement, linked to the exact objectives that caused it, and never overwrites an existing POA&M, so your remediation notes survive every re-run.

RunsNocoDBn8nrunner · VPSrecompute · SPRS · POA&M
6
Recommend, then close the loop ConsultantClient

Turn each gap into a specific, adoptable fix — and every gap is one of two kinds.

  • Documentation gap (a policy or procedure that isn't written) → draft a Documentation Recommendation: proposed language, placement, based on the standard library.
  • Implementation gap (a control not actually in place — setting not applied, technology not owned, coverage short) → a POA&M is recorded automatically, and a proposed remediation is drafted for it.
  • Client adopts the fix → that produces real Evidence, linked back and marked Implemented.
How each side is proposed

Documentation side. The draft is pulled from the standard libraryPPS_Statements, one atomic policy / procedure / standard statement per assessment objective. Pick the statement that satisfies the objective and propose where it goes. The language reads with the client's real values, not placeholders: {{company_name}} and the like resolve automatically, from values mined out of the client's own documents (and flagged for a human to confirm). Based On links the draft back to its source statement, so every recommendation is traceable to library language rather than free-written, and proposed text is never counted as coverage.

Implementation side. When a technical control isn't in place, the recompute opens a POA&M automatically, and a proposer drafts its fix from the data already linked to the failing requirement — target state from Evidence_Requirements, the satisfying tech class from Requirement_Technology_Map, what the client already owns from Client_Technologies, the required value from ODP Valuestyped as: apply a setting to a tool you own · acquire & implement one you don't · extend coverage. Both sides are one click on the assessment (Propose remediations / Propose documentation); the drafts land in a review queue, always advisory, never marking anything satisfied on their own.

7
Package & deliver ConsultantAutomation

Assemble the artifact that demonstrates readiness.

  • Author the SSP — build the System Security Plan from the structured assessment: a per-objective implementation statement (seeded from the standard library with the client's real values), plus the client's real technologies and roles. Each statement is Confirmed as it's finalized; until all are, the document stays a marked DRAFT.
  • Export the assessment package — bundle the SSP, the POA&M, the collected Evidence artifacts, and the SPRS score into one deliverable to self-attest with, or hand a C3PAO.
  • Freeze the final version — a finalized SSP is archived immutably, so next year's diff shows exactly how the readiness posture changed.
How it works

SSP — a first-class implementation-statement layer. Nothing is written from scratch. For every objective, how the control is satisfied is authored as its own implementation statement — seeded from the standard library (PPS_Statements) with the client's real values substituted in, and tied to the governing document and the implementing technology. Each statement carries a Draft → Confirmed status, and that Confirmed lock is the gate: the document renders as a DRAFT (“N of M statements confirmed”) until every assessable objective is Confirmed, then it becomes the Final SSP. It stays fail-closed throughout — unassessed objectives, a MET without evidence, or unsettled scope each hold it in DRAFT — so an incomplete assessment can never be mistaken for a finished one. Exports to Word (.docx) from a one-click Run Action, leading with the real SPRS score and its audit basis.

Package. The client-facing SSP is lean and reads in delivery voice; the evidence and internal workpaper detail split into a companion Objective Evidence Package, with the POA&M as its own spreadsheet. One export bundles them with the SPRS score into a single traceable deliverable — to self-attest with, or hand a C3PAO.

Version control. A finalized SSP freezes into an immutable archive — the exact delivered document, a content hash, and a snapshot of scope, score, and frameworks, kept as a version. Re-freeze next year and the document-to-document diff is the posture-change record: what moved, what newly passed, what regressed.

RunsNocoDBrunner-ai · VPSClaude APIauthored SSP · package · version freeze

The loop. New evidence from an adopted recommendation flows back to Phase 4 (re-verify) and Phase 5 (re-score). An unimplemented recommendation stays visibly distinct from a satisfied one — so proposed language can never be mistaken for coverage.

The outcome

A defensible readiness posture, packaged — a generated SSP, a scored SPRS self-assessment, a POA&M for every remaining gap, and verified evidence behind every MET. Enough to self-attest with confidence, or to hand a C3PAO on day one of a certification assessment.

Who does it

Consultant — you
Client
Automation — scripts & AI

Finding states

Provisional — a call not yet proven
MET — proven & sufficient
NOT MET / gap — routes to a POA&M

Read it as

A control's journey: claimed → proven → scored → remediated.
The prune (2e) is what keeps the evidence hunt small.

CMMC 2.0 / NIST SP 800-171 readiness methodology · portable Docker containers on a dedicated VPS · Last updated 2026-08-11 11:13 EDT — Phase 7 matured: the SSP control body is now a first-class implementation-statement layer (Draft→Confirmed gating a DRAFT vs Final document), the client SSP splits into a lean deliverable + Objective Evidence Package + POA&M spreadsheet, and finalized SSPs freeze into an immutable version archive whose year-over-year diff is the posture-change record.