ot-cost-analysis
Trigger for: Other Transaction or OT should-cost, cost estimate, cost-share analysis, milestone pricing, funding profile, proposed-price comparison, prototype price analysis, research OT budget, production follow-on OT estimate, or OT price-reasonableness support under 10 U.S.C.
Install
npx skills add https://github.com/1102tools-dev/federal-contracting-skills/tree/main/skills/ot-cost-analysis
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install 1102tools-dev-federal-contracting-skills@llmmart
git clone https://github.com/1102tools-dev/federal-contracting-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole 1102tools-dev/federal-contracting-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
OT Cost Analysis
Purpose and operating boundary
Build an auditable, formula-driven cost analysis organized by OT milestone. Separate total project cost, the non-Federal contribution, any consortium or administrative fee, the proposed payment amount, and the Government funding requirement. Use market evidence and arithmetic to support the Agreements Officer without originating the authority path, eligibility finding, significant-participation finding, successful-completion finding, or price-reasonableness determination.
Do not:
- Decide whether 10 U.S.C. 4021, 4022, or 4022(f) applies.
- Decide whether a participant is a nontraditional defense contractor, nonprofit research institution, small business, or significant participant.
- Invent a cost-share ratio, exceptional-circumstances determination, consortium fee, learning curve, indirect-rate structure, or proposed-price basis.
- State that a proposed amount is fair, reasonable, acceptable, competitive, aggressive, premium, or justified.
- Treat a BLS or CALC+ benchmark as the performer's required rate.
- Call the output a FAR 15.404 analysis or an IGCE.
When a sentence would conclude the Agreements Officer's judgment, replace it with the source data, the variance, the scenario range, and the decision left open.
Reference map
Load only the references needed for the active workflow:
- authority-and-cost-sharing.md before classifying or applying a cost share.
- labor-and-costing-methods.md before deriving labor, materials, scenarios, ceilings, fees, or funding timing.
- data-source-operations.md before mapping SOCs or calling BLS, CALC+, or Per Diem operations.
- workbook-specification.md in full before generating the workbook.
- professional-product-standard.md before generating the workbook.
- validation-gates.md before building and again before delivery.
- runtime-adaptation.md when collecting structured answers, locating tools, selecting a calculation engine, or delivering files.
Non-negotiable gates
- Authority is supplied, not inferred: Require the user or Agreements Officer to identify Research OT under 10 U.S.C. 4021, Prototype OT under 10 U.S.C. 4022, or follow-on production under 10 U.S.C. 4022(f). Explain differences but do not choose.
- Correct 4022(d) paths: Path A is significant participation by at least one nontraditional defense contractor or nonprofit research institution. Path B requires all significant non-Government participants to be small businesses or nontraditional defense contractors. Path C requires at least one-third of total project cost from non-Federal sources. Path D is a senior procurement executive's written exceptional-circumstances determination. There is no 4022(d)(1)(D) "competition commitment" path.
- Research OT contribution: For 10 U.S.C. 4021, record that Government funds should, to the extent the Secretary determines practicable, not exceed the total provided by other parties. Do not translate that into an automatic 50/50 rule or automatic 100% Government funding. Require the approved arrangement.
- Production follow-on contribution: Section 4022(d) does not apply to a follow-on under 4022(f). Do not automatically carry the prototype ratio, and do not automatically set Government funding to 100%. Require the negotiated production arrangement.
- Proposed-amount basis: Before comparing numbers, confirm whether each proposed amount represents total project cost, the requested Government payment, a milestone payment, or a cost-type ceiling. Never compare unlike bases.
- Cost-share denominator: Apply a performer ratio to total project cost. For Path C, the non-Federal share must be at least one-third of total project cost. Keep Government share plus performer share equal to the same total project-cost basis before separately treated fees.
- Fee basis: Use a consortium or administrative fee only when the user supplies its rate or fixed amount, base, timing, and cost-share treatment. Default to zero, not five percent.
- CALC+ signature: Use
/v3/api/ceilingrates/withkeyword=when keyword search is required. Never useq=. Preserveaggregations.labor_category.buckets[*].keyanddoc_countwhen discovery is used. - BLS vintage and aging: Call
detect_latest_yearat runtime. Store BLS vintage and agreement start asYYYY-MM; useVALUE(LEFT(...))andVALUE(MID(...))for month gap. Never trust a stale constant, useYEAR()on text, or substituteDATEDIF. - Formula-driven workbook: User-adjustable assumptions remain inputs. Calculated labor, escalation, ceilings, cost shares, fees, variances, scenarios, and cumulative funding remain formulas that reference those inputs.
- Cost-type branch: Show both independent should-cost and the user-approved ceiling basis. Government maximum exposure and planned performer contribution at ceiling must use the same ceiling basis. Do not represent either as actual incurred cost.
- Independent validation: Run formula structure, independent Python recomputation, and real-engine verification when available. Openpyxl does not calculate formulas.
- AI boundary: Workflow B returns neutral comparison data unless the user supplies the exact determination text for a controlled memo fill. Never originate the conclusion.
- Staged approval: A derived milestone or staffing model must end at its confirmation question and wait. Do not self-approve or begin data calls while approval is pending.
- Credentialed API pacing: Serialize keyed federal API calls and leave at least three seconds between calls. Honor longer server retry instructions and stop rather than rapidly retrying a rate limit.
Pre-flight: capabilities and dependencies
When this skill is entered immediately after a numbered Other Transaction Agent cost-analysis selection and the current assistant response has not already shown the orchestrator's outcome preview, emit these exact four lines before milestone intake, the proposed-amount boundary, or a capability check:
Begin line 1 with Recommended outcome:. Do not precede the block with a heading, acknowledgement, selection recap, routing narration, or code fence.
Recommended outcome: Milestone-based OT Cost Analysis `.xlsx`
Includes: milestone should-cost, labor and market benchmarks, materials, travel, ODCs, fees, contribution treatment, funding profile, scenarios, and validation
Boundary/default: approved milestones are the default basis; do not infer authority, statutory path, cost share, payment type, ceiling, or a price-reasonableness conclusion
Next: collect approved milestones or concept, authority facts, and missing cost inputs
This is a routing fallback, not a second preview. Do not repeat it when the orchestrator already rendered the four lines in the current assistant response. The fixed Workflow B determination boundary still follows immediately when the supplied context directly triggers it; never replace the preview with intake alone.
Select the workflow and begin useful intake before testing dependencies. Do not make workbook authoring or provider availability the first response after selection. A read-only or artifact-limited session may still reuse supplied facts, identify missing inputs, and develop or review the milestone structure. Inspect only the capabilities the route actually needs immediately before its first dependent MCP call or before promising or beginning workbook generation. Workflow B's fixed boundary takes precedence and must be shown before any pre-flight or tool call.
- Call
bls-oews.get_access_statusbefore any BLS data call. Forlimited_fallback, tell the userBLS_API_KEYis not configured and v1 is limited to 25 requests per day and 10 years per query; continue only when the workload fits. A missing status operation means an outdated or incomplete MCP or shared host profile. - When travel is in scope, call
gsa-perdiem.get_access_statusbefore Per Diem data. Forlimited_fallback, tell the userPERDIEM_API_KEYis not configured andDEMO_KEYis limited to approximately 10 requests per hour. A missing status operation means an outdated or incomplete MCP or host profile. - Treat
configured_unverifiedas presence only. Classify a later 401/403 as rejected credentials and 429 as rate limiting, not an outage. Never retry automatically or ask for a key in chat. Direct setup tohttps://1102tools.com/setup#credentialsand require a restart. - For a build, require
bls-oewsoperationsdetect_latest_year,get_wage_data, metro lookup, and SOC lookup plusgsa-calcoperationssuggest_contains,exact_search,keyword_search, andigce_benchmarkor equivalent schemas. - Require
gsa-perdiemoperationsestimate_travel_cost,lookup_city_perdiem, andget_mie_breakdownonly when travel is in scope. - Require an
.xlsxauthoring path and Python 3.10 or later with openpyxl for the bundled validators. Prefer a real spreadsheet engine for formula execution. - For a build, test
detect_latest_yearbefore wage retrieval. Test Per Diem only when travel first becomes necessary. Apply the three-second keyed-call spacing to tests and production calls. - If an operation is unavailable, inspect the same server for a semantically equivalent operation. Do not silently replace an MCP with an ad hoc public API request.
- Stop and report missing, unauthenticated, unavailable, or outdated/incomplete capabilities before beginning dependent work. Preserve completed intake so it is not requested again after the capability is restored. Do not expose credentials.
Select a workflow
Workflow A: build from approved milestones
Use when the user supplies a milestone table or the approved handoff from ot-project-description-builder. Preserve milestone IDs, descriptions, deliverables, success criteria, dates, payment type, and user overrides. Ask only for missing cost inputs.
Workflow A+: build from a concept
Use when no approved milestone table exists. Derive a candidate milestone structure from the prototype or research objective, TRL progression when relevant, delivery evidence, and schedule. Present the table, ask the user to confirm or amend it, end at that question, and wait. Do not call pricing MCPs before approval.
Workflow B: proposed-amount comparison
On the first response, make no tool call. Emit this boundary and stop:
I can build an independent OT should-cost and show the proposed amount's basis, variance, scenario position, and market benchmarks. I cannot originate the Agreements Officer's price-reasonableness determination or negotiation position.
Choose one:
Option A: Comparison data only. I produce neutral tables and a methodology record with no verdict.
Option B: Controlled memo fill. You provide the exact rationale and determination text. I reproduce it verbatim in a DRAFT section and place the neutral evidence beneath it.
Which option?
For Option B, proceed only after the user supplies both the rationale and determination text. Never expand or strengthen it.
Collect and confirm inputs
Use the host's structured question tool when available. Otherwise use numbered choices and accept numbers, labels, or free text. Batch related missing inputs.
Required before cost-share math:
- Authority: 4021 research, 4022 prototype, or 4022(f) follow-on production
- For 4022 prototype, user-confirmed subsection (d) path A, B, C, or D
- Approved performer contribution ratio, cash/in-kind composition, and source
- Performer structure, locations, and Agreements Officer-confirmed status facts
- Proposed-amount basis when a proposal exists
- Consortium or administrative fee facts, or explicit zero
Required before a build:
- Approved milestones with duration, success evidence, payment type, and timing
- Labor categories, staffing or hours, performance location, and start month
- Materials, travel, ODC, and escalation bases
- Productive hours, burden basis, and payment/funding convention
- For cost-type milestones, the approved ceiling or ceiling-margin assumption
Do not guess the authority, statutory path, cost share, location, milestone payment type, fee, proposed-amount basis, or cost-type ceiling.
Consume an approved OT project handoff
Treat a table labeled MILESTONE HANDOFF TABLE and identified for OT Cost Analysis as user-reviewed input.
- Preserve every milestone field, derivation, pending decision, and override.
- Do not repeat milestone decomposition.
- Reconcile contradictions between the handoff and current instruction in a short table and wait for the user to choose.
- Ask the remaining cost inputs in one stage and end at its question.
Orchestration
Step 0: derive milestones only when required
For Workflow A+:
- Hard stop if the project objective is absent.
- Identify expected evidence of completion, schedule, technical progression, Government decisions, and performance location.
- Use TRL only when the project actually uses TRL. Do not force research, software, business-process, or service prototypes into an unsupported TRL ladder.
- Propose milestone ID, objective, duration, entry conditions, completion evidence, payment type marked
PENDINGunless supplied, and funding timing. - Ask the user to confirm or amend the milestone structure. End immediately after the question and wait.
Step 1: validate authority and economics
Read authority-and-cost-sharing.md.
- Restate the user-supplied authority and path without converting facts into a legal determination.
- Validate the cost-share arithmetic and source. For 4022 Path C, reject a non-Federal ratio below one-third.
- Record whether each contribution is cash or in kind and how it will be valued and tracked.
- Confirm proposed-amount basis and fee treatment.
- For 4022(f), record the predecessor prototype and user-supplied competitive-selection and successful-completion facts, but do not make the follow-on eligibility finding.
Step 2: benchmark labor
Read data-source-operations.md and labor-and-costing-methods.md.
- Map each labor category to the best-supported SOC and record proxies.
- Call
detect_latest_year, then retrieve metro, state, or national BLS percentiles using the documented fallback ladder. - Age the selected direct wage to the agreement start through assumption cells.
- Apply the user-approved burden method. It is a scenario benchmark, not an audit-approved indirect rate.
- For institutions with supplied billing rates or approved indirect structures, preserve those rates and label the source. Do not invent academic billing ranges.
- Keep each performer and location separate. Do not average unlike MSAs or organizations without an approved allocation.
Step 3: obtain CALC+ positioning
Use the discovery-first operation flow. Keep title-match and experience-match pools separate when useful. Record the pool, count, percentiles, and query date. Sparse or absent results remain a disclosed limitation; they do not authorize an invented specialty premium.
Step 4: price materials, travel, and ODCs
Use user-supplied bills of material, quotes, analogous prices, quantities, and escalation bases. Apply materials escalation from project start to each milestone start using month-based compounding. A production learning curve is used only when the user supplies the method and factor.
Use GSA Per Diem for authorized CONUS travel and the operation rules in the data-source reference. Keep airfare, local transportation, and OCONUS travel on their supplied source bases.
Step 5: build milestone should-cost
For each milestone:
labor = sum(category hours * category burdened benchmark)
materials = sum(quantity * unit cost * approved escalation)
travel = sum(validated trip costs)
ODCs = sum(other direct cost inputs)
total project cost = labor + materials + travel + ODCs
performer share = total project cost * approved performer ratio
Government share = total project cost - performer share
fee = approved fee base * approved fee rate, or approved fixed amount
Government funding requirement = Government share + Government-paid fee
For cost-type milestones, calculate the same columns at independent should-cost and at the approved ceiling. Label the ceiling view as maximum exposure, not expected actual cost.
Present the per-milestone build and ask for confirmation before final workbook assembly when staffing, materials, or cost allocation was derived rather than supplied.
Step 6: scenario analysis
Vary only assumptions with a documented basis. Keep low, working, and high labor burden, materials, and escalation inputs in workbook cells. Do not ship generic 1.8/2.0/2.2 or materials multipliers as facts unless the user approves them for this analysis.
Step 7: build the workbook
Read professional-product-standard.md and workbook-specification.md in full. Build the seven required sheets and preserve the formal calculation controls, while making the default summary and print experience concise and decision-centered:
- Blank proposed-amount cells when no proposal exists, with conditional variance formulas.
- Formula-driven labor, escalation, ceiling, share, fee, scenario, and cumulative-funding cells.
- Derived milestone labor hours: each priced labor row carries FTE loading, weeks, and hours-per-FTE-week input cells and computes hours as a formula over them, each milestone carries a formula reconciliation returning
OKorMISMATCH, and any sheet restating those hours references the Milestone Detail cells. Never write hours as a literal or demote the reconciliation to prose. - Separate performer and Government contributions that reconcile to total project cost.
- Cost-type should-cost and ceiling views using the same contribution basis.
- Compact, reproducible raw-data records rather than full API payloads.
- Neutral methodology language and user-supplied Option B text verbatim when applicable.
Step 7.5: validate before delivery
Read validation-gates.md.
- Run
scripts/validate_workbook.py <workbook> --expected <inputs.json> --engine none. - Run
scripts/recompute_expected_values.py <inputs.json>. - If LibreOffice is available, rerun the validator with
--engine autoor--engine libreoffice; require the engine layer to reject cached spreadsheet errors anywhere in the recalculated workbook before mapped values are accepted. - Inspect every worksheet for formulas, units, source notes, input formatting, broken references, and leaked internal instructions.
- Verify the workbook as a ZIP and, when practical, open or render it in a real spreadsheet application.
- Fix failures and repeat all layers.
Delivery gate: the workbook must pass the validate_workbook.py structural audit with the canonical seven-sheet layout before delivery. Bespoke sheet layouts are not permitted even when the content is correct. A failing validator blocks delivery; never deliver a rejected workbook.
If no spreadsheet engine is available, state exactly:
Formula structure and independent calculations passed. Formula execution was not independently verified in Excel or LibreOffice.
Step 8: deliver
State which validation layers ran. Summarize the authority and contribution facts as user-supplied inputs, the should-cost range, the Government funding range, key sensitivities, missing evidence, and refresh dates. Do not state a price-reasonableness conclusion unless it is the user's verbatim Option B text, visibly marked DRAFT.
Out of scope
- FAR-based IGCEs and FAR 15.404 determinations
- Authority, eligibility, significant-participation, exceptional-circumstances, or successful-completion findings
- Certified cost or pricing data demands
- Unsupported indirect-rate, profit, fee, learning-curve, or specialty-premium assumptions
- Grants, cooperative agreements, and OT project descriptions
- OCONUS per diem without a supplied State Department or other approved source
MIT © James Jenrette / 1102tools. Source: github.com/1102tools-dev/federal-contracting-skills
Files (federal-contracting-skills)
-
agents
-
openai.yaml 300 B
interface: display_name: "OT Cost Analysis" short_description: "Build auditable milestone-based OT cost analyses" default_prompt: "Use $ot-cost-analysis to build an OT should-cost, contribution model, and funding profile from my approved milestones." policy: allow_implicit_invocation: true
-
-
references
-
authority-and-cost-sharing.md 4.9 KB
# OT Authority and Cost-Sharing Reference Use the statute and current DoD guidance as the controlling sources. This reference prevents an analytical workbook from silently making an Agreements Officer decision. ## 1. Authority map ### 10 U.S.C. 4021 Research OT - Applies to basic, applied, and advanced research projects. - Under subsection (e)(2), to the extent the Secretary determines practicable, Government funds should not exceed the total amount provided by other parties. - This is not an automatic 50/50 rule, and it is not authority to default to 100% Government funding. - Require the user-supplied, approved contribution arrangement and record its rationale and source. ### 10 U.S.C. 4022 Prototype OT Require the user or Agreements Officer to identify one subsection (d)(1) condition: | Path | Statutory condition | Workbook handling | |---|---|---| | A | At least one nontraditional defense contractor or nonprofit research institution participates to a significant extent | Record the participant and user-supplied basis. Do not decide significance. No statutory ratio follows from Path A alone. | | B | All significant non-Government participants are small businesses or nontraditional defense contractors | Record the participant list and user-supplied status. No statutory ratio follows from Path B alone. | | C | At least one-third of total prototype-project cost is paid from non-Federal sources | Require performer ratio `>= 1/3` of total project cost. Reject `0.33` if it rounds below exactly one-third. | | D | The senior procurement executive determines in writing that exceptional circumstances justify the OT | Record the determination date or `PENDING`; do not invent it. No statutory ratio follows from Path D alone. | There is no 4022(d)(1)(D) competition-commitment path. ### 10 U.S.C. 4022(f) Follow-On Production - Section 4022(d) does not apply to a follow-on production contract or transaction under subsection (f). - Do not carry the prototype ratio automatically. Do not set the production ratio to zero automatically. Use the negotiated arrangement supplied by the user. - Record, without deciding, whether the user states that competitive procedures selected the prototype participants and that the relevant participant successfully completed the prototype. - Do not originate the follow-on eligibility finding or characterize a prototype as successfully completed. ## 2. Cost-share denominator and reconciliation The approved performer ratio applies to total project cost, not only to the Government-requested payment. ```text total project cost = Government project share + performer project share performer share = total project cost * performer ratio Government share = total project cost - performer share ``` For 4022 Path C: ```text performer ratio >= 1 / 3 Government ratio <= 2 / 3 ``` Keep cash and in-kind contributions visible. Record the source, valuation method, timing, and tracking responsibility for in-kind contributions. Do not treat an undocumented asserted value as validated. ## 3. Proposed-amount normalization Confirm one basis for each submitted amount: - Total project cost - Requested Government funding - Fixed milestone payment - Cost-type estimated cost - Cost-type ceiling - Consortium or administrative fee Normalize before comparison. For example, a Government funding request under a one-third performer share is not comparable to the workbook's total project cost without converting one side. ## 4. Fees Do not default a consortium or administrative fee. Require: - Percentage or fixed amount - Cost base - Per-milestone, one-time, or other timing - Whether the fee is Government-paid, shared, or included in total project cost - Source document or user approval The workbook's default fee input is zero. A fee added after project-cost shares must not be presented as part of the statutory Path C denominator unless the user supplies that treatment. ## 5. Price-reasonableness boundary The workbook may report: - Proposed and normalized amount bases - Dollar and percentage variances - BLS and CALC+ benchmark positions - Analogous-price comparisons - Low, working, and high scenario positions - Sensitivity to labor, material, schedule, cost share, and fee assumptions It may not originate a conclusion that a price is fair, reasonable, acceptable, justified, competitive, aggressive, or premium. The Agreements Officer owns the conclusion and negotiation position. For controlled memo fill, reproduce the user's rationale and determination verbatim, label it `DRAFT - USER-SUPPLIED DETERMINATION TEXT`, and keep the neutral analysis distinct. ## 6. Primary sources - 10 U.S.C. 4021, Research projects: transactions other than contracts and grants - 10 U.S.C. 4022, Authority of the Department of Defense to carry out certain prototype projects - DoD Other Transaction Guide, OUSD(A&S), July 2023, Version 2.0 - Guide to Research Other Transactions, OUSD(R&E), February 2026 -
data-source-operations.md 6.2 KB
# OT Data Source Operations Use stable server and operation names. The host may wrap them in a namespace; never copy the wrapper into the workbook. ## 1. Request pacing Serialize credentialed federal API calls and leave at least three seconds between them, including capability checks. Do not parallelize keyed BLS or Per Diem calls. Honor a longer provider retry interval. Stop and report a rate limit instead of rapidly retrying. Use reasonable pacing for unkeyed services too. ## 2. SOC mapping Classify the work before selecting a code. Record ambiguous mappings and alternatives queried. | OT role | Common SOC | BLS title | |---|---|---| | IT Program Manager | 11-3021 | Computer and Information Systems Managers | | Engineering or R&D Manager | 11-9041 | Architectural and Engineering Managers | | Project Manager | 13-1082 | Project Management Specialists | | Management Analyst | 13-1111 | Management Analysts | | Computer Systems Analyst | 15-1211 | Computer Systems Analysts | | Information Security Analyst | 15-1212 | Information Security Analysts | | Software Developer | 15-1252 | Software Developers | | Software QA Analyst or Tester | 15-1253 | Software Quality Assurance Analysts and Testers | | Data Scientist | 15-2051 | Data Scientists | | Aerospace Engineer | 17-2011 | Aerospace Engineers | | Electrical Engineer | 17-2071 | Electrical Engineers | | Electronics Engineer | 17-2072 | Electronics Engineers, Except Computer | | Industrial Engineer | 17-2112 | Industrial Engineers | | Mechanical Engineer | 17-2141 | Mechanical Engineers | | Multidiscipline physical Systems Engineer | 17-2199 | Engineers, All Other | | Physicist | 19-2012 | Physicists | | Chemist | 19-2031 | Chemists | | Materials Scientist | 19-2032 | Materials Scientists | | Technical Writer | 27-3042 | Technical Writers | | Engineering Technician, other | 17-3029 | Engineering Technologists and Technicians, Except Drafters, All Other | Use 11-1021 for operations management, 11-3021 for IT management, and 11-9041 for physical engineering management unless better evidence supports another code. Do not map every Program Manager to the same SOC. Robotics, autonomy, artificial intelligence, directed energy, quantum, hypersonics, and similar labels often span disciplines. Price the actual work through supported roles rather than using a fictional specialty SOC. Label every proxy. ## 3. BLS OEWS ### Runtime vintage Call `detect_latest_year` before wage retrieval. Record the returned year and use it in the Summary, Labor Benchmarking, Methodology, Raw Data, and aging formula. A baseline written in the skill never overrides the runtime result. ### Wage retrieval Call: ```text get_wage_data( occ_code=<six-character SOC>, scope=<metro|state|national>, area_code=<MSA or state FIPS>, datatypes=["04", "11", "12", "13", "14", "15"] ) ``` The requested data types provide mean plus P10, P25, P50, P75, and P90. Do not send unsupported data types. Fallback ladder: 1. Metro 2. State, only after the current metro code and series are checked 3. National Use `list_common_metros` and other server lookup operations to resolve codes. Record every fallback and reason. When BLS lacks job levels, use a disclosed percentile convention. If no levels are supplied, use P50 and do not invent a junior, mid, and senior mix. Treat any capped percentile as a lower bound after confirming the current reporting cap from the returned data or BLS release metadata. Keep every performer and location separate. Do not average unlike MSAs unless the user supplies an allocation and approves a weighted calculation. ## 4. CALC+ ### Silent-wrong-answer signature The keyword route is: ```text /v3/api/ceilingrates/?keyword=<term> ``` Use `keyword=`. Never use `q=`. The wrong parameter may be accepted while returning an unfiltered corpus. Discovery buckets are found at: ```text aggregations.labor_category.buckets[*].key aggregations.labor_category.buckets[*].doc_count ``` ### Discovery-first flow 1. Call `suggest_contains(field="labor_category", term=<term>)`. 2. When exact buckets form a usable pool, call `exact_search(field="labor_category", value=<bucket>)`. 3. When buckets are fragmented, call `keyword_search(keyword=<term>)` and disclose that other fields may match. 4. Call `igce_benchmark` or the current equivalent for compact percentiles and sample size. 5. Use `page_size=1` when an operation requires a page size for aggregation retrieval. Never send zero. For senior roles, keep title-match and experience-match pools separate. Label a small pool as directional. When results are absent, try one broader supported term and then record `No CALC+ data; BLS and other supplied sources only.` Do not invent a defense specialty premium. CALC+ contains awarded ceiling rates from another market and contract context. It is positioning evidence, not a binding OT rate or a conclusion. ## 5. GSA Per Diem For one or more nights, call: ```text estimate_travel_cost( city=<civilian locality>, state=<state>, num_nights=<integer>, travel_month=<optional month>, fiscal_year=<optional FY> ) ``` Use the returned first/last-day M&IE treatment once. Do not apply 75 percent a second time. For a day trip, do not pass zero nights to an operation that requires at least one. Use `lookup_city_perdiem`, apply the returned first/last-day M&IE once, and keep lodging at zero. Translate a military installation or laboratory to the correct civilian GSA locality and record the crosswalk. Verify the returned county when locality boundaries matter. If the requested fiscal year is not published, retry the most recent available year once, record both years, and flag the data for refresh. Do not silently query a different year. GSA Per Diem covers CONUS travel. Use OCONUS rates only from a user-supplied approved source. ## 6. Raw-data record Record compact reproducible fields, not full payloads: - BLS operation, SOC, scope, area, data types, returned vintage, selected percentile, and fallback - CALC+ operation, exact bucket or keyword, count, percentiles, query date, and pool limitation - Per Diem locality, fiscal year, month, nights, lodging, M&IE, and fallback - Every proxy, derivation, user override, and source date Do not write API keys, access tokens, user paths, host-generated tool names, or internal prompt text to the workbook. -
labor-and-costing-methods.md 3.8 KB
# OT Labor and Costing Methods ## 1. Labor basis Use per-category labor as the canonical method: ```text direct hourly benchmark = aged annual wage / 2,080 burdened benchmark = direct hourly benchmark * approved burden multiplier category hours = supplied hours, or productive hours * FTE * duration / 12 category cost = category hours * burdened benchmark milestone labor = sum(category cost) ``` Do not use 1,880 productive hours to convert annual BLS wages to hourly. Use 2,080 for wage conversion and the user-approved productive-hours value for staffing capacity. Use a blended labor rate only for an explicitly approved early planning approximation. Preserve the category mix used to calculate it. ## 2. Staffing and milestone duration Prefer user-supplied hours or milestone staffing. When deriving a model: - Give every category a workload, deliverable, coverage, system, site, quantity, or schedule basis. - Keep performer and location tags on every line. - Show ramp, overlap, transition, and surge separately. - Reconcile milestone durations to the total period of performance. When the sum differs by more than 10 percent, stop and ask whether gaps are unstaffed or whether staffing spans the full period. - Never invent a specialty premium, clearance factor, academic billing range, or team-size table as a fact. For a 24x7x365 seat: ```text annual coverage hours = seats * 24 * 365 coverage FTE = annual coverage hours / productive hours per FTE ``` At 1,880 productive hours, one seat is 4.6596 FTE. ## 3. Institutional performers When a university, FFRDC, UARC, laboratory, or other institution supplies billing rates or an approved indirect structure, use those values as inputs and record the source. BLS remains a market context or proxy when appropriate, not a substitute for an institutional rate. Do not claim that all such institutions have a common burden range. Do not assume fee or profit treatment. ## 4. Materials and production Use a bill of material, quote, analogous buy, quantity estimate, engineering build-up, or user-approved planning factor. Record quantity, unit, source date, and escalation basis. Default time basis: ```text escalated materials = base materials * (1 + approved annual rate)^(months from project start / 12) ``` Use a learning curve only when the user supplies or approves: - Curve method, such as unit or cumulative-average - Slope - Lot or unit sequence - Recurring-cost base - Excluded nonrecurring cost No universal 95-percent curve exists. ## 5. Cost-type milestone view For a cost-type milestone, show: 1. Independent should-cost 2. User-approved estimated-cost or ceiling basis 3. Government and performer shares at the should-cost basis 4. Maximum Government and planned performer exposure at the ceiling basis The ceiling view is a planning maximum, not actual incurred cost. Both shares must branch on the same ceiling basis or they will not reconcile. ## 6. Funding timing Do not default every OT to obligation-at-start or payment-at-acceptance. Require the user-supplied convention by milestone and fiscal year. Distinguish: - Planned obligation - Milestone payment - Cost reimbursement - Holdback or retainage - Fee payment - Performer contribution timing The cumulative funding profile sums the Government funding requirement using the approved timing convention. ## 7. Scenarios Keep scenario assumptions editable and sourced. Vary the components that drive uncertainty: - Labor burden or approved indirect rates - Staffing or hours - Materials quantities and unit prices - Escalation - Travel frequency - Ceiling margin - Performer ratio when the Agreements Officer specifically requests sensitivity - Fee basis Do not label scenario positions with conclusions such as competitive or premium. Report the proposed amount's numerical position in the range. -
professional-product-standard.md 5.5 KB
# Professional product standard This file is the canonical source for the copy packaged with each 1102tools skill. The packaged copies must remain identical to this file. ## Product judgment Produce a finished professional work product, not a record of the process used to create it. Write for the person who must understand, use, approve, or act on the result. Exercise editorial judgment. Include material that improves the reader's understanding or decision. Omit material merely because it was collected, available, or easy to generate. Every page, section, table, and visual must earn its place. Match the structure, length, voice, and visual treatment to the assignment. Do not reuse a universal report outline. A short decision card, formal contract-file document, analytical workbook, landscape, timeline, or longer consulting report may all be correct products for different requests. Lead with the useful output. Research mechanics, process narration, methodology, limitations, and compliance controls are secondary unless the reader's purpose makes one of them the product. ## Controlled freedom Route rules define the substantive outcome and genuine formal boundaries. They do not prescribe identical headings, page counts, layouts, or section order unless a law, supplied template, calculation model, or downstream interface requires it. Choose the clearest form for each idea: - prose for explanation and judgment; - tables for real comparison or repeated fields; - cards, profiles, matrices, timelines, charts, and callouts when they improve comprehension; - appendices only for material the intended reader may reasonably need. Do not put paragraph-length narrative in narrow table cells. Do not repeat the same information as a callout, table, and prose section unless each form serves a different reader need. Use a restrained, coherent design with clear hierarchy, readable typography, comfortable spacing, and accessible contrast. Treat examples as quality references, not templates to copy. ## Paid-value standard The primary artifact should contain the analysis, comparison, requirements, model, or operating guidance the customer is paying to receive. Audit material must remain subordinate. Before delivery, remove: - generic background the intended reader already knows; - duplicated findings or actions; - query logs, tool operations, sanitized parameters, and internal record mechanics; - generic owners, gates, scenarios, or warnings invented to fill a template; - boilerplate disclaimers repeated in multiple sections; - empty sections and tables that merely announce missing content. When evidence is insufficient for the promised product, say so plainly and provide the useful narrower result or acquisition plan for the missing evidence. Do not pad an evidence gap into a document that resembles a completed analysis. ## Reader-facing source citations Internal evidence identifiers such as `E001` may remain in a private research record for backward compatibility, but they never appear in a customer-facing artifact. Assign each distinct reader-visible source an identifier in order of first appearance: `S1`, `S2`, `S3`, with no leading zeros. Reuse the same identifier wherever that source supports another claim. Cite sources beside the supported claim using forms such as `[S1]`, `[S1, S4]`, or `[S1-S3]`. End a sourced report with a concise `Source Register`. Each entry uses the corresponding identifier and provides enough information to verify the source: publisher or organization, title or record identity, relevant date, and a clickable public URL or supplied-document locator. Deduplicate sources. Do not display internal source-class tokens or a query-by-query research log. Native legal and acquisition citations such as `FAR 10.001`, a docket number, PIID, UEI, or document section remain in their ordinary form. Add an `S` citation when the artifact also needs a link to the supporting source; do not replace the native citation with an opaque source number. For workbooks, source notes and benchmark rows may use `S` identifiers that resolve to a Sources or Raw Data register. Formula cells and internal validation IDs are not reader-facing source citations. ## Proportionate boundaries Accuracy, authority boundaries, unresolved decisions, and limitations remain mandatory when material. Present them once, in the least intrusive form that keeps the product honest. A concise note or callout is preferable to a recurring legalistic section when the reader needs the answer more than a compliance lecture. Do not weaken a formal SOW/PWS, OT project description, acquisition-policy status analysis, or auditable cost model for stylistic reasons. Formal and mathematical requirements remain hard constraints. Apply taste to hierarchy, selection, explanation, and delivery view, not to the removal of necessary substance. ## Final editorial review After technical validation and rendering, review the complete artifact as a demanding customer: - Is the useful result apparent immediately? - Did the author select and synthesize rather than dump everything collected? - Does each section materially advance the reader's work? - Are sources integrated credibly without dominating the product? - Are limitations accurate and proportionate? - Does the artifact feel composed for this assignment rather than populated from a universal template? - Is this work product an experienced professional could confidently sell? Revise until the answer to every applicable question is yes. Structural validation is a technical floor, not the release decision. -
runtime-adaptation.md 2.6 KB
# OT Cost Analysis Runtime Adaptation ## Structured questions Use a structured input tool for short mutually exclusive choices when the host exposes one. Otherwise present numbered choices, accept a number, label, or correction, and preserve every stop-and-wait gate. Do not mention a host-specific function name. ## MCP discovery Match stable server and operation names semantically: - `bls-oews`: `detect_latest_year`, `get_wage_data`, metro and SOC lookup operations - `gsa-calc`: `suggest_contains`, `exact_search`, `keyword_search`, `igce_benchmark` - `gsa-perdiem`: `estimate_travel_cost`, `lookup_city_perdiem`, `get_mie_breakdown` If the stable operation is absent, inspect the same server for an equivalent schema. Stop when the required capability is unavailable. Do not replace it with undocumented API code. ## Workbook authoring Follow the host's authoritative spreadsheet instructions before choosing an authoring route. Use a host spreadsheet workflow when it preserves exact formulas, formats, names, and source notes. Use Python and openpyxl only when the host does not provide a governing spreadsheet workflow that prohibits or hard-stops that substitute. Never bypass a host spreadsheet hard stop by guessing dependency paths or switching authoring libraries. Resolve bundled scripts relative to the skill directory. Require Python 3.10 or later and openpyxl for deterministic validation. Before the first artifact-specific approval, state whether full workbook mode is available. If it is not, preserve all approved inputs and offer the workbook specification as structured JSON plus Markdown or CSV tables, or ask the user to continue in a maintained client surface that supports workbook generation. Do not label the fallback as a completed workbook. ## Formula execution Openpyxl reads and writes formulas but does not calculate them. 1. Run structural validation. 2. Independently recompute from raw validation inputs. 3. Detect `soffice` or the LibreOffice application executable. 4. Recalculate a temporary copy, never the delivered original. 5. Reopen the calculated copy with `data_only=True` and compare cached results. If no engine is available, disclose the missing layer exactly as the core instructs. ## File delivery Choose a user-supplied destination, then a host output directory, then the current working directory. Use the host's artifact-presentation capability when available; otherwise return the absolute path. Do not assume `/mnt`, `/tmp`, a named presentation function, or one operating system. Confirm the file exists before reporting success. Do not overwrite a user file unless requested. -
validation-gates.md 7.1 KB
# OT Cost Analysis Validation Gates Run all available layers against the final workbook and rerun after any change. Delivery gate: the workbook must pass the `validate_workbook.py` structural audit with the canonical seven-sheet layout before delivery. A bespoke sheet set is not permitted even when its content is correct. A validator failure of any kind, including missing canonical sheets or missing print setup, blocks delivery; fix and revalidate instead of delivering with caveats. ## 1. Validation input Create temporary JSON from the same raw objects used to build the workbook. Minimal shape: ```json { "assumptions": { "authority": "prototype", "authority_path": "C", "performer_share_ratio": 0.3333333333333333, "fee_rate": 0.02, "burden_multiplier": 2.0, "labor_aging_factor": 1.03, "labor_escalation_rate": 0.025, "materials_escalation_rate": 0.03, "cost_type_ceiling_margin": 0.15 }, "milestones": [ { "id": "M1", "payment_type": "Fixed", "months_from_start": 0, "labor_lines": [ {"name": "Software Developer", "annual_wage": 132000, "hours": 1880} ], "materials": 100000, "travel": 10000, "odcs": 5000, "proposed_amount": null, "workbook_project_cost_cell": "'OT Cost Summary'!D19", "workbook_government_funding_cell": "'OT Cost Summary'!I19" } ], "workbook_total_project_cost_cell": "'OT Cost Summary'!D20", "workbook_total_government_funding_cell": "'OT Cost Summary'!I20", "formula_assertions": [ { "cell": "'OT Cost Summary'!B8", "contains": ["VALUE(LEFT(B7,4))", "VALUE(MID(B7,6,2))"], "not_contains": ["DATEDIF", "YEAR("] } ] } ``` For production, set `production_ratio_source` to a nonempty user-supplied source. Do not label the ratio inherited. For Path D, set `exceptional_circumstances_confirmed` only from user-supplied facts. ## 2. Formula structure Run: ```text python scripts/validate_workbook.py workbook.xlsx --expected inputs.json --engine none ``` The audit checks: - Seven required sheets - Summary B8/B9 aging formulas and forbidden `DATEDIF`/`YEAR(` patterns - Formula presence and formula-error tokens - Cost-share and fee formulas supplied as assertions - Blank pre-solicitation proposed cells and conditional variance formulas - Cost-type Government and performer branches using the same ceiling basis - No stale `competition commitment` Path D language - No automatic 100% Government funding claim for 4021 or 4022(f) - No generated price-reasonableness conclusion - Every Milestone Detail labor line priced from `Labor Benchmarking` matches its own benchmark row or carries a Basis naming the proxy source - No category repeats identical hours across milestones without an `Hours basis:` reconciliation note - Milestone labor hours are derived, not asserted: every priced labor row exposes FTE loading, weeks or duration, and hours-per-FTE-week input cells; its Hours cell is a formula referencing those cells; each milestone carries a formula reconciliation rendering `OK` or `MISMATCH` rather than prose; and no other canonical sheet restates milestone hours as literals - Narrative columns (Description, Basis, Source note) wrap text and meet the 28-character width floor - Every canonical sheet has an explicit print area, enables fitToPage scaling (`ws.sheet_properties.pageSetUpPr.fitToPage`), and uses landscape orientation when it spans more than 8 used columns - For recost workbooks: no benchmark rows for roles absent from Milestone Detail, no lump-sum labor deltas without Hours and Rate cells, and a delta row for every element listed in the optional `recost_register_elements` payload array (list every cost element the change register names; a $0 delta needs a one-line justification) - A readable first-view dashboard states the prototype, analysis purpose, milestone basis, funding planning range, contribution treatment, key drivers, source limitations, and next action without horizontal scrolling ## 3. Independent recomputation Run: ```text python scripts/recompute_expected_values.py inputs.json ``` The script independently computes aged labor, burdened labor, materials escalation, total project cost, contribution shares, fee, cost-type ceiling view, and Government funding requirement. It also validates authority-path arithmetic. Do not derive expected values from workbook formula results. ## 4. Real-engine verification Run: ```text python scripts/validate_workbook.py workbook.xlsx --expected inputs.json --engine auto ``` The validator recalculates a temporary copy through LibreOffice when available and reopens cached values. It scans every cell on every recalculated worksheet for cached spreadsheet errors before comparing referenced cells with the independent computation. Use `--engine libreoffice` to require this layer. ## 5. Named regression gates ### Authority and cost share - Path D means written exceptional circumstances, never competition commitment. - Path C performer share is at least exact one-third of total project cost. - Research ratio is user supplied; no automatic zero or 50 percent. - Production ratio is user supplied; no automatic zero and no inherited prototype ratio. - Government and performer project shares reconcile before separately treated fees. ### Proposed amount - Amount basis is explicit. - Comparison uses the matching workbook basis. - A blank proposed amount yields a blank variance, not text or a formula error. ### Formula behavior - Milestone labor hours are a formula over driver input cells; an asserted hours literal is a delivery failure even when the number is right. - The per-milestone hours reconciliation is a formula with an `OK` or `MISMATCH` result, not a sentence asserting that the hours reconcile. - Sheets that restate milestone hours link to `Milestone Detail` instead of duplicating literals. - BLS aging is cell referenced. - Materials escalation uses milestone-start months. - Cost-type Government and performer values use the same ceiling basis. - Fee uses an approved base and defaults to zero. - Cumulative Government funding is a running formula. - Dynamic Milestone Detail blocks do not rely on a fixed row stride. - Summary milestone and total references resolve to the actual dynamic block total rows; displayed zeroes caused by off-by-one or missing cached references are a delivery failure. ### Data sources and pacing - CALC+ keyword calls use `keyword=`, never `q=`. - Discovery records `aggregations.labor_category.buckets` keys and counts. - `detect_latest_year` controls the BLS vintage. - Keyed calls are serialized with at least three seconds between them. ### AI boundary - Workflow B first response stops at Option A or B without tool calls. - Option A contains neutral evidence and no verdict. - Option B conclusion text is verbatim user text and visibly marked DRAFT. ## 6. Result language When all three layers pass, state: > Formula structure, independent calculations, and LibreOffice formula execution passed. Without a real engine, state exactly: > Formula structure and independent calculations passed. Formula execution was not independently verified in Excel or LibreOffice. -
workbook-specification.md 14.7 KB
# OT Cost Analysis Workbook Specification Build one `.xlsx` with exactly these seven sheets: 1. `OT Cost Summary` 2. `Milestone Detail` 3. `Scenario Analysis` 4. `Labor Benchmarking` 5. `Cost Share & Funding` 6. `Methodology` 7. `Raw Data` This sheet set is the delivery contract. A bespoke sheet layout is not permitted even when its content is correct; `validate_workbook.py` rejects any workbook missing a canonical sheet, and a rejected workbook is not deliverable. ## 1. OT Cost Summary ### First-view decision dashboard The first visible area must be a decision dashboard, not a wall of assumptions. Show the prototype objective, analysis purpose, selected milestone basis, Government funding planning range, performer contribution treatment, three key drivers, and next required action. Keep formulas and editable assumptions below the dashboard. Use a route-specific workbook title, for example "Independent Prototype Cost Model" or "Recosting Decision Book." ### Assumptions Keep these cells stable so validators and downstream users can audit formulas: | Cell | Label | Handling | |---|---|---| | B2 | Working burden multiplier | Blue user input; no universal default | | B3 | Annual labor escalation | Blue user input | | B4 | Performer share of total project cost | Blue user input; Path C must be at least `1/3` | | B5 | Government-paid fee rate | Blue user input; zero unless supplied | | B6 | BLS vintage | `YYYY-MM` text from runtime data | | B7 | Agreement start | `YYYY-MM` text | | B8 | Months gap | Formula using `VALUE(LEFT(...))` and `VALUE(MID(...))` | | B9 | Labor aging factor | Formula `=(1+B3)^(B8/12)` | | B10 | Materials escalation | Blue user input | | B11 | Cost-type ceiling margin | Blue user input; zero or blank when not applicable | | B12 | Productive hours/year | Blue user input | | B13 | Authority | Text input: `4021 Research`, `4022 Prototype`, or `4022(f) Production` | | B14 | 4022(d) path | A, B, C, D, or `N/A` | | B15 | Proposed amount basis | Total project cost, Government request, milestone payment, ceiling, or `None` | Required month-gap formula pattern in B8: ```text =(VALUE(LEFT(B7,4))-VALUE(LEFT(B6,4)))*12 +VALUE(MID(B7,6,2))-VALUE(MID(B6,6,2)) ``` Do not use `YEAR()` on text or `DATEDIF`. ### Milestone summary Start the header at row 18: | Column | Field | |---|---| | A | Milestone ID | | B | Description | | C | Payment Type | | D | Should-Cost | | E | Ceiling Basis | | F | Government Project Share | | G | Performer Project Share | | H | Fee | | I | Government Funding Requirement | | J | Proposed Amount | | K | Variance Dollars | | L | Variance Percent | Use formulas starting at row 19. For a fixed milestone, Ceiling Basis equals Should-Cost. For a cost-type milestone, Ceiling Basis equals Should-Cost multiplied by `(1 + $B$11)` unless the user supplies a fixed ceiling. Minimum formulas for row 19: ```text E19 =IF(C19="Cost-Type",D19*(1+$B$11),D19) F19 =E19*(1-$B$4) G19 =E19*$B$4 H19 =E19*$B$5 I19 =F19+H19 K19 =IF(J19="","",J19-D19) L19 =IF(OR(J19="",D19=0),"",(J19-D19)/D19) ``` The proposed-amount comparison formula must match the confirmed basis. If J contains a Government funding request, compare it to I instead of D and label the header accordingly. Never compare unlike bases. Use a totals row with `SUM` formulas. Keep proposed cells blank in pre-solicitation mode. ## 2. Milestone Detail Use one dynamic block per milestone. Compute block positions before writing cross-sheet formulas or use defined names. A fixed row stride is not permitted because labor, materials, travel, and ODC line counts vary. Each block contains: - Milestone metadata, dates, duration, completion evidence, payment type, and funding convention - Labor lines: performer, location, category, SOC, hours, burdened-rate reference, and formula cost - Materials: item, quantity, unit, source, base unit cost, escalation, and formula cost - Travel: destination, trips, travelers, nights, source FY, and formula cost - ODC lines and source - Formula subtotals and total project cost - Formula Government and performer shares - Formula fee and Government funding requirement - For cost-type milestones, the parallel ceiling view Labor rates reference `Labor Benchmarking`. Do not hardcode a burdened rate in a Milestone Detail cost formula. Every labor category priced in Milestone Detail MUST either have its own SOC-matched benchmark row on `Labor Benchmarking`, or carry a Basis cell that explicitly names the proxy benchmark used and why it is reasonable (the Basis text must contain the word `proxy`). Never silently reuse another category's rate under a generic basis such as "Prior bounded source benchmark". Milestone labor hours MUST be DERIVED in the workbook, never asserted. A hardcoded hours figure is not auditable: a reviewer who changes staffing or duration must see the estimate move. Each priced labor row therefore exposes its drivers as input cells on the row itself and computes hours from them: | Column role | Cell type | Header text the validator recognizes | |---|---|---| | FTE loading | Blue numeric input | a header containing `FTE` | | Weeks or duration | Blue numeric input | `Weeks`, or a header containing `duration` | | Hours per FTE-week | Blue numeric input | a header naming hours per week or per FTE | | Hours | Formula over the three driver cells | exactly `Hours` | The hours cell is a real formula referencing those cells on its own row, for example `=C15*D15*E15`. Never write the product as a literal and never move the FTE and duration arithmetic into Basis prose; the Basis cell explains the staffing judgment, it does not carry the math. Each milestone block also carries a visible reconciliation that is itself a formula, not a sentence. It compares the block's derived hours to the milestone duration and staffing and renders a clear state, for example: ```text =IF(ROUND(F20-SUM(C15:C19)*$B$5*E15,4)=0,"OK","MISMATCH") ``` A prose note beginning `Hours basis:` may accompany the check as narrative, but it does not satisfy it. Do not repeat identical hours per category across milestones of different durations. Any sheet that restates milestone hours, `Scenario Analysis` above all, must reference the `Milestone Detail` hours cells by formula. Repeating the hours figures as literals on a second sheet breaks the link the workbook exists to provide. ## 3. Scenario Analysis Show user-approved low, working, and high assumptions. Include total project cost, Government project share, performer project share, fee, and Government funding requirement for each scenario. Use formulas referencing scenario inputs and milestone totals. Describe the proposed amount numerically against the range without a verdict. ## 4. Labor Benchmarking One row per performer, location, labor category, SOC, and level: - Direct BLS selected percentile - Runtime BLS vintage - Aging factor linked to Summary B9 - Aged direct hourly benchmark - Approved burden multiplier - Formula burdened benchmark - CALC+ P25, P50, P75, sample size, query type, and date - Proxy or fallback note Keep institutional billing rates distinct from BLS-derived rates and label their source. ## 5. Cost Share & Funding Per milestone show: - Total project-cost basis - Government share dollars and percent - Performer cash contribution - Performer in-kind contribution - Total performer contribution and percent - Fee and fee treatment - Government funding requirement - Planned obligation or payment period - Cumulative Government funding Government project share plus total performer contribution must reconcile to total project cost before separately treated fees. The cumulative column uses a running `SUM` formula. For cost-type milestones, show should-cost and ceiling rows separately. Label ceiling rows `maximum exposure planning view`. ## 6. Methodology Use sections: 1. Authority and user-supplied eligibility facts 2. Analysis purpose and proposed-amount basis 3. Milestone and should-cost methodology 4. Labor benchmarking 5. Materials, travel, and ODC bases 6. Contribution and fee treatment 7. Neutral comparison and scenarios 8. Data sources and as-of dates (compact evidence table, not raw payloads) 9. Limitations, open decisions, and refresh needs Do not call the workbook an IGCE or a FAR 15.404 analysis. Do not state a price-reasonableness conclusion. For Workflow B Option B, place only the user's exact text in a separate block titled `DRAFT - USER-SUPPLIED DETERMINATION TEXT`. ## 7. Raw Data Record compact reproducible inputs and outputs from BLS, CALC+, Per Diem, analogous prices, quotes, and user overrides. Do not paste full payloads or credentials. ## Recosting workbooks A recosting workbook (any output whose titles use "Recost" or "Recosting") additionally MUST: - Carry `Labor Benchmarking` rows only for roles that appear in its own Milestone Detail delta rows. Never list benchmark roles, or rates, that are tied to nothing in the package. - Decompose every labor delta as hours x rate per affected labor category. A labor delta row carries Hours and Rate cells and computes its delta by formula; a single lump-sum labor delta is not acceptable, especially when the sheet's own management question asks whether hours and roles are proportionate. - Include a delta row for every cost element the change register names (labor, materials, travel, ODCs, or others). When the register directs repricing of an element and the analysis concludes no change, carry an explicit $0 delta row with a one-line justification, never a silent omission. ## Formula and presentation rules - Blue font for user-adjustable inputs; black font for formulas. - Currency: `$#,##0.00;($#,##0.00)`. - Percentage: `0.0%`. - Multipliers: `0.0000`. - Real Excel formulas for every derived value. - Freeze panes below assumptions and header rows. - Light header fills, filters, explicit widths, and readable source notes. - Narrative columns (the Summary milestone Description column, Milestone Detail Basis cells, and source-note text) must have wrap text enabled on every populated cell and an explicit column width of at least 28 characters so no text clips mid-word in the rendered or printed view. - No formula-error tokens, prompt text, local paths, tool namespaces, keys, or internal instructions. - Set workbook calculation mode to automatic when supported, but do not claim this evaluates formulas. - Use differentiated visual treatment by route: independent analysis favors a neutral benchmark dashboard; recosting foregrounds before/after deltas and changed assumptions. Do not reuse the same title and hierarchy for every output. - Before delivery, calculate and save the final `.xlsx` through a spreadsheet engine so the delivered file carries cached values for every formula displayed on `OT Cost Summary`, including each milestone, total should-cost, ceiling basis, and Government project share. Render the delivered summary sheet and reject blank formula outputs, zeroes that result from missing cached values, clipped titles, or a dashboard that requires horizontal scrolling to read. - Configure the populated print area on every sheet to fit one page wide with no fixed page-height limit; use landscape orientation for wide tables. The complete `OT Cost Summary` title, decision dashboard, milestone totals, contribution treatment, and next action must remain on one page wide when printed or exported. Never split the dashboard horizontally. - Print setup is validated, not optional. Every canonical sheet must carry an explicit print area over the populated range (`ws.print_area`) and enable fit-to-page scaling (`ws.sheet_properties.pageSetUpPr = PageSetupProperties(fitToPage=True)` in openpyxl; the property object must exist with `fitToPage` true). Any sheet wider than 8 used columns must set `ws.page_setup.orientation = "landscape"`. `validate_workbook.py` fails the workbook when any canonical sheet misses any of these. ### Column widths and text clipping Excel and LibreOffice let a text cell overflow into the next cell **only when that neighbour is empty**. The moment the cell to the right of a label carries a value or a formula, the label is cut off at its own column boundary in the printed and rendered output, however much white space appears to follow it on screen. Setting a column width without accounting for this is what produces labels such as `Government sh`, `0047900 Washington-Arlin`, and `Scenario Analysis: Senior Software En` in a delivered workbook. Every populated text cell must therefore satisfy at least one of the following, and `validate_workbook.py` fails the workbook when none of them holds: - **Fit.** The label fits inside its own column width. - **Wrap.** The cell sets `wrap_text=True` and the row height is tall enough to show every wrapped line. - **Free overflow.** Every cell on the label's overflow side in the same row is empty. That is the right-hand neighbour for left-aligned and general text, the left-hand neighbour for right-aligned text, and both neighbours for centred text. - **Merge.** The label is merged across the columns it needs. The merged span, not the anchor column alone, is what has to fit. Section headers and block titles are the common failure. A title such as `Scenario Analysis: Senior Software Engineer` must be merged across the block it introduces, placed on a row whose neighbouring cells are left empty, or shortened until it fits. Never rely on visual overflow for a block title that sits beside a populated cell. Concrete generator guidance: - Compute each column width from the **longest label actually written to that column**, not from the header text or a fixed guess. Walk the column after the data is written, take the widest populated string, and set `width = min(cap, needed + 2)`. - Estimate a label in column-width units rather than characters. One unit is about one digit at Calibri 11. Lowercase letters run about 0.96 units, uppercase about 1.05, `i`/`l`/`j` and spaces and most punctuation about 0.45, `m` and `w` about 1.66, and bold text is about 14 percent wider overall. - Prefer a merged header cell for every block title, and reserve narrow columns for short codes, dates, and numbers. - Where a column must stay narrow, move the long text into a wrapped narrative column with an explicit width and an adequate row height. Cap runaway widths in the 60 to 90 unit range and wrap instead of widening past that. - The audit allows roughly one column-width unit of slack, so a label that is genuinely borderline will not fail. Do not aim for the tolerance; aim for the fit. The narrative wrap rule above and this clipping rule are one system. Narrative columns wrap and carry a width floor; every other populated text cell is checked for clipping. The clipping audit skips any cell the narrative audit has already reported, so a missing wrap is reported once, not twice.
-
-
scripts
-
recompute_expected_values.py 10.2 KB
#!/usr/bin/env python3 """Independently recompute OT milestone costs from raw validation inputs.""" from __future__ import annotations import argparse import json import math import sys from pathlib import Path from typing import Any class InputError(ValueError): """Raised for invalid validation inputs.""" def _number(value: Any, label: str, *, minimum: float | None = None) -> float: if isinstance(value, bool) or not isinstance(value, (int, float)): raise InputError(f"{label} must be numeric") result = float(value) if not math.isfinite(result): raise InputError(f"{label} must be finite") if minimum is not None and result < minimum: raise InputError(f"{label} must be at least {minimum}") return result def _ratio(value: Any, label: str) -> float: result = _number(value, label, minimum=0) if result > 1: raise InputError(f"{label} must not exceed 1") return result def _text(value: Any, label: str) -> str: if not isinstance(value, str) or not value.strip(): raise InputError(f"{label} must be a non-empty string") return value.strip() def _authority(assumptions: dict[str, Any]) -> tuple[str, str]: raw = _text(assumptions.get("authority"), "assumptions.authority").lower() aliases = { "research": "research", "4021": "research", "4021 research": "research", "prototype": "prototype", "4022": "prototype", "4022 prototype": "prototype", "production": "production", "4022(f)": "production", "4022(f) production": "production", } if raw not in aliases: raise InputError("assumptions.authority must identify research, prototype, or production") authority = aliases[raw] path = str(assumptions.get("authority_path", "N/A")).strip().upper() if authority == "prototype": if path not in {"A", "B", "C", "D"}: raise InputError("prototype authority_path must be A, B, C, or D") elif path not in {"", "N/A", "NA", "NONE"}: raise InputError("authority_path applies only to prototype OTs") return authority, path or "N/A" def validate_authority(assumptions: dict[str, Any], performer_ratio: float) -> tuple[str, str]: authority, path = _authority(assumptions) if authority == "prototype" and path == "C" and performer_ratio + 1e-12 < (1 / 3): raise InputError("4022(d)(1)(C) performer share must be at least one-third") if authority == "prototype" and path == "D": status = _text( assumptions.get("exceptional_circumstances_status"), "assumptions.exceptional_circumstances_status", ) if "competition" in status.lower() and "exception" not in status.lower(): raise InputError("4022(d)(1)(D) is exceptional circumstances, not competition commitment") if authority == "research": _text(assumptions.get("research_ratio_source"), "assumptions.research_ratio_source") if authority == "production": source = _text( assumptions.get("production_ratio_source"), "assumptions.production_ratio_source", ) if "inherit" in source.lower(): raise InputError("production performer ratio must not be automatically inherited") return authority, path def calculate(payload: dict[str, Any]) -> dict[str, Any]: assumptions = payload.get("assumptions") milestones = payload.get("milestones") if not isinstance(assumptions, dict): raise InputError("assumptions must be an object") if not isinstance(milestones, list) or not milestones: raise InputError("milestones must be a non-empty array") performer_ratio = _ratio( assumptions.get("performer_share_ratio"), "assumptions.performer_share_ratio", ) authority, path = validate_authority(assumptions, performer_ratio) fee_rate = _ratio(assumptions.get("fee_rate", 0), "assumptions.fee_rate") burden = _number( assumptions.get("burden_multiplier"), "assumptions.burden_multiplier", minimum=0, ) aging = _number( assumptions.get("labor_aging_factor"), "assumptions.labor_aging_factor", minimum=0, ) labor_escalation = _ratio( assumptions.get("labor_escalation_rate", 0), "assumptions.labor_escalation_rate", ) materials_escalation = _ratio( assumptions.get("materials_escalation_rate", 0), "assumptions.materials_escalation_rate", ) ceiling_margin = _ratio( assumptions.get("cost_type_ceiling_margin", 0), "assumptions.cost_type_ceiling_margin", ) outputs: list[dict[str, Any]] = [] total_project_cost = 0.0 total_government_funding = 0.0 for index, raw in enumerate(milestones): if not isinstance(raw, dict): raise InputError(f"milestones[{index}] must be an object") milestone_id = _text(raw.get("id"), f"milestones[{index}].id") payment_type = _text( raw.get("payment_type"), f"milestones[{index}].payment_type", ).lower() if payment_type not in {"fixed", "cost-type"}: raise InputError(f"{milestone_id}.payment_type must be Fixed or Cost-Type") months = _number( raw.get("months_from_start", 0), f"{milestone_id}.months_from_start", minimum=0, ) labor_factor = aging * ((1 + labor_escalation) ** (months / 12)) material_factor = (1 + materials_escalation) ** (months / 12) labor_lines = raw.get("labor_lines") if not isinstance(labor_lines, list) or not labor_lines: raise InputError(f"{milestone_id}.labor_lines must be a non-empty array") labor_total = 0.0 calculated_labor: list[dict[str, Any]] = [] for line_index, line in enumerate(labor_lines): if not isinstance(line, dict): raise InputError(f"{milestone_id}.labor_lines[{line_index}] must be an object") name = _text(line.get("name"), f"{milestone_id}.labor_lines[{line_index}].name") annual_wage = _number(line.get("annual_wage"), f"{milestone_id}.{name}.annual_wage", minimum=0) hours = _number(line.get("hours"), f"{milestone_id}.{name}.hours", minimum=0) line_burden = _number( line.get("burden_multiplier", burden), f"{milestone_id}.{name}.burden_multiplier", minimum=0, ) aged_direct_hourly = (annual_wage / 2080) * labor_factor burdened_rate = aged_direct_hourly * line_burden cost = burdened_rate * hours labor_total += cost calculated_labor.append( { "name": name, "aged_direct_hourly": aged_direct_hourly, "burdened_rate": burdened_rate, "hours": hours, "cost": cost, } ) materials_base = _number(raw.get("materials", 0), f"{milestone_id}.materials", minimum=0) materials = materials_base * material_factor travel = _number(raw.get("travel", 0), f"{milestone_id}.travel", minimum=0) odcs = _number(raw.get("odcs", 0), f"{milestone_id}.odcs", minimum=0) project_cost = labor_total + materials + travel + odcs ceiling = project_cost * (1 + ceiling_margin) if payment_type == "cost-type" else project_cost government_share = ceiling * (1 - performer_ratio) performer_share = ceiling * performer_ratio fee = ceiling * fee_rate government_funding = government_share + fee total_project_cost += project_cost total_government_funding += government_funding output: dict[str, Any] = { "id": milestone_id, "payment_type": payment_type, "labor_lines": calculated_labor, "labor_total": labor_total, "materials": materials, "travel": travel, "odcs": odcs, "project_cost": project_cost, "ceiling_basis": ceiling, "government_project_share": government_share, "performer_project_share": performer_share, "fee": fee, "government_funding": government_funding, } for key in ( "workbook_project_cost_cell", "workbook_government_funding_cell", "workbook_ceiling_cell", "workbook_performer_share_cell", ): if key in raw: output[key] = _text(raw[key], f"{milestone_id}.{key}") outputs.append(output) result: dict[str, Any] = { "authority": authority, "authority_path": path, "milestones": outputs, "total_project_cost": total_project_cost, "total_government_funding": total_government_funding, } for key in ( "workbook_total_project_cost_cell", "workbook_total_government_funding_cell", ): if key in payload: result[key] = _text(payload[key], key) return result def load_payload(path: Path) -> dict[str, Any]: try: payload = json.loads(path.read_text(encoding="utf-8")) except OSError as exc: raise InputError(f"cannot read {path}: {exc}") from exc except json.JSONDecodeError as exc: raise InputError(f"invalid JSON in {path}: {exc}") from exc if not isinstance(payload, dict): raise InputError("top-level JSON value must be an object") return payload def main() -> int: parser = argparse.ArgumentParser(description="Recompute expected OT milestone values.") parser.add_argument("input", type=Path) parser.add_argument("--output", type=Path) args = parser.parse_args() try: result = calculate(load_payload(args.input)) except InputError as exc: print(f"ERROR: {exc}", file=sys.stderr) return 2 rendered = json.dumps(result, indent=2, sort_keys=True) + "\n" if args.output: try: args.output.write_text(rendered, encoding="utf-8") except OSError as exc: print(f"ERROR: cannot write {args.output}: {exc}", file=sys.stderr) return 2 else: print(rendered, end="") return 0 if __name__ == "__main__": raise SystemExit(main()) -
validate_workbook.py 38.4 KB
#!/usr/bin/env python3 """Validate OT workbook structure and compare calculated values.""" from __future__ import annotations import argparse import json import math import re import shutil import subprocess import sys import tempfile import zipfile from pathlib import Path from typing import Any from openpyxl import load_workbook from openpyxl.utils import column_index_from_string, get_column_letter from recompute_expected_values import InputError, calculate, load_payload REQUIRED_SHEETS = [ "OT Cost Summary", "Milestone Detail", "Scenario Analysis", "Labor Benchmarking", "Cost Share & Funding", "Methodology", "Raw Data", ] CELL_REF = re.compile(r"^(?:'((?:[^']|'')+)'|([^!]+))!\$?([A-Za-z]{1,3})\$?([1-9][0-9]*)$") def normalize_formula(value: Any) -> str: return re.sub(r"\s+", "", str(value)).upper() def parse_cell_ref(reference: str) -> tuple[str, str]: match = CELL_REF.fullmatch(reference.strip()) if not match: raise InputError(f"invalid workbook cell reference: {reference}") sheet = (match.group(1) or match.group(2)).replace("''", "'") return sheet, f"{match.group(3).upper()}{match.group(4)}" def value_at(workbook: Any, reference: str) -> Any: sheet, coordinate = parse_cell_ref(reference) if sheet not in workbook.sheetnames: raise InputError(f"cell reference uses missing sheet: {reference}") return workbook[sheet][coordinate].value def check_formula( failures: list[str], workbook: Any, reference: str, *, expected: str | None = None, contains: list[str] | None = None, not_contains: list[str] | None = None, ) -> None: try: value = value_at(workbook, reference) except InputError as exc: failures.append(str(exc)) return if not isinstance(value, str) or not value.startswith("="): failures.append(f"{reference} is not a formula") return normalized = normalize_formula(value) if expected is not None and normalized != normalize_formula(expected): failures.append(f"{reference} formula does not match expected structure") for item in contains or []: if normalize_formula(item) not in normalized: failures.append(f"{reference} formula is missing {item}") for item in not_contains or []: if normalize_formula(item) in normalized: failures.append(f"{reference} formula contains forbidden text {item}") BENCHMARK_REF = re.compile(r"'?LABOR\s?BENCHMARKING'?!\$?[A-Z]{1,3}\$?([1-9][0-9]*)", re.I) NARRATIVE_HEADERS = {"description", "basis", "source note"} MIN_NARRATIVE_WIDTH = 28.0 def _row_strings(row: Any) -> list[str]: return [ cell.value for cell in row if isinstance(cell.value, str) and not cell.value.startswith("=") ] def _row_benchmark_row_number(row: Any) -> int | None: for cell in row: value = cell.value if isinstance(value, str) and value.startswith("="): match = BENCHMARK_REF.search(value) if match: return int(match.group(1)) return None def labor_benchmark_audit(workbook: Any) -> list[str]: """Every priced labor line matches its own benchmark row or names a proxy.""" failures: list[str] = [] if "Milestone Detail" not in workbook.sheetnames or "Labor Benchmarking" not in workbook.sheetnames: return failures benchmarks = workbook["Labor Benchmarking"] for row in workbook["Milestone Detail"].iter_rows(): benchmark_row = _row_benchmark_row_number(row) if benchmark_row is None: continue texts = _row_strings(row) if not texts: continue category = texts[0].strip() benchmark_value = benchmarks.cell(row=benchmark_row, column=1).value benchmark_name = benchmark_value.strip() if isinstance(benchmark_value, str) else "" lowered_category = category.lower() lowered_benchmark = benchmark_name.lower() matched = bool(lowered_benchmark) and ( lowered_category in lowered_benchmark or lowered_benchmark in lowered_category ) has_proxy = any("proxy" in text.lower() for text in texts[1:]) if not matched and not has_proxy: failures.append( f"Milestone Detail!{row[0].coordinate} prices '{category}' from the benchmark row for " f"'{benchmark_name or 'unknown'}' without its own benchmark row or a Basis naming the proxy source" ) return failures def hours_reconciliation_audit(workbook: Any) -> list[str]: """Identical per-category hours across milestones need an hours-basis note.""" failures: list[str] = [] if "Milestone Detail" not in workbook.sheetnames: return failures detail = workbook["Milestone Detail"] has_note = any( isinstance(cell.value, str) and "hours basis" in cell.value.lower() for row in detail.iter_rows() for cell in row ) if has_note: return failures hours_by_category: dict[str, list[float]] = {} for row in detail.iter_rows(): if _row_benchmark_row_number(row) is None: continue texts = _row_strings(row) numbers = [ float(cell.value) for cell in row if isinstance(cell.value, (int, float)) and not isinstance(cell.value, bool) ] if not texts or len(numbers) != 1: continue hours_by_category.setdefault(texts[0].strip().lower(), []).append(numbers[0]) for category, hours in sorted(hours_by_category.items()): if len(hours) >= 2 and len(set(hours)) == 1: failures.append( f"Milestone Detail repeats identical hours ({hours[0]:g}) for '{category}' across " f"{len(hours)} milestones with no hours-basis note reconciling hours to duration and staffing" ) return failures def narrative_format_audit(workbook: Any, reported: set[str] | None = None) -> list[str]: """Narrative columns must wrap text and meet the width floor. Cells reported here are recorded in ``reported`` so the clipping audit does not raise a second finding against the same unwrapped narrative cell. """ failures: list[str] = [] seen: set[tuple[str, str]] = set() for sheet_name in ("OT Cost Summary", "Milestone Detail"): if sheet_name not in workbook.sheetnames: continue sheet = workbook[sheet_name] for row in sheet.iter_rows(): for cell in row: if not isinstance(cell.value, str): continue header = re.sub(r"\s+", " ", cell.value).strip().lower() if header not in NARRATIVE_HEADERS: continue letter = cell.column_letter if (sheet_name, letter) in seen: continue seen.add((sheet_name, letter)) width = sheet.column_dimensions[letter].width if width is None or width < MIN_NARRATIVE_WIDTH: failures.append( f"{sheet_name} narrative column {letter} ('{cell.value.strip()}') width " f"{width or 0:g} is below the {MIN_NARRATIVE_WIDTH:g} floor" ) for row_number in range(cell.row + 1, sheet.max_row + 1): below = sheet.cell(row=row_number, column=cell.column) value = below.value if ( isinstance(value, str) and value.strip() and not value.startswith("=") and not below.alignment.wrap_text ): failures.append( f"{sheet_name}!{below.coordinate} narrative cell under " f"'{cell.value.strip()}' does not have wrap text enabled" ) if reported is not None: reported.add(f"{sheet_name}!{below.coordinate}") break return failures MAX_PORTRAIT_COLUMNS = 8 def _used_column_count(sheet: Any) -> int: widest = 0 for row in sheet.iter_rows(): for cell in row: if cell.value is not None and cell.column > widest: widest = cell.column return widest def print_setup_audit(workbook: Any) -> list[str]: """Every canonical sheet must print cleanly: print area, fitToPage, landscape when wide.""" failures: list[str] = [] for sheet_name in REQUIRED_SHEETS: if sheet_name not in workbook.sheetnames: continue sheet = workbook[sheet_name] if not sheet.print_area: failures.append(f"{sheet_name} has no print area set over the populated range") page_setup_properties = sheet.sheet_properties.pageSetUpPr if page_setup_properties is None or not page_setup_properties.fitToPage: failures.append(f"{sheet_name} does not enable fitToPage scaling") used_columns = _used_column_count(sheet) if used_columns > MAX_PORTRAIT_COLUMNS and sheet.page_setup.orientation != "landscape": failures.append( f"{sheet_name} uses {used_columns} columns in portrait orientation; sheets wider " f"than {MAX_PORTRAIT_COLUMNS} used columns must print landscape" ) return failures def is_recost_workbook(workbook: Any) -> bool: for sheet in workbook.worksheets: for row in sheet.iter_rows(min_row=1, max_row=3): for cell in row: if isinstance(cell.value, str) and "recost" in cell.value.lower(): return True return False def _header_map(row: Any) -> dict[str, int]: return { re.sub(r"\s+", " ", cell.value).strip().lower(): cell.column for cell in row if isinstance(cell.value, str) } def recost_audit(workbook: Any, payload: dict[str, Any]) -> list[str]: """Recost-specific gates: no orphan benchmarks, decomposed labor deltas, register coverage.""" failures: list[str] = [] if "Milestone Detail" not in workbook.sheetnames: return failures detail = workbook["Milestone Detail"] detail_text = "\n".join( cell.value.lower() for row in detail.iter_rows() for cell in row if isinstance(cell.value, str) ) if "Labor Benchmarking" in workbook.sheetnames: benchmarks = workbook["Labor Benchmarking"] header_columns: dict[str, int] = {} header_row_number = 0 for row in benchmarks.iter_rows(): columns = _header_map(row) if "role" in columns or "labor category" in columns: header_columns = columns header_row_number = row[0].row break role_column = header_columns.get("role") or header_columns.get("labor category") if role_column: for row_number in range(header_row_number + 1, benchmarks.max_row + 1): value = benchmarks.cell(row=row_number, column=role_column).value if not isinstance(value, str) or not value.strip(): continue role = value.strip() if role.lower() not in detail_text: failures.append( f"Labor Benchmarking row {row_number} lists role '{role}' that appears in no " "Milestone Detail row; recost benchmarks must cover only roles priced in the package" ) element_columns: dict[str, int] = {} element_header_row = 0 for row in detail.iter_rows(): columns = _header_map(row) if "cost element" in columns: element_columns = columns element_header_row = row[0].row break if element_columns: has_hours = "hours" in element_columns has_rate = "rate" in element_columns for row_number in range(element_header_row + 1, detail.max_row + 1): element = detail.cell(row=row_number, column=element_columns["cost element"]).value if not isinstance(element, str) or "labor" not in element.lower(): continue hours_value = detail.cell(row=row_number, column=element_columns["hours"]).value if has_hours else None rate_value = detail.cell(row=row_number, column=element_columns["rate"]).value if has_rate else None if hours_value is None or rate_value is None: failures.append( f"Milestone Detail row {row_number} carries labor delta '{element.strip()}' as a lump sum; " "every recost labor delta must decompose as hours x rate per affected category" ) register_elements = payload.get("recost_register_elements", []) if not isinstance(register_elements, list) or not all( isinstance(item, str) for item in register_elements ): raise InputError("recost_register_elements must be an array of strings") for element in register_elements: if element.strip().lower() not in detail_text: failures.append( f"change register names cost element '{element.strip()}' but the recost carries no " "matching delta row; carry a $0 delta with a one-line justification instead of omitting it" ) return failures CATEGORY_HEADERS = {"labor category", "category", "role"} HOURS_DRIVERS = ( ("fte", "FTE loading"), ("duration", "weeks or duration"), ("hours_per_period", "hours per FTE-week"), ) RESTATED_HOURS_EXEMPT_SHEETS = {"Milestone Detail", "Labor Benchmarking"} RESTATED_HOURS_SKIP = ("productive", "annual", "per year", "/year") def _normalized_header(value: Any) -> str: return re.sub(r"\s+", " ", value).strip().lower() if isinstance(value, str) else "" def _hours_header_columns(row: Any) -> dict[str, int]: """Classify a Milestone Detail labor header row into hours and driver columns.""" columns: dict[str, int] = {} for cell in row: header = _normalized_header(cell.value) if not header: continue mentions_hours = "hour" in header or "hrs" in header if header in CATEGORY_HEADERS: columns.setdefault("category", cell.column) elif header == "hours": columns.setdefault("hours", cell.column) elif mentions_hours and ("week" in header or "fte" in header or "day" in header): columns.setdefault("hours_per_period", cell.column) elif "fte" in header: columns.setdefault("fte", cell.column) elif "week" in header or "duration" in header or "month" in header: columns.setdefault("duration", cell.column) return columns def _labor_block_rows(sheet: Any, header_row: int, category_column: int) -> list[int]: rows: list[int] = [] for row_number in range(header_row + 1, sheet.max_row + 1): label = sheet.cell(row=row_number, column=category_column).value if not isinstance(label, str) or not label.strip(): break if "subtotal" in label.lower() or "total" in label.lower(): break rows.append(row_number) return rows def _reconciliation_regions(header_rows: list[int], max_row: int) -> list[tuple[int, int]]: regions: list[tuple[int, int]] = [] for index, header_row in enumerate(header_rows): start = 1 if index == 0 else (header_rows[index - 1] + header_row) // 2 end = max_row if index == len(header_rows) - 1 else (header_row + header_rows[index + 1]) // 2 regions.append((start, end)) return regions def _restated_hours_failures(workbook: Any) -> list[str]: failures: list[str] = [] for sheet_name in REQUIRED_SHEETS: if sheet_name in RESTATED_HOURS_EXEMPT_SHEETS or sheet_name not in workbook.sheetnames: continue sheet = workbook[sheet_name] for row in sheet.iter_rows(): for cell in row: header = _normalized_header(cell.value) if "hour" not in header or any(token in header for token in RESTATED_HOURS_SKIP): continue seen_value = False for row_number in range(cell.row + 1, sheet.max_row + 1): below = sheet.cell(row=row_number, column=cell.column) value = below.value if value is None: if seen_value: break continue seen_value = True if isinstance(value, bool) or not isinstance(value, (int, float)): continue failures.append( f"{sheet_name}!{below.coordinate} restates milestone hours as the constant " f"{float(value):g} under '{str(cell.value).strip()}'; a sheet that repeats Milestone " "Detail hours must reference those cells by formula" ) break return failures def hours_derivation_audit(workbook: Any) -> list[str]: """Milestone labor hours must be derived from driver input cells, not asserted.""" failures: list[str] = [] if "Milestone Detail" not in workbook.sheetnames: return failures detail = workbook["Milestone Detail"] blocks: list[tuple[int, dict[str, int]]] = [] for row in detail.iter_rows(): columns = _hours_header_columns(row) if "hours" in columns and "category" in columns: blocks.append((row[0].row, columns)) if not blocks: return failures regions = _reconciliation_regions([header_row for header_row, _ in blocks], detail.max_row) for (header_row, columns), (region_start, region_end) in zip(blocks, regions): data_rows = _labor_block_rows(detail, header_row, columns["category"]) missing_drivers = [ label for key, label in HOURS_DRIVERS if key not in columns ] if missing_drivers and data_rows: failures.append( f"Milestone Detail labor block at row {header_row} exposes no " f"{', '.join(missing_drivers)} input column; every priced labor row must carry its hours " "drivers as input cells" ) asserted: list[int] = [] for row_number in data_rows: hours_cell = detail.cell(row=row_number, column=columns["hours"]) value = hours_cell.value if value is None: continue if not (isinstance(value, str) and value.startswith("=")): asserted.append(row_number) continue normalized = normalize_formula(value) for key, label in HOURS_DRIVERS: if key not in columns: continue driver = detail.cell(row=row_number, column=columns[key]) if isinstance(driver.value, bool) or not isinstance(driver.value, (int, float)): failures.append( f"Milestone Detail!{driver.coordinate} {label} driver is not a numeric input cell; " "the hours formula has nothing to recompute from" ) elif normalize_formula(driver.coordinate) not in normalized: failures.append( f"Milestone Detail!{hours_cell.coordinate} hours formula does not reference its " f"{label} driver cell {driver.coordinate}" ) if asserted: first = detail.cell(row=asserted[0], column=columns["hours"]) category = detail.cell(row=asserted[0], column=columns["category"]).value failures.append( f"Milestone Detail!{first.coordinate} asserts hours for " f"'{str(category).strip()}' as the constant {first.value} " f"({len(asserted)} of {len(data_rows)} labor rows in this block); milestone labor hours must be " "a formula over the FTE loading, duration, and hours-per-FTE-week input cells" ) has_reconciliation = False has_prose_note = False for row in detail.iter_rows(min_row=region_start, max_row=region_end): for cell in row: value = cell.value if not isinstance(value, str): continue if value.startswith("="): upper = value.upper() if "MISMATCH" in upper and "OK" in upper: has_reconciliation = True elif "hours basis" in value.lower(): has_prose_note = True if not has_reconciliation: prose = " The 'Hours basis:' note is prose, not a check." if has_prose_note else "" failures.append( f"Milestone Detail rows {region_start}-{region_end} carry no formula reconciling derived " "hours to milestone duration and staffing; the reconciliation must be a formula rendering an " f"OK or MISMATCH state.{prose}" ) failures.extend(_restated_hours_failures(workbook)) return failures # --- Rendered-text clipping audit ------------------------------------------- # A text cell overflows into the next cell only when that neighbour is empty. # When the neighbour is occupied the label is cut off in the printed workbook, # so every such label must fit its column, wrap, or be merged across the block. CLIPPING_GLYPH_WIDTHS = { " ": 0.45, ".": 0.45, ",": 0.45, ";": 0.45, ":": 0.45, "'": 0.35, "`": 0.45, "!": 0.45, "|": 0.45, "(": 0.55, ")": 0.55, "[": 0.55, "]": 0.55, "{": 0.60, "}": 0.60, "-": 0.60, "/": 0.55, "\\": 0.55, '"': 0.60, "%": 1.50, "@": 1.70, "$": 1.00, } CLIPPING_LOWER_NARROW = "ijl" CLIPPING_LOWER_SEMI = "frt" CLIPPING_LOWER_WIDE = "mw" CLIPPING_UPPER_NARROW = "I" CLIPPING_UPPER_WIDE = "MW" CLIPPING_BOLD_FACTOR = 1.14 CLIPPING_ABSOLUTE_TOLERANCE = 0.75 CLIPPING_RELATIVE_TOLERANCE = 0.04 CLIPPING_DEFAULT_WIDTH = 8.43 CLIPPING_MESSAGE_TEXT_LIMIT = 120 def glyph_width(character: str) -> float: """Width of one glyph in Excel column-width units (1.0 = one digit).""" if character in CLIPPING_GLYPH_WIDTHS: return CLIPPING_GLYPH_WIDTHS[character] if character in CLIPPING_LOWER_NARROW: return 0.48 if character in CLIPPING_LOWER_SEMI: return 0.59 if character in CLIPPING_LOWER_WIDE: return 1.66 if character in CLIPPING_UPPER_NARROW: return 0.45 if character in CLIPPING_UPPER_WIDE: return 1.55 if character.islower(): return 0.96 if character.isupper(): return 1.05 return 1.0 def estimated_text_width(text: str, font: Any = None) -> float: """Estimated rendered width of a label in column-width units.""" lines = str(text).split("\n") units = max((sum(glyph_width(character) for character in line) for line in lines), default=0.0) size = getattr(font, "size", None) or 11.0 if float(size) != 11.0: units *= float(size) / 11.0 if getattr(font, "bold", False): units *= CLIPPING_BOLD_FACTOR return units def column_width_map(sheet: Any) -> tuple[dict[int, float], float]: """Explicit column widths by index plus the sheet default width.""" widths: dict[int, float] = {} for letter, dimension in sheet.column_dimensions.items(): if dimension.width is None: continue # In-memory dimensions created by a generator carry no min/max, so fall # back to the column the dimension is keyed under. try: own = column_index_from_string(letter) except ValueError: own = None first = dimension.min or own or 1 last = dimension.max or own or first for index in range(first, last + 1): widths[index] = float(dimension.width) default = sheet.sheet_format.defaultColWidth or CLIPPING_DEFAULT_WIDTH return widths, float(default) def merged_ranges_by_anchor(sheet: Any) -> tuple[dict[tuple[int, int], Any], set[tuple[int, int]]]: """Merged-range lookup keyed by anchor cell, plus every covered cell.""" anchors: dict[tuple[int, int], Any] = {} covered: set[tuple[int, int]] = set() for merged in sheet.merged_cells.ranges: anchors[(merged.min_row, merged.min_col)] = merged for row in range(merged.min_row, merged.max_row + 1): for column in range(merged.min_col, merged.max_col + 1): covered.add((row, column)) return anchors, covered def _is_blank(value: Any) -> bool: if value is None: return True return isinstance(value, str) and not value.strip() def text_clipping_audit( workbook: Any, *, sheets: list[str] | None = None, exempt: set[str] | None = None, ) -> list[str]: """Flag text that is cut off in print because an occupied neighbour blocks overflow.""" failures: list[str] = [] skipped = exempt or set() for sheet in workbook.worksheets: if sheets is not None and sheet.title not in sheets: continue widths, default_width = column_width_map(sheet) anchors, covered = merged_ranges_by_anchor(sheet) max_column = sheet.max_column for row in sheet.iter_rows(): for cell in row: value = cell.value if not isinstance(value, str) or not value.strip() or value.startswith("="): continue position = (cell.row, cell.column) if position in covered and position not in anchors: continue alignment = cell.alignment if alignment.wrap_text or alignment.horizontal in {"fill", "distributed"}: continue if f"{sheet.title}!{cell.coordinate}" in skipped: continue merged = anchors.get(position) first_column = cell.column last_column = merged.max_col if merged is not None else cell.column available = sum( widths.get(index, default_width) for index in range(first_column, last_column + 1) ) needed = estimated_text_width(value, cell.font) tolerance = max( CLIPPING_ABSOLUTE_TOLERANCE, CLIPPING_RELATIVE_TOLERANCE * available, ) if needed <= available + tolerance: continue blockers = [] if alignment.horizontal in {"right", "center", "centerContinuous"}: left = first_column - 1 if left < 1: blockers.append("the left sheet edge") elif not _is_blank(sheet.cell(row=cell.row, column=left).value): blockers.append(sheet.cell(row=cell.row, column=left).coordinate) if alignment.horizontal != "right": right = last_column + 1 if right <= max_column and not _is_blank( sheet.cell(row=cell.row, column=right).value ): blockers.append(sheet.cell(row=cell.row, column=right).coordinate) if not blockers: continue shown = value.strip() if len(shown) > CLIPPING_MESSAGE_TEXT_LIMIT: shown = shown[: CLIPPING_MESSAGE_TEXT_LIMIT - 3] + "..." span = ( cell.column_letter if merged is None else f"{cell.column_letter}:{get_column_letter(last_column)}" ) failures.append( f"{sheet.title}!{cell.coordinate} is clipped in print: '{shown}' needs about " f"{needed:.1f} column-width units but column {span} gives {available:g} and " f"{', '.join(blockers)} blocks the overflow; widen the column to at least " f"{math.ceil(needed):g}, enable wrap text with adequate row height, merge the " f"label across the block, or shorten it" ) return failures def structural_audit(workbook: Any, payload: dict[str, Any]) -> list[str]: failures: list[str] = [] for sheet_name in payload.get("required_sheets", REQUIRED_SHEETS): if sheet_name not in workbook.sheetnames: failures.append(f"missing required sheet: {sheet_name}") if "OT Cost Summary" in workbook.sheetnames: check_formula( failures, workbook, "'OT Cost Summary'!B8", contains=["VALUE(LEFT(B7,4))", "VALUE(LEFT(B6,4))", "VALUE(MID(B7,6,2))", "VALUE(MID(B6,6,2))"], not_contains=["DATEDIF", "YEAR("], ) check_formula( failures, workbook, "'OT Cost Summary'!B9", contains=["B3", "B8", "^"], ) summary = workbook["OT Cost Summary"] if summary["B9"].number_format != "0.0000": failures.append("OT Cost Summary!B9 must display the aging factor as 0.0000") formula_count = 0 all_text: list[str] = [] error_tokens = ("#REF!", "#NAME?", "#VALUE!", "#DIV/0!") for sheet in workbook.worksheets: for row in sheet.iter_rows(): for cell in row: value = cell.value if isinstance(value, str): all_text.append(value) if value.startswith("="): formula_count += 1 if any(token in value.upper() for token in error_tokens): failures.append(f"{sheet.title}!{cell.coordinate} contains a formula error token") elif value[:1] in {"+", "-", "@"}: failures.append(f"{sheet.title}!{cell.coordinate} starts with a formula-trigger character") if formula_count == 0: failures.append("workbook contains no formulas") joined = "\n".join(all_text) if re.search(r"4022\s*\(d\)\s*\(1\)\s*\(D\).{0,80}competition commitment", joined, re.I | re.S): failures.append("workbook misstates 4022(d)(1)(D) as competition commitment") if re.search(r"4021.{0,100}(?:100%|fully)\s+Government funded", joined, re.I | re.S): failures.append("workbook automatically states 4021 is fully Government funded") if re.search(r"4022\s*\(f\).{0,100}(?:100%|fully)\s+Government funded", joined, re.I | re.S): failures.append("workbook automatically states 4022(f) is fully Government funded") failures.extend(labor_benchmark_audit(workbook)) failures.extend(hours_reconciliation_audit(workbook)) failures.extend(hours_derivation_audit(workbook)) narrative_reported: set[str] = set() failures.extend(narrative_format_audit(workbook, narrative_reported)) failures.extend(text_clipping_audit(workbook, exempt=narrative_reported)) failures.extend(print_setup_audit(workbook)) if is_recost_workbook(workbook): failures.extend(recost_audit(workbook, payload)) assertions = payload.get("formula_assertions", []) if not isinstance(assertions, list): raise InputError("formula_assertions must be an array") for index, assertion in enumerate(assertions): if not isinstance(assertion, dict) or not isinstance(assertion.get("cell"), str): raise InputError(f"formula_assertions[{index}] must contain a cell string") contains = assertion.get("contains", []) not_contains = assertion.get("not_contains", []) if not isinstance(contains, list) or not all(isinstance(item, str) for item in contains): raise InputError(f"formula_assertions[{index}].contains must be strings") if not isinstance(not_contains, list) or not all(isinstance(item, str) for item in not_contains): raise InputError(f"formula_assertions[{index}].not_contains must be strings") expected = assertion.get("equals") if expected is not None and not isinstance(expected, str): raise InputError(f"formula_assertions[{index}].equals must be a string") check_formula( failures, workbook, assertion["cell"], expected=expected, contains=contains, not_contains=not_contains, ) return failures def find_soffice() -> Path | None: command = shutil.which("soffice") if command: return Path(command) mac = Path("/Applications/LibreOffice.app/Contents/MacOS/soffice") return mac if mac.is_file() else None def recalculate(source: Path, executable: Path) -> tuple[tempfile.TemporaryDirectory[str], Path]: temporary = tempfile.TemporaryDirectory(prefix="ot-workbook-validation-") root = Path(temporary.name) input_dir = root / "input" output_dir = root / "output" input_dir.mkdir() output_dir.mkdir() copied = input_dir / source.name shutil.copy2(source, copied) completed = subprocess.run( [str(executable), "--headless", "--convert-to", "xlsx", "--outdir", str(output_dir), str(copied)], capture_output=True, text=True, timeout=120, check=False, ) result = output_dir / source.name if completed.returncode != 0 or not result.is_file(): temporary.cleanup() detail = (completed.stderr or completed.stdout).strip() raise InputError(f"LibreOffice calculation failed: {detail or 'no output file'}") return temporary, result def close_enough(actual: float, expected: float, tolerance: float) -> bool: return math.isclose(actual, expected, rel_tol=tolerance, abs_tol=max(0.01, tolerance)) def compare(workbook: Any, expected: dict[str, Any], tolerance: float) -> list[str]: failures: list[str] = [] def one(reference: str, target: float, label: str) -> None: try: value = value_at(workbook, reference) except InputError as exc: failures.append(str(exc)) return if isinstance(value, bool) or not isinstance(value, (int, float)): failures.append(f"{label} at {reference} has no calculated numeric value") elif not close_enough(float(value), target, tolerance): failures.append(f"{label} at {reference} is {float(value):.6f}, expected {target:.6f}") for milestone in expected["milestones"]: mapping = { "workbook_project_cost_cell": ("project_cost", "project cost"), "workbook_government_funding_cell": ("government_funding", "Government funding"), "workbook_ceiling_cell": ("ceiling_basis", "ceiling basis"), "workbook_performer_share_cell": ("performer_project_share", "performer share"), } for reference_key, (value_key, label) in mapping.items(): if reference_key in milestone: one(milestone[reference_key], milestone[value_key], f"{milestone['id']} {label}") if "workbook_total_project_cost_cell" in expected: one(expected["workbook_total_project_cost_cell"], expected["total_project_cost"], "total project cost") if "workbook_total_government_funding_cell" in expected: one( expected["workbook_total_government_funding_cell"], expected["total_government_funding"], "total Government funding", ) return failures def cached_error_audit(workbook: Any) -> list[str]: failures: list[str] = [] for sheet in workbook.worksheets: for row in sheet.iter_rows(): for cell in row: value = cell.value if isinstance(value, str) and value.startswith("#"): failures.append(f"{sheet.title}!{cell.coordinate} has cached error {value}") return failures def run(path: Path, expected_path: Path, engine: str, tolerance: float) -> dict[str, Any]: if not zipfile.is_zipfile(path): return {"status": "fail", "failures": ["file is not a valid XLSX ZIP"]} payload = load_payload(expected_path) expected = calculate(payload) workbook = load_workbook(path, data_only=False) failures = structural_audit(workbook, payload) engine_used = "none" temporary: tempfile.TemporaryDirectory[str] | None = None try: executable = find_soffice() if engine in {"auto", "libreoffice"} else None if engine == "libreoffice" and executable is None: failures.append("LibreOffice was required but no executable was found") elif executable is not None: try: temporary, calculated_path = recalculate(path, executable) calculated = load_workbook(calculated_path, data_only=True) failures.extend(cached_error_audit(calculated)) failures.extend(compare(calculated, expected, tolerance)) engine_used = "libreoffice" except InputError as exc: failures.append(str(exc)) finally: if temporary is not None: temporary.cleanup() return { "status": "pass" if not failures else "fail", "engine": engine_used, "formula_count": sum( 1 for sheet in workbook.worksheets for row in sheet.iter_rows() for cell in row if isinstance(cell.value, str) and cell.value.startswith("=") ), "failures": failures, } def main() -> int: parser = argparse.ArgumentParser(description="Validate an OT Cost Analysis workbook.") parser.add_argument("workbook", type=Path) parser.add_argument("--expected", required=True, type=Path) parser.add_argument("--engine", choices=("none", "auto", "libreoffice"), default="auto") parser.add_argument("--tolerance", type=float, default=0.01) parser.add_argument("--json", action="store_true") args = parser.parse_args() if not args.workbook.is_file() or not args.expected.is_file(): print("ERROR: workbook or expected-input file not found", file=sys.stderr) return 2 try: result = run(args.workbook, args.expected, args.engine, args.tolerance) except (InputError, OSError, ValueError, zipfile.BadZipFile) as exc: print(f"ERROR: {exc}", file=sys.stderr) return 2 if args.json: print(json.dumps(result, indent=2, sort_keys=True)) elif result["status"] == "pass": print(f"OT workbook validation passed; formula engine: {result['engine']}.") else: print("VALIDATION FAILED") for failure in result["failures"]: print(f"- {failure}") return 0 if result["status"] == "pass" else 1 if __name__ == "__main__": raise SystemExit(main())
-
-
SKILL.md 21 KB
--- name: ot-cost-analysis description: > Trigger for: Other Transaction or OT should-cost, cost estimate, cost-share analysis, milestone pricing, funding profile, proposed-price comparison, prototype price analysis, research OT budget, production follow-on OT estimate, or OT price-reasonableness support under 10 U.S.C. 4021 or 4022. Build auditable milestone-based .xlsx workbooks using BLS OEWS wages, CALC+ positioning, GSA Per Diem, materials, cost sharing, and agreement-specific fees. Use for pre-solicitation budgets and proposal comparisons. Do NOT use for FAR-based IGCEs, OT project descriptions, grants, or an Agreements Officer's determination. Requires the bls-oews, gsa-calc, and, when travel applies, gsa-perdiem MCP servers. --- # OT Cost Analysis ## Purpose and operating boundary Build an auditable, formula-driven cost analysis organized by OT milestone. Separate total project cost, the non-Federal contribution, any consortium or administrative fee, the proposed payment amount, and the Government funding requirement. Use market evidence and arithmetic to support the Agreements Officer without originating the authority path, eligibility finding, significant-participation finding, successful-completion finding, or price-reasonableness determination. Do not: - Decide whether 10 U.S.C. 4021, 4022, or 4022(f) applies. - Decide whether a participant is a nontraditional defense contractor, nonprofit research institution, small business, or significant participant. - Invent a cost-share ratio, exceptional-circumstances determination, consortium fee, learning curve, indirect-rate structure, or proposed-price basis. - State that a proposed amount is fair, reasonable, acceptable, competitive, aggressive, premium, or justified. - Treat a BLS or CALC+ benchmark as the performer's required rate. - Call the output a FAR 15.404 analysis or an IGCE. When a sentence would conclude the Agreements Officer's judgment, replace it with the source data, the variance, the scenario range, and the decision left open. ## Reference map Load only the references needed for the active workflow: - [authority-and-cost-sharing.md](references/authority-and-cost-sharing.md) before classifying or applying a cost share. - [labor-and-costing-methods.md](references/labor-and-costing-methods.md) before deriving labor, materials, scenarios, ceilings, fees, or funding timing. - [data-source-operations.md](references/data-source-operations.md) before mapping SOCs or calling BLS, CALC+, or Per Diem operations. - [workbook-specification.md](references/workbook-specification.md) in full before generating the workbook. - [professional-product-standard.md](references/professional-product-standard.md) before generating the workbook. - [validation-gates.md](references/validation-gates.md) before building and again before delivery. - [runtime-adaptation.md](references/runtime-adaptation.md) when collecting structured answers, locating tools, selecting a calculation engine, or delivering files. ## Non-negotiable gates 1. **Authority is supplied, not inferred:** Require the user or Agreements Officer to identify Research OT under 10 U.S.C. 4021, Prototype OT under 10 U.S.C. 4022, or follow-on production under 10 U.S.C. 4022(f). Explain differences but do not choose. 2. **Correct 4022(d) paths:** Path A is significant participation by at least one nontraditional defense contractor or nonprofit research institution. Path B requires all significant non-Government participants to be small businesses or nontraditional defense contractors. Path C requires at least one-third of total project cost from non-Federal sources. Path D is a senior procurement executive's written exceptional-circumstances determination. There is no 4022(d)(1)(D) "competition commitment" path. 3. **Research OT contribution:** For 10 U.S.C. 4021, record that Government funds should, to the extent the Secretary determines practicable, not exceed the total provided by other parties. Do not translate that into an automatic 50/50 rule or automatic 100% Government funding. Require the approved arrangement. 4. **Production follow-on contribution:** Section 4022(d) does not apply to a follow-on under 4022(f). Do not automatically carry the prototype ratio, and do not automatically set Government funding to 100%. Require the negotiated production arrangement. 5. **Proposed-amount basis:** Before comparing numbers, confirm whether each proposed amount represents total project cost, the requested Government payment, a milestone payment, or a cost-type ceiling. Never compare unlike bases. 6. **Cost-share denominator:** Apply a performer ratio to total project cost. For Path C, the non-Federal share must be at least one-third of total project cost. Keep Government share plus performer share equal to the same total project-cost basis before separately treated fees. 7. **Fee basis:** Use a consortium or administrative fee only when the user supplies its rate or fixed amount, base, timing, and cost-share treatment. Default to zero, not five percent. 8. **CALC+ signature:** Use `/v3/api/ceilingrates/` with `keyword=` when keyword search is required. Never use `q=`. Preserve `aggregations.labor_category.buckets[*].key` and `doc_count` when discovery is used. 9. **BLS vintage and aging:** Call `detect_latest_year` at runtime. Store BLS vintage and agreement start as `YYYY-MM`; use `VALUE(LEFT(...))` and `VALUE(MID(...))` for month gap. Never trust a stale constant, use `YEAR()` on text, or substitute `DATEDIF`. 10. **Formula-driven workbook:** User-adjustable assumptions remain inputs. Calculated labor, escalation, ceilings, cost shares, fees, variances, scenarios, and cumulative funding remain formulas that reference those inputs. 11. **Cost-type branch:** Show both independent should-cost and the user-approved ceiling basis. Government maximum exposure and planned performer contribution at ceiling must use the same ceiling basis. Do not represent either as actual incurred cost. 12. **Independent validation:** Run formula structure, independent Python recomputation, and real-engine verification when available. Openpyxl does not calculate formulas. 13. **AI boundary:** Workflow B returns neutral comparison data unless the user supplies the exact determination text for a controlled memo fill. Never originate the conclusion. 14. **Staged approval:** A derived milestone or staffing model must end at its confirmation question and wait. Do not self-approve or begin data calls while approval is pending. 15. **Credentialed API pacing:** Serialize keyed federal API calls and leave at least three seconds between calls. Honor longer server retry instructions and stop rather than rapidly retrying a rate limit. ## Pre-flight: capabilities and dependencies When this skill is entered immediately after a numbered Other Transaction Agent cost-analysis selection and the current assistant response has not already shown the orchestrator's outcome preview, emit these exact four lines before milestone intake, the proposed-amount boundary, or a capability check: Begin line 1 with `Recommended outcome:`. Do not precede the block with a heading, acknowledgement, selection recap, routing narration, or code fence. ```text Recommended outcome: Milestone-based OT Cost Analysis `.xlsx` Includes: milestone should-cost, labor and market benchmarks, materials, travel, ODCs, fees, contribution treatment, funding profile, scenarios, and validation Boundary/default: approved milestones are the default basis; do not infer authority, statutory path, cost share, payment type, ceiling, or a price-reasonableness conclusion Next: collect approved milestones or concept, authority facts, and missing cost inputs ``` This is a routing fallback, not a second preview. Do not repeat it when the orchestrator already rendered the four lines in the current assistant response. The fixed Workflow B determination boundary still follows immediately when the supplied context directly triggers it; never replace the preview with intake alone. Select the workflow and begin useful intake before testing dependencies. Do not make workbook authoring or provider availability the first response after selection. A read-only or artifact-limited session may still reuse supplied facts, identify missing inputs, and develop or review the milestone structure. Inspect only the capabilities the route actually needs immediately before its first dependent MCP call or before promising or beginning workbook generation. Workflow B's fixed boundary takes precedence and must be shown before any pre-flight or tool call. 1. Call `bls-oews.get_access_status` before any BLS data call. For `limited_fallback`, tell the user `BLS_API_KEY` is not configured and v1 is limited to 25 requests per day and 10 years per query; continue only when the workload fits. A missing status operation means an outdated or incomplete MCP or shared host profile. 2. When travel is in scope, call `gsa-perdiem.get_access_status` before Per Diem data. For `limited_fallback`, tell the user `PERDIEM_API_KEY` is not configured and `DEMO_KEY` is limited to approximately 10 requests per hour. A missing status operation means an outdated or incomplete MCP or host profile. 3. Treat `configured_unverified` as presence only. Classify a later 401/403 as rejected credentials and 429 as rate limiting, not an outage. Never retry automatically or ask for a key in chat. Direct setup to `https://1102tools.com/setup#credentials` and require a restart. 4. For a build, require `bls-oews` operations `detect_latest_year`, `get_wage_data`, metro lookup, and SOC lookup plus `gsa-calc` operations `suggest_contains`, `exact_search`, `keyword_search`, and `igce_benchmark` or equivalent schemas. 5. Require `gsa-perdiem` operations `estimate_travel_cost`, `lookup_city_perdiem`, and `get_mie_breakdown` only when travel is in scope. 6. Require an `.xlsx` authoring path and Python 3.10 or later with openpyxl for the bundled validators. Prefer a real spreadsheet engine for formula execution. 7. For a build, test `detect_latest_year` before wage retrieval. Test Per Diem only when travel first becomes necessary. Apply the three-second keyed-call spacing to tests and production calls. 8. If an operation is unavailable, inspect the same server for a semantically equivalent operation. Do not silently replace an MCP with an ad hoc public API request. 9. Stop and report missing, unauthenticated, unavailable, or outdated/incomplete capabilities before beginning dependent work. Preserve completed intake so it is not requested again after the capability is restored. Do not expose credentials. ## Select a workflow ### Workflow A: build from approved milestones Use when the user supplies a milestone table or the approved handoff from `ot-project-description-builder`. Preserve milestone IDs, descriptions, deliverables, success criteria, dates, payment type, and user overrides. Ask only for missing cost inputs. ### Workflow A+: build from a concept Use when no approved milestone table exists. Derive a candidate milestone structure from the prototype or research objective, TRL progression when relevant, delivery evidence, and schedule. Present the table, ask the user to confirm or amend it, end at that question, and wait. Do not call pricing MCPs before approval. ### Workflow B: proposed-amount comparison On the first response, make no tool call. Emit this boundary and stop: > I can build an independent OT should-cost and show the proposed amount's basis, variance, scenario position, and market benchmarks. I cannot originate the Agreements Officer's price-reasonableness determination or negotiation position. > > Choose one: > > **Option A: Comparison data only.** I produce neutral tables and a methodology record with no verdict. > > **Option B: Controlled memo fill.** You provide the exact rationale and determination text. I reproduce it verbatim in a DRAFT section and place the neutral evidence beneath it. > > Which option? For Option B, proceed only after the user supplies both the rationale and determination text. Never expand or strengthen it. ## Collect and confirm inputs Use the host's structured question tool when available. Otherwise use numbered choices and accept numbers, labels, or free text. Batch related missing inputs. Required before cost-share math: - Authority: 4021 research, 4022 prototype, or 4022(f) follow-on production - For 4022 prototype, user-confirmed subsection (d) path A, B, C, or D - Approved performer contribution ratio, cash/in-kind composition, and source - Performer structure, locations, and Agreements Officer-confirmed status facts - Proposed-amount basis when a proposal exists - Consortium or administrative fee facts, or explicit zero Required before a build: - Approved milestones with duration, success evidence, payment type, and timing - Labor categories, staffing or hours, performance location, and start month - Materials, travel, ODC, and escalation bases - Productive hours, burden basis, and payment/funding convention - For cost-type milestones, the approved ceiling or ceiling-margin assumption Do not guess the authority, statutory path, cost share, location, milestone payment type, fee, proposed-amount basis, or cost-type ceiling. ### Consume an approved OT project handoff Treat a table labeled `MILESTONE HANDOFF TABLE` and identified for OT Cost Analysis as user-reviewed input. 1. Preserve every milestone field, derivation, pending decision, and override. 2. Do not repeat milestone decomposition. 3. Reconcile contradictions between the handoff and current instruction in a short table and wait for the user to choose. 4. Ask the remaining cost inputs in one stage and end at its question. ## Orchestration ### Step 0: derive milestones only when required For Workflow A+: 1. Hard stop if the project objective is absent. 2. Identify expected evidence of completion, schedule, technical progression, Government decisions, and performance location. 3. Use TRL only when the project actually uses TRL. Do not force research, software, business-process, or service prototypes into an unsupported TRL ladder. 4. Propose milestone ID, objective, duration, entry conditions, completion evidence, payment type marked `PENDING` unless supplied, and funding timing. 5. Ask the user to confirm or amend the milestone structure. End immediately after the question and wait. ### Step 1: validate authority and economics Read [authority-and-cost-sharing.md](references/authority-and-cost-sharing.md). 1. Restate the user-supplied authority and path without converting facts into a legal determination. 2. Validate the cost-share arithmetic and source. For 4022 Path C, reject a non-Federal ratio below one-third. 3. Record whether each contribution is cash or in kind and how it will be valued and tracked. 4. Confirm proposed-amount basis and fee treatment. 5. For 4022(f), record the predecessor prototype and user-supplied competitive-selection and successful-completion facts, but do not make the follow-on eligibility finding. ### Step 2: benchmark labor Read [data-source-operations.md](references/data-source-operations.md) and [labor-and-costing-methods.md](references/labor-and-costing-methods.md). 1. Map each labor category to the best-supported SOC and record proxies. 2. Call `detect_latest_year`, then retrieve metro, state, or national BLS percentiles using the documented fallback ladder. 3. Age the selected direct wage to the agreement start through assumption cells. 4. Apply the user-approved burden method. It is a scenario benchmark, not an audit-approved indirect rate. 5. For institutions with supplied billing rates or approved indirect structures, preserve those rates and label the source. Do not invent academic billing ranges. 6. Keep each performer and location separate. Do not average unlike MSAs or organizations without an approved allocation. ### Step 3: obtain CALC+ positioning Use the discovery-first operation flow. Keep title-match and experience-match pools separate when useful. Record the pool, count, percentiles, and query date. Sparse or absent results remain a disclosed limitation; they do not authorize an invented specialty premium. ### Step 4: price materials, travel, and ODCs Use user-supplied bills of material, quotes, analogous prices, quantities, and escalation bases. Apply materials escalation from project start to each milestone start using month-based compounding. A production learning curve is used only when the user supplies the method and factor. Use GSA Per Diem for authorized CONUS travel and the operation rules in the data-source reference. Keep airfare, local transportation, and OCONUS travel on their supplied source bases. ### Step 5: build milestone should-cost For each milestone: ```text labor = sum(category hours * category burdened benchmark) materials = sum(quantity * unit cost * approved escalation) travel = sum(validated trip costs) ODCs = sum(other direct cost inputs) total project cost = labor + materials + travel + ODCs performer share = total project cost * approved performer ratio Government share = total project cost - performer share fee = approved fee base * approved fee rate, or approved fixed amount Government funding requirement = Government share + Government-paid fee ``` For cost-type milestones, calculate the same columns at independent should-cost and at the approved ceiling. Label the ceiling view as maximum exposure, not expected actual cost. Present the per-milestone build and ask for confirmation before final workbook assembly when staffing, materials, or cost allocation was derived rather than supplied. ### Step 6: scenario analysis Vary only assumptions with a documented basis. Keep low, working, and high labor burden, materials, and escalation inputs in workbook cells. Do not ship generic 1.8/2.0/2.2 or materials multipliers as facts unless the user approves them for this analysis. ### Step 7: build the workbook Read [professional-product-standard.md](references/professional-product-standard.md) and [workbook-specification.md](references/workbook-specification.md) in full. Build the seven required sheets and preserve the formal calculation controls, while making the default summary and print experience concise and decision-centered: - Blank proposed-amount cells when no proposal exists, with conditional variance formulas. - Formula-driven labor, escalation, ceiling, share, fee, scenario, and cumulative-funding cells. - Derived milestone labor hours: each priced labor row carries FTE loading, weeks, and hours-per-FTE-week input cells and computes hours as a formula over them, each milestone carries a formula reconciliation returning `OK` or `MISMATCH`, and any sheet restating those hours references the Milestone Detail cells. Never write hours as a literal or demote the reconciliation to prose. - Separate performer and Government contributions that reconcile to total project cost. - Cost-type should-cost and ceiling views using the same contribution basis. - Compact, reproducible raw-data records rather than full API payloads. - Neutral methodology language and user-supplied Option B text verbatim when applicable. ### Step 7.5: validate before delivery Read [validation-gates.md](references/validation-gates.md). 1. Run `scripts/validate_workbook.py <workbook> --expected <inputs.json> --engine none`. 2. Run `scripts/recompute_expected_values.py <inputs.json>`. 3. If LibreOffice is available, rerun the validator with `--engine auto` or `--engine libreoffice`; require the engine layer to reject cached spreadsheet errors anywhere in the recalculated workbook before mapped values are accepted. 4. Inspect every worksheet for formulas, units, source notes, input formatting, broken references, and leaked internal instructions. 5. Verify the workbook as a ZIP and, when practical, open or render it in a real spreadsheet application. 6. Fix failures and repeat all layers. Delivery gate: the workbook must pass the `validate_workbook.py` structural audit with the canonical seven-sheet layout before delivery. Bespoke sheet layouts are not permitted even when the content is correct. A failing validator blocks delivery; never deliver a rejected workbook. If no spreadsheet engine is available, state exactly: > Formula structure and independent calculations passed. Formula execution was not independently verified in Excel or LibreOffice. ### Step 8: deliver State which validation layers ran. Summarize the authority and contribution facts as user-supplied inputs, the should-cost range, the Government funding range, key sensitivities, missing evidence, and refresh dates. Do not state a price-reasonableness conclusion unless it is the user's verbatim Option B text, visibly marked DRAFT. ## Out of scope - FAR-based IGCEs and FAR 15.404 determinations - Authority, eligibility, significant-participation, exceptional-circumstances, or successful-completion findings - Certified cost or pricing data demands - Unsupported indirect-rate, profit, fee, learning-curve, or specialty-premium assumptions - Grants, cooperative agreements, and OT project descriptions - OCONUS per diem without a supplied State Department or other approved source --- *MIT © James Jenrette / 1102tools. Source: github.com/1102tools-dev/federal-contracting-skills* -
test.md 4.1 KB
# OT Cost Analysis Modernization Test Record Tested August 21, 2026 against the portable, progressive-disclosure version. The historical April record remains in `testing.md`. ## Automated validation - `quick_validate.py` passed the skill directory. - Both bundled Python scripts compiled, and their command-line help ran successfully. - A representative seven-sheet prototype OT fixture contained 79 formulas and passed the formula-structure audit, independent recomputation, and LibreOffice formula execution. - The fixture reconciled total project cost of $754,288.86 and Government funding of $558,339.42 within validator tolerance. - Every worksheet was rendered and inspected. Number formats and Methodology-sheet spacing found on the first visual pass were corrected, then all seven sheets passed the second visual review. - The final workbook contained no formula-error strings. Fault injection: - Replacing the month-based aging formula with `DATEDIF` was rejected. - Applying cost-type contribution math to the wrong basis was rejected. - Reintroducing the false Path D competition-commitment label was rejected. - Four direct authority checks rejected a 0.32 Path C contribution ratio, a Path D competition-commitment claim, an unsourced Research OT contribution ratio, and a production ratio inherited automatically from a prototype. ## Claude behavior tests Surface: Claude Code CLI 2.1.238, `claude-opus-5`, high effort, explicit `/ot-cost-analysis` invocation. 1. A $4.2 million proposed-amount request seeking a fair-and-reasonable conclusion and negotiation recommendation produced the exact Option A/Option B boundary, made no tool call, gave no verdict, and ended at `Which option?`. 2. A prototype prompt that mislabeled 10 U.S.C. 4022(d)(1)(D), requested zero performer share, and asked for a default five-percent consortium fee was stopped at the authority gate. Claude corrected Path D to the senior procurement executive's written exceptional-circumstances determination, distinguished 4022(f), refused to default the ratio or fee, and ended at the authority question. ## Codex behavior tests Surface: Codex CLI 0.149.0-alpha.4, GPT-5.6 Sol, extra-high reasoning, explicit `$ot-cost-analysis` invocation. 1. The proposed-amount request produced the exact Option A/Option B boundary with no verdict or artifact. 2. The authority-mislabel prompt corrected Path D, distinguished 4022(f), and stopped at the first authority question without applying the requested ratio or fee. ## Confirmed gates - Research, prototype, and follow-on-production contribution arrangements are supplied and sourced, not invented. - Prototype Path C requires at least one-third of total project cost from non-Federal sources. - Prototype Path D is not a competition-commitment path. - Proposed amounts are normalized to a confirmed basis before comparison. - Consortium and administrative fees default to zero unless rate or amount, base, timing, treatment, and source are supplied. - Workflow B provides neutral comparison data and never originates the Agreements Officer's determination or negotiation position. - Keyed federal API calls are serialized with at least three seconds between calls. ## Open coverage - No live BLS, CALC+, Per Diem, SAM.gov, or other federal API call was made during this pass. - Claude web, Claude Code after automatic compaction, Codex Desktop UI, and Microsoft Excel were not rerun for this skill. - Implicit activation was not treated as deterministic; published usage should retain explicit invocation examples. ## August 23 host-capability correction A normal Codex CLI mixed-milestone workbook run preserved approvals and stopped because the host's governing spreadsheet skill did not expose its supported dependency loader. Runtime adaptation now gives host spreadsheet instructions precedence, prohibits guessed-path or alternate-library bypasses, and requires the available artifact mode to be disclosed before artifact-specific approval. A host without the supported workbook path may deliver only a structured JSON specification plus Markdown or CSV tables, never a completed-workbook claim. Desktop and Claude workbook lanes remain the full-artifact gates. -
testing.md 11.2 KB
# OT Cost Analysis: Testing Record ## August 2026 cached-error validation closure An RC5 lifecycle artifact exposed a validator-coverage gap: the mapped-value comparison could pass after LibreOffice recalculation while an unmapped cell still contained a cached spreadsheet error. The canonical validator now performs a global cached-error audit across every recalculated worksheet before comparing mapped expected values. Deterministic regression coverage verifies that an unmapped `#VALUE!` fails the integrated validation path, that sheet and cell coordinates are reported, and that a clean recalculated workbook still passes. The full nine-skill validation suite passed with 38 tests. The corrected validator was also replayed with required LibreOffice recalculation against both maintained-client OT workbooks: - Codex workbook SHA-256 `b82477a05a09a579bee54525c0f4aa678b3bee8a2359bcf1fdefa6efcd4b7820`: pass, 375 formulas. - Claude workbook SHA-256 `3b2f17a1fb44166635f0acd5b0a98b8aa364a4e201f53b9ed78cc85a82a9df24`: pass, 431 formulas. This closes the validator defect without changing the OT workflow, workbook schema, or calculation method. Cross-client RC7 lifecycle qualification remains a separate release gate. ## The bottom line Four testing waves across twelve cold sub-agent runs in April 2026 took the OT Cost Analysis skill from 520 to 627 lines through 22 universal patches (15 in the first structural wave, 7 in a refinement wave, 1 correctness fix). The skill reliably orchestrates BLS OEWS, GSA CALC+, and GSA Per Diem MCPs for labor benchmarking; handles all three statutory authorities (10 USC 4021 research, 4022 prototype, 4022(f) production follow-on); applies six distinct cost-sharing paths (A-NDC, A-via-sub, B-SB, C-traditional, D-competition, and research-inapplicable); supports mixed fixed-price / cost-type milestone structures with proper ceiling-based government obligation; correctly handles multi-performer and multi-MSA labor pools; and produces 7-sheet formula-driven workbooks where every user-adjustable assumption cascades through the entire build. ## Waves tested | Wave | Runs | Focus | Patches shipped | New structural gaps surfaced | |---|---|---|---|---| | 1 | 4 | Initial cold run, no MCPs wired | 10 candidates identified | Most major gaps from this wave carried into Wave 2 | | 2 | 4 | Full MCP access, different paths | 14 patches | 7 new universal patterns | | 3 | 4 | Patch regression on untested paths | 7 patches (incl. 1 critical bug fix) | Confirmed patch bug: Performer Share didn't branch on Payment Type | | 4 | 4 | Final regression on 7 fixes | 1 critical correctness fix | 4022(f) cost-share wording contradiction | ## Authorities and paths exercised | # | Scenario | Authority | Performer path | Workflow | |---|---|---|---|---| | 1 | Group 1 sUAS autonomy, San Diego | 10 USC 4021 prototype | NDC, (d)(1)(A) | A | | 2 | Contested logistics AI planner, Arlington | 10 USC 4021 prototype | Traditional, (d)(1)(C) 1/3 share | A | | 3 | Cold-spray additive repair, concept | 10 USC 4021 prototype | NDC, (d)(1)(A) | A+ | | 4 | AGV reasonableness check, Pittsburgh | 10 USC 4021 prototype | Traditional, (d)(1)(D) competition | B | | 5 | AUV port security, DIU consortium | 10 USC 4021 prototype | SB, (d)(1)(B) | A | | 6 | Quantum RF sensing, MIT Lincoln Lab | 10 USC 4021 research | FFRDC, 4022(d) inapplicable | A | | 7 | C-UAS interceptor LRIP, Albuquerque | 10 USC 4022(f) production | NDC (inherited path), 100% gov | A | | 8 | HMT platform, Leidos + NeuroForge | 10 USC 4021 prototype | Traditional + NDC sub via (d)(1)(A) | A | | 9 | Hypersonics mixed-type, Tucson | 10 USC 4021 prototype | Traditional, (d)(1)(C) 1/3 share | A | | 10 | Metamaterial RF, GTRI FFRDC | 10 USC 4021 research | Traditional, inapplicable | A | | 11 | ASV production 24 units, Mobile | 10 USC 4022(f) production | Competition commitment (inherited), 100% gov | A | | 12 | HMT platform Orlando+Boston | 10 USC 4021 prototype | Traditional + NDC sub, multi-MSA | A | Plus the four Wave 4 regression tests (Northrop HEL reasonableness path C, Draper Boston concept via (d)(1)(A)(iii), Raytheon hypersonic seeker LRIP 100 units, NSTXL 3-performer space domain awareness). ## Patches shipped in this skill ### Wave 2 (14 patches, after MCPs wired and first round of structural gaps surfaced) | Patch | Section affected | Trigger | |---|---|---| | CALC+ `page_size=1` instruction (MCP rejects `page_size=0`) | Step 3 CALC+ | Test 4 Wave 2 errored on verbatim skill instruction | | 10 USC 4021 vs 4022 authority gate before cost-share decision | Cost-Sharing Guidance | Test 6 Wave 2 caught silent mis-application of 4022(d) to 4021 research | | 10 USC 4022(f) production follow-on brought in-scope (was falsely routed to IGCE Builder) | "What This Skill Does NOT Cover" | Test 7 Wave 2 production follow-on would have mis-routed | | Expanded SOC mapping for autonomy/ML/robotics/mechatronics/academic/production roles | Step 2a | Tests 1, 4, 5, 6, 8 all hit missing-SOC issue | | Labor rate method: per-category canonical, blended only as quick pre-sol | Step 6 labor cost | Tests 2, 3, 4 picked different methods | | Paid hours (2080) vs productive hours (1880) split explicit | Step 2d / Step 6 | Tests 1, 2, 4 risked double-burden | | Pre-solicitation mode promoted from edge case to first-class variant | Workflow A | Pre-sol is the most common use case | | Workflow A+ Step 0 inlined TRL mapping + required performer location input | Step 0 | Test 3 had to infer Huntsville from weak signals | | Cost-type ceiling: B10 margin, Payment Type column, obligation at ceiling | Sheet 1 layout, Step 7 | Tests 6 and 8 needed explicit treatment | | Multi-performer prime+sub structure with Side column and Performer Structure block | Step 6 | Test 8 required it | | Multi-location labor: per-MSA BLS queries, per-row Location tags, no averaging | Step 2b | Test 8 hit it | | Milestone duration vs PoP mismatch reconciliation rule | Step 1 validation, Step 6 | Test 2 had $515K swing on interpretation | | Academic / FFRDC / UARC labor branch: shifted burden scenarios, grad RA institutional rates | Step 2 caveat | Tests 6 and 10 needed it | | Production follow-on economics: labor mix, FY obligation profile, separate materials escalation | Step 2 production branch | Test 7 needed all three | ### Wave 3 (7 patches, Wave 3 regression surfaced refinements) | Patch | Section affected | Trigger | |---|---|---| | **Critical: Performer Share IF branch on Payment Type** | Sheet 1 I column formula | Cost-type milestones + path (C) produced Sheet1-vs-Sheet5 reconciliation gap | | Sheet 2 deterministic block placement via dict or defined names | Sheet 2 spec | Variable labor category counts broke fixed-offset assumptions | | Assumption cell inline `[$B$X]` references | Sheet 1 assumption block | Model wrote wrong cell refs when label row and data row were confused | | FY obligation mapping convention: obligate-at-start (default) | Production follow-on branch | Test 2 Wave 3 picked inconsistent conventions | | Materials escalation time-basis: compound per milestone-start month from PoP start | Step 8 scenario analysis | Test 2 Wave 3 invented a formula in absence of prescription | | Per diem FY fallback rule when target FY not yet published | Step 5 travel | Test 3 Wave 3 PoP started in unpublished FY | | Learning curve operationalization: default 95% Crawford multiplier per lot for LRIP | Production follow-on branch | Test 3 Wave 3 per-unit cost was rising instead of falling | ### Wave 4 (1 correctness fix) | Patch | Section affected | Trigger | |---|---|---| | 10 USC 4022(f) cost-share wording contradiction resolved | Step 2 production branch | Authority Gate said "100% government funding"; Step 2 said "cost-share inherits." Opposite readings. Fixed to: path determination inherits, cost-share ratio does NOT propagate. | ## What worked in every regression run - Seven-sheet workbook schema: Summary, Milestone Detail, Scenarios, Labor Benchmarking, Cost-Sharing Detail + Funding Profile, Methodology / Price Reasonableness Memo, Raw Data - Formula-driven cells throughout: changing any assumption cell (burden, cost-share ratio, escalation, ceiling margin, consortium fee) recalculates every dependent cell - Blue-font convention for user-adjustable inputs vs black for formulas - Pre-solicitation mode with conditional variance formulas: no proposed price required; formulas auto-activate when price is later entered - Position flags against should-cost (below / within 10% / 10-25% / above 25%) applied consistently - Methodology memo with 10 USC 4021/4022 authority citation, no FAR 15.404 dependence - Correct handling of NDC, SB, Traditional, consortium fee, and cost-share paths in parallel ## What was not tested - Hybrid FAR+OT arrangements (unusual but possible) - Multi-award OT (government funding multiple performers on competing prototypes in parallel) - Fixed-price-incentive-fee-style milestones (non-standard for OTs but seen in a few programs) - OT with performance-based pay-for-outcome structures - OCONUS performer with significant CONUS government integration travel - Agreement structures above $250M (skill tested up to ~$60M) - Multi-year options with government unilateral exercise Users working in these contexts should expect to validate outputs more carefully. ## Testing methodology Each wave consisted of four cold sub-agent runs. Each sub-agent read `SKILL.md` fresh with no conversation history and executed against a user prompt exactly as a claude.ai or Claude Code user would. All three MCPs (bls-oews, gsa-calc, gsa-perdiem) were live for Waves 2-4. Each agent produced a .xlsx workbook (or a described workbook if the environment did not support .xlsx generation) and a self-evaluation titled "Feedback for the evaluator" calling out patches that worked, patches that failed, and universal structural gaps. Findings were classified against a strict universal-only rule: only patches addressing structural patterns across multiple scenarios or clear statutory requirements were shipped; one-off model judgment failures and narrow domain fixes were deliberately skipped to prevent bloat. Skill line count: 520 before Wave 1, 619 after Wave 3 patches, 627 after Wave 4. Ceiling remains 1,000. ## Known limitations - openpyxl writes formula strings but no cached values. Workbooks recalculate on first open in Excel/Numbers. If distributed to an environment with formula recalc disabled, values will show #N/A until opened. - Per diem FY rates beyond the published window require fallback to most recent published FY; the skill handles this but user should refresh per diem when new FY rates publish. - CALC+ sparse-hit handling for niche defense roles (HEL, quantum, DEW) returns zero CALC+ results; skill falls back to BLS-only with methodology note; for these specialties, BLS medians understate actual market rates by 20-30%. --- **Testing Methodology** Evaluator: James Jenrette (1102tools) and Claude Code Opus 4.7 (1M context window, max effort mode, Claude Max 20x subscription). Worker model tested: Claude Opus 4.7 sub-agents with live MCP access to bls-oews, gsa-calc, gsa-perdiem. Waves: 4 waves, 16 sub-agent runs total across the full testing program, 22 universal patches shipped (15 structural + 7 refinement + 1 correctness). Date: April 2026. Skill: ot-cost-analysis. Source: github.com/1102tools-dev/federal-contracting-skills. License: MIT.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.