Data & Analytics|June 8, 2026|13 min read

OASIS+ Self-Scoring Optimization: Data Architecture for 42-Credit Qualification

OASIS+ applicants can lose points to preventable data errors. Here's how to architect your project database, automate scoring, and build audit-ready evidence across the 13 domains.

Projectory team

Picture a mid-size services firm that self-scores its OASIS+ Management and Advisory domain submission comfortably above the threshold, then learns during evaluation that two of its projects do not count the way it assumed: one falls below the domain's minimum average annual value once the value is annualized correctly, and another was claimed for a scope the documentation does not show. That scenario is illustrative, but every piece of it comes from rules GSA publishes. The contractors who qualify cleanly aren't always the ones with the most impressive past performance. They're the ones who built their evidence architecture before they started scoring.

This article walks through the data infrastructure, scoring logic, and documentation strategy that separate first-attempt qualifications from expensive resubmissions.

Where the Credits Come From

OASIS+ qualification is scored against Attachment J.P-1, the OASIS+ Domain Qualifications Matrix and Scorecards, which defines Qualifying Projects, Federal Experience Projects, Systems, and Certifications, and GSA recommends a self-scoring exercise against it before you submit [1]. The qualifying threshold is 36 points for the Small Business and socioeconomic contracts and 42/45 points for the Unrestricted contracts [1]. GSA lists thirteen domains, from Management & Advisory and Technical & Engineering to Financial Services and Social Services [2].

The scorecard elements to plan around:

  • Qualifying Projects (QPs): an offeror may submit a maximum of five distinct QPs for each domain, and each must meet or exceed the minimum average annual value (AAV) for that domain in J.P-1 [1].
  • Federal Experience Projects (FEPs): prime federal awards that meet their own criteria [1].
  • Systems and Certifications: examples GSA lists include an adequate accounting system, approved purchasing system, EVMS, facility clearance, CMMI, and ISO certifications [1].
  • Past performance: a QP cannot have an associated record of negative past performance [1].

Read the actual credit values for your domain and pool in J.P-1. They differ by domain, so any internal model should load them from the scorecard rather than hard-coding a single table.

Scorecard ElementWhat It RewardsCommon Failure Reason
Qualifying ProjectsUp to five projects per domain that meet the domain's AAVAAV calculated the wrong way, relevance not documented
Federal Experience ProjectsPrime federal awardsSubcontracts submitted where a prime award is required
Systems/CertificationsApproved systems and current certificationsExpired certificate or system approval at submission
Past performanceQPs without negative past performanceA QP with a weak record that disqualifies it

The pattern is consistent: points are rarely lost because a firm lacks qualifying work. They are lost because the firm can't prove it the way the scorecard requires.

The Relevance and Value Traps

Three miscalculations deserve a schema-level defense.

First, misreading how task orders count. A QP can be a single contract, a single task order, or one "Collection of Task Orders," and offerors are limited to one Collection of Task Orders per domain submission [1]. For a collection, AAV is the combined obligated or estimated value of the task orders divided by the number of days from the start of the earliest order to the end of the last, multiplied by 366 [1]. Model each option before you decide how to present a group of orders.

Second, claiming partial scope as full credit. Relevant work does not need to be the primary purpose of a project, but the offeror must clearly demonstrate, for example through a distinct CLIN or section of the PWS, that the relevant portion meets the minimum QP criteria for the domain [1]. A contract where your firm provided cybersecurity monitoring doesn't show engineering scope just because the prime contract included engineering performed by another team member.

Third, conflating subcontract value with prime value. If you performed $2M of work as a subcontractor on a $15M prime contract, the work you can document is your $2M, not $15M.

Consider an illustrative scenario. A contractor self-scores using five task orders under the same base contract and counts each one as a separate QP. If the orders individually fall short of the domain's AAV, presenting them as one Collection of Task Orders, with AAV calculated across the whole span, may be the only way they count at all, and only one collection is allowed per domain [1]. Running both calculations before submission avoids the surprise.

Schema Design: One Database for 13 Domain Matrices

The reason spreadsheets fail for OASIS+ scoring is structural, not cosmetic. A flat spreadsheet with one row per project cannot represent the many-to-many relationship between projects and domains without creating duplicate rows. Duplicate rows inevitably lead to duplicate counting, which is exactly the error a reviewer will catch.

A normalized relational model needs four core tables: Projects, Domains, Project_Domain_Allocations, and Evidence_Artifacts. The junction table (Project_Domain_Allocations) is where scoring logic lives. It records which project is allocated to which domain, with what credited scope, and at what value.

Critical fields for the Projects table include:

  • contract_number: The base contract number, not individual task orders
  • contract_type: FFP, T&M, CPFF, IDIQ (affects how annual value is calculated)
  • naics_primary: Primary NAICS code on the contract
  • annual_value_calculated: Computed with GSA's AAV formula, total project value divided by the days of performance and multiplied by 366 [1]
  • pop_start and pop_end: Period of performance dates (must fall within GSA's lookback window)
  • prime_or_sub: Whether your firm was prime or subcontractor
  • labor_categories_performed: Maps to domain-specific scope requirements
  • modification_history: JSON or linked table of contract modifications affecting value or scope
sql
CREATE TABLE projects (
    project_id SERIAL PRIMARY KEY,
    contract_number VARCHAR(50) NOT NULL,
    contract_type VARCHAR(10) CHECK (contract_type IN ('FFP','TM','CPFF','IDIQ','BPA')),
    naics_primary VARCHAR(6) NOT NULL,
    total_obligated_value DECIMAL(15,2),
    pop_start DATE NOT NULL,
    pop_end DATE NOT NULL,
    prime_or_sub VARCHAR(5) CHECK (prime_or_sub IN ('PRIME','SUB')),
    -- GSA AAV: total value / days of performance x 366; projects of 12 months or less use face value
    annual_value_calculated DECIMAL(15,2)
        GENERATED ALWAYS AS (CASE WHEN (pop_end - pop_start) <= 366 THEN total_obligated_value
            ELSE total_obligated_value / (pop_end - pop_start) * 366 END) STORED
);

CREATE TABLE project_domain_allocations (
    allocation_id SERIAL PRIMARY KEY,
    project_id INT REFERENCES projects(project_id),
    domain_id INT REFERENCES domains(domain_id),
    credited_scope TEXT NOT NULL,
    relevance_basis VARCHAR(20) CHECK (relevance_basis IN ('auto_naics_psc','standard')),
    allocation_status VARCHAR(20) DEFAULT 'draft'
        CHECK (allocation_status IN ('draft','validated','submitted','adjudicated'))
);

-- Prevent the same project from being double-allocated to the same domain
CREATE UNIQUE INDEX idx_unique_project_domain
    ON project_domain_allocations(project_id, domain_id);

The `UNIQUE INDEX` on `project_domain_allocations` stops the same project from being allocated twice to the same domain at the data layer. It does not stop a project from appearing in several domains, so pair it with the cross-domain conflict check described later.

The Field Most Contractors Forget

Contract modification history directly impacts your annual value calculation. A base contract awarded at $2M that received three modifications increasing the ceiling to $5.8M over four years has a very different annual value than the original $2M. If your project records only store the original award amount, your AAV will not match the documentation you submit. Store the current value and the modifications behind it. Pull modification data from FPDS-NG or your contracting officer's files and store it as a linked record.

Automating the Average Annual Value Proof

Each QP must meet or exceed the minimum AAV that J.P-1 sets for the domain and pool, and GSA's own examples show the minimum differs by domain [1]. AAV is the total project value divided by the total number of days of performance, multiplied by 366; GSA's example is a $3M project over 450 days, which has an AAV of about $2.44M [1].

The calculation itself is straightforward, but assembling the evidence chain is where applicants struggle. You need three data sources aligned to a single contract number:

  1. FPDS-NG records: Pull the contract summary including all modifications. This gives you the official obligated amount.
  2. Invoicing records: Internal financial data showing actual billings by period. Keep them ready in case FPDS data is incomplete.
  3. CPARS entries: Past performance evaluations that reference the same contract number and confirm the scope performed.

The problem is these three sources frequently disagree. FPDS may show a $4.2M obligation while your invoicing records show $3.8M billed and CPARS references a different contract number because the evaluation was written at the task order level.

Here's an illustrative case. A contractor holds a T&M IDIQ with four task orders: $1.2M, $800K, $2.1M, and $900K. Submitted individually, two of them fall below a $1M domain minimum. Submitted as one Collection of Task Orders spanning, say, 1,095 days from the first start to the last end, the $5M total yields an AAV of about $1.67M ($5M / 1,095 x 366). One collection, one QP, one evidence package, and it uses the domain's single collection slot [1].

Build your evidence packages so every number traces to the award documents and FPDS records you will submit.

Scoring Automation: From Manual Spreadsheet to Repeatable Pipeline

Manual scoring spends most of its time cross-referencing spreadsheets, not making strategic decisions. A scoring automation pipeline handles the mechanical calculations and flags only the exceptions that require human judgment. The function below is a simplified sketch: the point values are placeholders, and a real implementation should load each domain's credits, AAV minimum, and threshold from J.P-1.

python
def score_domain(domain_id, projects, allocations, certs, cpars_ratings):
    """Calculate OASIS+ domain score from project database records."""
    domain_projects = [
        a for a in allocations
        if a['domain_id'] == domain_id and a['allocation_status'] == 'validated'
    ]

    # Qualifying Project scoring (placeholder credit values; load real ones from J.P-1)
    experience_score = 0
    qualifying_projects = []
    for alloc in domain_projects:
        proj = projects[alloc['project_id']]
        annual_val = proj['annual_value_calculated']
        threshold = domain_min_aav(domain_id, proj.get('business_size'))  # from J.P-1

        if annual_val < threshold:
            alloc['flag'] = f"Annual value ${annual_val:,.0f} below ${threshold:,.0f} threshold"
            continue

        if not naics_matches_domain(proj['naics_primary'], domain_id):
            alloc['flag'] = f"NAICS {proj['naics_primary']} not aligned to domain"
            continue

        qualifying_projects.append(alloc)

    # Placeholder credit assignment; GSA allows at most five QPs per domain
    experience_score = min(len(qualifying_projects), 5) * qp_credit(domain_id)

    # Systems and Certifications (credit values from J.P-1)
    cert_score = sum(c['point_value'] for c in certs if c['domain_id'] == domain_id)

    # Past performance screen (placeholder mapping)
    relevant_ratings = [r['score'] for r in cpars_ratings
                        if r['contract_number'] in
                        [projects[a['project_id']]['contract_number'] for a in qualifying_projects]]
    pp_score = calculate_cpars_points(relevant_ratings)  # placeholder

    total = experience_score + cert_score + pp_score
    threshold_points = domain_threshold(domain_id)  # 36 for SB contracts, 42/45 for Unrestricted
    shortfall = max(0, threshold_points - total)

    return {
        'domain_id': domain_id,
        'experience': experience_score,
        'certifications': cert_score,
        'past_performance': pp_score,
        'total': total,
        'qualifies': total >= threshold_points,
        'shortfall': shortfall,
        'flags': [a.get('flag') for a in domain_projects if a.get('flag')]
    }

The validation rules embedded in this function catch three categories of errors before submission: projects below the annual value threshold, NAICS code misalignment to the target domain, and point caps that prevent over-counting. The `flags` output tells your team exactly which projects need attention and why.

Running this function across all 13 domains takes seconds. When GSA opens an on-ramp, the firms that move fastest are the ones that can re-score their portfolio quickly, not the ones that start from scratch each cycle.

Building Audit-Ready Documentation That Survives GSA Review

Organize your evidence package in a sequence an evaluator can follow: (1) the self-scoring summary, (2) contract documentation for each claimed project, (3) past performance records, (4) certification and systems evidence, and (5) a cross-domain overlap check for multi-domain submissions. Each qualifying project needs a project evidence folder containing the contract award document, all relevant modifications, a scope summary mapping to the domain definition, annual value calculation with supporting data, and the corresponding CPARS evaluation.

Scoring ElementRequired EvidenceAcceptable FormatCommon Deficiency
Relevant Experience (per project)Contract award, modifications, scope narrativePDF copies from FPDS, signed CO lettersMissing modifications that affect value calculation
Annual Value ThresholdFPDS obligation data, invoicing summaryFPDS printout with modification detail, internal financial reportUsing ceiling value instead of obligated value
Relevant portion of a broader projectDocumentation of the relevant workDistinct CLIN or PWS/SOW section cross-referenced in the narrativeClaiming relevance without showing which portion of the work is relevant
CertificationsCurrent certification documentsPDF of certificate with expiration date visibleExpired certificates at time of submission
CPARS RatingsCPARS evaluation reportContractor CPARS access PDFRatings filed under task order numbers instead of base contract
NAICS AlignmentSelf-certification, SAM.gov profileSAM.gov entity registration printoutNAICS listed in SAM doesn't match contract NAICS

A content reuse library becomes essential when applying to multiple domains. The same project might support two different domain applications with different scope emphasis. Store your project narratives as modular components (scope description, value summary, integration narrative) so you can assemble domain-specific evidence packages without rewriting from scratch. The critical rule: no two domain packages should describe the same project with contradictory scope claims. Your database schema handles the allocation logic, but your narrative library must enforce consistency at the prose level.

Multi-Domain Strategy: When to Apply Broad vs. When to Go Deep

Not all 13 OASIS+ domains carry equal value or qualification difficulty for your firm. Domains that demand specialized project histories are harder to qualify for with a general portfolio.

Applying to every domain you might qualify for is a mistake if it thins your evidence across too many applications. Each domain application requires dedicated project allocations. If you have eight qualifying projects and try to cover six domains, you're spreading those projects thin and risking shortfalls in multiple domains simultaneously.

The smarter approach: rank domains by three criteria.

  1. Revenue potential: Which domains align with your pipeline and active opportunities?
  2. Qualification certainty: Where do you clear the threshold with margin, and where are you one disallowed project from falling short?
  3. Evidence exclusivity: How many of your qualifying projects can only be used in one domain?

A practical sequencing strategy for continuous on-ramp cycles: qualify first for your two highest-confidence, highest-value domains. Use subsequent on-ramp windows to add domains as you accumulate new qualifying projects. Your project database makes this trivial because you can re-run the scoring function each cycle with updated project records and see exactly where new projects push you over the threshold.

Projects that qualify across multiple domains are your most valuable assets. Check the current solicitation's rules on reusing a project across domains, and let your `project_domain_allocations` table enforce whatever policy you adopt. Before each submission, run a conflict detection query to ensure no project is double-allocated across the domains you're applying for simultaneously.

Your First 48 Hours: Setting Up the Scoring Infrastructure

Stop estimating your OASIS+ readiness from memory. Here's what to do in the next two days.

Hours 1 through 8: Inventory your contract data. Pull every active and recently completed contract from three sources: your internal project management system, your SAM.gov entity registration (confirm your NAICS codes match your target domains), and FPDS-NG for federal contracts (search by your UEI). Export everything into a structured format. Prioritize contracts whose AAV clears the minimum for your target domains.

Hours 9 through 24: Map projects to domain matrices. Using GSA's published domain definitions (available on the OASIS+ Interact page), tag each contract with the domains it could potentially support. Create your `project_domain_allocations` records in draft status. Run the scoring function from the previous section against each target domain.

Hours 25 through 48: Identify gaps and build your action plan. Your automated scoring output will show exactly which domains you qualify for today, which are within 5 points of qualification, and which are unreachable with current evidence. For domains within 5 points, identify what's missing: is it a project below the value threshold (fixable with modification data), a missing certification (fixable with procurement), or a CPARS gap (fixable by requesting evaluations from contracting officers)?

The metric to track weekly: qualified domain count at current evidence levels versus your target domain count. If you're at 2 of 5 target domains today, your scoring pipeline will tell you exactly which projects or certifications close the gap for domains 3, 4, and 5.

Firms that miss the threshold often have the qualifications but lack the data architecture to prove them in the format GSA requires. Building that architecture now, before the next on-ramp window opens, is the difference between a first-attempt qualification and a costly resubmission.

Start with the database schema. Everything else follows from clean data.

References