Extraction schema:
{"$defs": {"ScheduleItem": {"properties": {"item_no": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The line-item identifier (CLIN, SubCLIN/SLIN, or sequence number) for this row of the SF1449 Schedule of Supplies/Services, as printed in column '19. ITEM NO.' of the SF1449 form (or column '(A) ITEM NO.' on any attached Optional Form 336 'CONTINUATION SHEET' that continues the schedule). INCLUDE both top-level CLINs (typically 4 digits like '0001', '0002') AND any SubCLINs/SLINs printed as separate rows (typically 6 digits like '000101', '0001AA'). Label aliases: '19. ITEM NO.', '15A. ITEM NO.', 'ITEM NO.', 'ITEM NO. (A)', 'CLIN', 'SLIN', 'SUBCLIN'. Format requirement: copy the identifier VERBATIM from the page, preserving leading zeros, casing, and length exactly as printed (e.g. '0001', '000101', '1001AA'). Do NOT trim leading zeros (do NOT return '1' for '0001'). Do NOT add a '#' prefix. NULL semantics: if the SF1449 'ITEM NO.' column is genuinely blank for this entry (e.g. the schedule cell shows only narrative text or program name with no numeric identifier in column 19), return null. For RFP/solicitation documents where Section B.1 ('ITEMS BEING ACQUIRED') prints CLINs in a NARRATIVE list rather than in the Block 19-24 grid (e.g. 'CLIN 001 - Joule HPC...', 'CLIN 002 - Backup Storage...', 'SubCLIN 004 - Viewing/Visualization Requirement'), the printed CLIN code is the item_no — extract it VERBATIM as printed (e.g. 'CLIN 001' → '001', 'SubCLIN 004' → '004') WITHOUT the 'CLIN '/'SubCLIN ' prefix; preserve the original digit count even if shorter than 4 digits. Location hint: leftmost column of the Block 19-24 schedule grid on page 1 of the SF1449 form, plus any continuation pages (Optional Form 336 'CONTINUATION SHEET' with reference number matching the contract); also Section B.1 narrative CLIN listings on solicitations. Do NOT confuse with: (a) the CONTRACT NO. (block 2 — typically a long alphanumeric PIID like 'TOFS-16-D-0004' or 'DE-SOL-0011826'); (b) the REQUISITION NUMBER (block 1); (c) the ORDER NUMBER (block 4); (d) the SOLICITATION NUMBER (block 5); (e) any FAR clause number like '52.212-4' appearing in clauses pages; (f) sub-section identifiers like 'B.1', 'C.1' which are SECTION numbers not CLIN numbers; (g) the page-number 'PAGE OF' fields in the top-right corner of the cover sheet. [PATCH-v3 — blank item_no is valid for deliverable SLINs] NULL semantics REFINEMENT: blank `item_no` IS valid and EXPECTED for deliverable sub-rows printed within a parent CLIN's block in the Section B grid. Such rows have their own quantity / unit / unit_price / amount but no leftmost identifier. For these rows, return `item_no=null` AND set `parent_item_no` to the parent CLIN's item_no. DO emit them as separate ScheduleItem entries — they are not the same row as the parent CLIN. Composite identity (see repeated_structure.clin_items.identity_key) is `[parent_item_no, item_no, supplies_services]` so blank item_no + non-null parent_item_no + unique supplies_services title is uniquely addressable. NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Item No"}, "parent_item_no": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Parent ITEM NO", "description": "[PATCH-v3 — new field for deliverable-SLIN lineage] The `item_no` of the parent CLIN under which this row is printed. Set ONLY for blank-item_no deliverable sub-rows that sit within a parent CLIN's block in the Section B Price Schedule grid (the row has its own qty/unit/price columns but no leftmost ITEM NO cell, and the nearest preceding printed ITEM NO cell is the parent). For all top-level CLINs (rows whose own ITEM NO cell is filled in), `parent_item_no` is null. Format requirement: copy the parent CLIN's item_no VERBATIM as printed (e.g. '0001', '1001', '000101'); do NOT prefix with 'CLIN '/'SubCLIN '. Identity rule: this field is the FIRST key in the composite identity_key `[parent_item_no, item_no, supplies_services]` — it disambiguates deliverable sub-rows belonging to different parent CLINs even when they share titles (e.g. 'ATO Documentation' deliverables under both the base CLIN and option-year CLINs). NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.\n\n[PATCH-v4 — parent_item_no is the nearest preceding filled ITEM NO] DETERMINISTIC RULE for `parent_item_no`: when this row's own ITEM NO is blank (deliverable sub-row), `parent_item_no` MUST be the `item_no` value of the NEAREST PRECEDING row in the same Section B grid whose ITEM NO column is FILLED IN. Walk upward from this row through the printed-grid order; the first row encountered whose ITEM NO is non-null is the parent. Example from PDF 0059 (FAI VA Services Platform): the Section B grid prints '00XX  XX  EA  $  $  Agile Delivery' as a parent CLIN row, and then 23 deliverable sub-rows below it (each with `1 LO NSP NSP <deliverable_title>` but no leftmost ITEM NO). For ALL 23 sub-rows, `parent_item_no` MUST be `'00XX'` (the nearest preceding filled ITEM NO), NOT `'0001'` or any other prior CLIN's item_no. CRITICAL: do NOT use the deliverable's serial position number (e.g. the first deliverable's '1' in the QUANTITY column) as parent_item_no; parent_item_no is always copied verbatim from a PRECEDING ITEM NO cell, never derived from a different column or from row position."}, "supplies_services": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The short product/service title printed at the TOP of this item's '20. SCHEDULE OF SUPPLIES/SERVICES' cell — the first one or two lines that name what is being acquired for this line. Examples of correct values: 'Legal Support Services - Base Year', 'Legal Support Services - Option Year 1', 'Joule High Performance Computing (HPC) System Requirement (3-year lease)', 'Backup Storage Requirement (single purchase during year 1)', 'TARP Acquisition Support Blanket Purchase Agreement'. Where the item is a CLIN with a parenthetical period qualifier on the same heading line (e.g. 'Legal Support Services - Option Year 2'), include the qualifier as part of the title. Where the cover schedule of an RFP names the CLIN in Section B.1 NARRATIVE (e.g. 'CLIN 001 - Joule High Performance Computing (HPC) System Requirement (3-year lease)' followed on the next line by '$(TBD)/Month'), the supplies_services title is the text AFTER the CLIN code dash (e.g. 'Joule High Performance Computing (HPC) System Requirement (3-year lease)') — do NOT include the leading 'CLIN 001 - ' prefix (that is the item_no); also do NOT include the '$(TBD)' price/period qualifier on the following line (that goes into the price columns or description). Label aliases: '20. SCHEDULE OF SUPPLIES/SERVICES', '15B. SUPPLIES/SERVICES', 'SUPPLIES/SERVICES', 'SUPPLIES/SERVICES (B)'. Format requirement: preserve internal punctuation, hyphens, parentheses, and the original casing verbatim; collapse a soft line wrap inside the title into a single space. NULL semantics: if the schedule cell for this item is BLANK with no title line printed (only price-column data, no service-name text in the SUPPLIES/SERVICES column), return null. Do NOT confuse with: (a) the long narrative description body that follows the title (e.g. 'Base Year Fully Burdened Labor Rates:\\nPartner: (b)(4) per Hour\\nAssociate: (b)(4) per Hour ...' — those belong in `description`); (b) the document-level title 'SOLICITATION/CONTRACT/ORDER FOR COMMERCIAL ITEMS' or 'SOLICITATION/CONTRACT/ORDER FOR COMMERCIAL ITEM' printed at the top of the SF1449 cover page; (c) section headings like 'SECTION B - SUPPLIES OR SERVICES/PRICES'; (d) PRIME/SUB contractor name lines (e.g. 'PRIME:', 'SUB:', 'Small Business Administration', '807372839', 'INTEGRATED FEDERAL SOLUTIONS INC.') that some BPA cover sheets print into block 20 to identify parties rather than priced items — those are CONTRACTOR-IDENTIFICATION lines, NOT priced supplies/services, and do NOT constitute a separate schedule item; (e) Period-of-Performance lines (e.g. 'Period of Performance: 03/09/2012 to 03/08/2015', 'Base Year - 3/9/2012 through 3/8/2013') printed in block 20 — those are POP rows that document the contract term, NOT priced supplies/services, and should NEVER appear as their own ScheduleItem (omit them entirely from clin_items). [PATCH-v3 — blank-item_no deliverable rows] For blank-item_no deliverable SLIN rows (see item_no description's blank-item_no clause), `supplies_services` is the deliverable's printed name (e.g. 'Stable Pre-Production Environments', 'Automated Pipelines', 'ATO Documentation'). These are first-class titles for their own row, not continuations of the parent CLIN's title. See the list-level row-boundary rule for page-break handling. NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.\n\n[PATCH-v4 — title-below-item-no layout on OF-336 continuation pattern] On the SF1449 / OF-336 continuation form, many PDFs print the row using a TWO-LINE pattern: line A is the grid columns 'ITEM_NO  QTY  UNIT  UNIT_PRICE  AMOUNT' (e.g. '0011 6.00 EA'), and line B is the supplies_services title alone (e.g. 'Scanner Kit EX1902HC-FV5'). This title-below pattern means the row's title text appears on the NEXT TEXT LINE below the ITEM NO grid line, not on the same line as the ITEM NO cell. ROW BINDING RULE (deterministic, OVERRIDES any positional-alignment heuristic): the title text on line B belongs to the row whose ITEM NO is on line A, NOT to the row whose ITEM NO appears on the line C below line B. Example from PDF 0003 page 4-5 (a real, common layout): line `0011 6.00 EA` is followed on the next line by `Scanner Kit EX1902HC-FV5`, which is the title for row 0011 (NOT row 0012). The lines that follow are `0012 6.00 EA` then `Electronic Signature Pad T-S261-HSB-R` — that pair is row 0012. This rule applies EVEN ACROSS A PAGE BREAK: if line A ends a page and line B (the title) is the FIRST data line at the top of the next page (immediately under the column-header repeat), line B is still the title for row A. NEVER shift the title down one row just because the title sits on a separate line, on a new page, or in a different table sub-cell. [PATCH-v5 — strict title-only on multi-paragraph CLIN cells] STRICT TITLE-ONLY RULE FOR MULTI-PARAGRAPH BLOCK 20 CELLS: when a CLIN's Block 20 'SCHEDULE OF SUPPLIES/SERVICES' cell contains MULTIPLE paragraphs (common pattern: a one-line product/service title in bold/larger type, followed by a free-text narrative body of one or more paragraphs that may include labor-rate breakdowns, delivery dates, deliverables enumeration, or per-CLIN clauses), `supplies_services` captures ONLY the first paragraph (the product/service title line). Every subsequent paragraph in the SAME Block 20 cell — regardless of length, regardless of whether it begins with a colon-headed label like 'Partner:' or 'Delivery:' or 'Obligated Amount:', regardless of whether it appears to continue the title's subject — belongs to `description`, NOT to `supplies_services`. NEVER concatenate the title paragraph with body paragraphs into a single `supplies_services` value. WORKED EXAMPLE (PDF 0059 Agile Delivery CLIN 0001 pattern): Block 20 prints the line 'Agile Delivery — Base Period' as the title, then a body paragraph starting 'The contractor shall provide ...' which lists 23 deliverable sub-items. `supplies_services` = 'Agile Delivery — Base Period' (title only). `description` = the full body paragraph(s) including the deliverables enumeration. Each deliverable that is printed AS ITS OWN ROW in the price-table grid (with its own qty/unit/price columns and a blank ITEM NO) is a separate ScheduleItem with its own supplies_services title — see the blank-item_no deliverable-SLIN clause and the parent_item_no field.", "title": "Supplies/Services Title"}, "description": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The narrative body printed inside this item's '20. SCHEDULE OF SUPPLIES/SERVICES' cell AFTER the title line captured in `supplies_services` and BEFORE the next ITEM NO heading (or before Section C / Section H / Block 25 'ACCOUNTING AND APPROPRIATION DATA'). Typically contains: labor-rate breakdowns (e.g. 'Partner: (b)(4) per Hour\\nAssociate: (b)(4) per Hour\\nParalegal: (b)(4) per Hour'), 'Obligated Amount: $0.00' / 'Amount: $0.00 (Option Line Item)', 'Delivery: 01/14/2016' lines, and any per-CLIN free text like 'The contractor shall ...'. For solicitation-style RFP documents where Section B.1 prints each CLIN as a narrative paragraph with only a period/price qualifier (e.g. CLIN 001 followed by '$(TBD)/Month'), this field is the pricing/period qualifier line (e.g. '$(TBD)/Month') — preserve it verbatim using the canonical no-space token. Format requirement: concatenate every narrative line inside this item's schedule cell into a SINGLE STRING with a single space between successive lines (collapse hard newlines to a single space and collapse runs of whitespace). Preserve verbatim casing, punctuation, embedded labels (e.g. 'Partner:', 'Delivery:', 'Obligated Amount:'), and any redaction tokens (e.g. '(b)(4)'). WHITESPACE CANONICALIZATION (REQUIRED, applies to every doc-type and OVERRIDES the generic 'preserve verbatim punctuation' rule for these specific placeholder tokens): Collapse any whitespace that appears between `$` and the following `(` in `$(TBD)` / `$(amount)` / `$(estimate)` placeholder tokens. The PDF may print these with a literal space character (e.g. '$ (TBD)', '$ (TBD)/Month') because of form-field rendering quirks — do NOT preserve that literal space. The canonical token form is '$(TBD)' or '$(TBD)/Month' with NO space between the `$` and the `(`. Likewise canonicalize '$ TBD' to '$TBD' if that variant appears without parentheses. DO NOT repeat the title line already captured in `supplies_services`. DO NOT include the 'Delivery:' / 'Period of Performance:' lines that print OUTSIDE the per-CLIN block (e.g. the standalone 'Period of Performance: 01/14/2016 to 01/13/2021' that some forms print once for the whole contract above CLIN 0001) — only narrative inside the same boxed schedule cell as the CLIN. NULL semantics: if the cell contains ONLY the title (no narrative body and no labor-rate breakdown and no embedded 'Delivery:'/'Obligated Amount:' line), return null. Do NOT confuse with: (a) Section C 'DESCRIPTION/SPECIFICATIONS' / Statement of Work text (that is a separate document section, not the per-CLIN schedule description); (b) Section F 'DELIVERIES OR PERFORMANCE' which describes contract-wide delivery terms; (c) Section H 'SPECIAL CONTRACT REQUIREMENTS'; (d) the BPA Scope-of-Agreement narrative on later pages of a BPA (e.g. the 'TARP Acquisition Support' background/scope/objectives paragraphs in a Treasury BPA) — that prose lives in subsequent body pages, not inside the Block 19-24 grid, and does NOT belong to any ScheduleItem.description. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Description"}, "quantity": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The value printed in column '21. QUANTITY' of the SF1449 schedule for this row. Label aliases: '21. QUANTITY', '15C. QUANTITY', 'QUANTITY', 'QUANTITY (C)'. Format requirement: extract VERBATIM as a string, preserving any printed comma thousand-separators (e.g. '1,482'). If the cell is REDACTED with a FOIA marker — either text '(b)(4)' / '(b) (4)' or a solid black redaction rectangle (visible as alt-text such as 'QUANTITY (b) (4)' or as a literal black-box image) — return the canonical token '(b)(4)' (no internal whitespace, no surrounding quotes). If the cell prints a non-numeric placeholder such as 'N/A', 'NSP' (Not Separately Priced), 'TBD', or '(TBD)' — return that placeholder verbatim. NULL semantics: return null ONLY if column 21 is genuinely empty for this row (no number, no redaction marker, no placeholder text). On BPAs and IDIQs the entire QUANTITY column is often blank because pricing is task-order-driven; in that case quantity is null. Location hint: column 21 of the SF1449 form (or column C of the OF-336 continuation sheet), same row as this item's ITEM NO. Do NOT confuse with: (a) the cumulative-ceiling dollar amount printed in narrative such as 'cumulative value ... shall not exceed $3,500,000.00' — that is a contract ceiling, not a line-item quantity; (b) labor-hour counts mentioned inside the description narrative; (c) the SIZE STANDARD value in block 10; (d) per-task-order quantities defined in unattached call orders. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Quantity"}, "unit": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The unit of measure printed in column '22. UNIT' of the SF1449 schedule for this row. Label aliases: '22. UNIT', '15D. UNIT', 'UNIT', 'UNIT (D)'. Format requirement: extract VERBATIM as printed, preserving exact casing (e.g. 'Each', 'EA', 'LO', 'JB', 'HR', 'MO', 'YR'). If the cell is REDACTED (FOIA token or black box), return '(b)(4)'. If the cell is genuinely blank, return null. Do NOT default-fill 'EA' or '1' if the column is blank. Location hint: column 22 of the SF1449 form (or column D of the OF-336 continuation sheet), same row as this item's ITEM NO. Do NOT confuse with: (a) packaging descriptors that appear inside the narrative (e.g. '100 kits per box'); (b) period qualifiers that appear inside the title or description (e.g. '/Month', '/Year', 'per Hour'); (c) any column labeled 'UNIT PRICE' (that is column 23, a separate field). [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Unit"}, "unit_price": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The value printed in column '23. UNIT PRICE' of the SF1449 schedule for this row. Label aliases: '23. UNIT PRICE', '15E. UNIT PRICE', 'UNIT PRICE', 'UNIT PRICE (E)'. Format requirement: extract VERBATIM, preserving the leading dollar sign, comma thousand-separators, and decimal places exactly as printed (e.g. '$3.84', '$148,225.00'). REDACTED values: if the UNIT PRICE cell shows '(b)(4)' / '(b) (4)' text or a solid black redaction rectangle, return the canonical token '(b)(4)'. Placeholder values: 'NSP' (Not Separately Priced) — return 'NSP' verbatim if 'NSP' is printed in column 23 of the Block 19-24 grid. NULL semantics: return null if column 23 is genuinely empty (no number, no redaction marker, no placeholder text) — common on BPA cover sheets where pricing is task-order-driven. CRITICAL DOC-TYPE CLAUSE (RFP / solicitation handling, SUPERSEDES all other guidance): on an SF1449 SOLICITATION where the Block 19-24 schedule grid is BLANK for this row AND the only printed pricing qualifier (e.g. '$(TBD)', '$(TBD)/Month', '$ (TBD)', '$ (TBD)/Month', 'TBD', '$ TBD') appears in the Section B.1 NARRATIVE paragraph for the CLIN, `unit_price` MUST be null. The '$(TBD)' / 'TBD' qualifier text belongs ONLY in `description` — NEVER copy it into `unit_price`. This rule applies to every CLIN whose `item_no` was extracted from a Section B.1 narrative paragraph rather than from a populated row of the Block 19-24 grid. It is intentional that on RFP-style solicitations the entire `unit_price` column will read null for every CLIN — that is the correct, deterministic answer because the grid column is genuinely blank. CRITICAL — when the row collapses to a single visible dollar value: the SF1449 grid has TWO money columns (23 UNIT PRICE and 24 AMOUNT). If only one dollar amount is visible in the row, locate which column it sits under by horizontal position before assigning: a number aligned under the rightmost AMOUNT column is `amount`, not `unit_price`. When unit price is redacted but amount is visible (a frequent FOIA-pattern), unit_price=`(b)(4)` and amount holds the visible value. Do NOT confuse with: (a) AMOUNT in column 24 (they may be equal when quantity=1 but are different fields); (b) the labor-rate values printed inside the description narrative (e.g. 'Partner: (b)(4) per Hour') — those are part of `description`, NOT this field; (c) the TOTAL AWARD AMOUNT (block 26) which is the contract-wide total; (d) any cost-code AMOUNT in block 25 ACCOUNTING AND APPROPRIATION DATA. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell. [PATCH-v5 — placeholder-only cells normalize to null] PLACEHOLDER-ONLY CELLS: if the cell contains ONLY a placeholder symbol with no numeric content (e.g. a lone '$' with no digits after it; a lone 'XX' or 'X' standing in for a digit; 'TBD' / '(TBD)' standing alone in the column with no monetary value; an em-dash '—' or hyphen '-' filler), return JSON `null`. The cell carries no extractable value. Do NOT return the placeholder character itself as the value. EXCEPTIONS — these are NOT placeholders and DO carry value: (a) 'NSP' (Not Separately Priced) — return 'NSP' verbatim per the NSP rule elsewhere in this description; (b) '(b)(4)' / '(b) (4)' — return the canonical '(b)(4)' token per the FOIA redaction rule elsewhere in this description; (c) '$0.00' / '0.00' — return verbatim per the option-year-zero rule. The placeholder→null rule is narrowly for cells that contain ONLY a non-informative symbol like a stray '$' or 'XX' character.", "title": "Unit Price"}, "amount": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The value printed in column '24. AMOUNT' (the extended line total, generally quantity * unit_price) of the SF1449 schedule for this row. Label aliases: '24. AMOUNT', '15F. AMOUNT', 'AMOUNT', 'AMOUNT (F)'. Format requirement: extract VERBATIM, preserving the leading dollar sign, comma thousand-separators, and decimal places exactly as printed (e.g. '$148,225.00', '$11,600.00', '$0.00'). The form does sometimes print the value without a leading '$' (especially on continuation sheets, e.g. '0.00') — in that case return the value EXACTLY as printed including the missing dollar sign. REDACTED values: '(b)(4)' or '(b) (4)' → return the canonical token '(b)(4)'. Placeholder values: 'NSP' → return 'NSP' verbatim; '$0.00' on an option line item that has been written into the schedule but not exercised → return '$0.00' verbatim. NULL semantics: return null ONLY if column 24 is genuinely empty. On RFP solicitation cover sheets where the entire Block 19-24 grid is blank and CLINs are listed only in Section B.1 narrative with '$(TBD)' qualifiers, the amount column is null (the '$(TBD)' qualifier text belongs in `description` ONLY; `unit_price` remains `null` unless column 23 is populated; either way, this qualifier is NEVER copied into `amount`). Location hint: rightmost column of the Block 19-24 schedule grid (or column F of the OF-336 continuation sheet). Do NOT confuse with: (a) UNIT PRICE in column 23; (b) the TOTAL AWARD AMOUNT printed in block 26 of the cover page; (c) per-ACRN accounting allocations printed in block 25 'ACCOUNTING AND APPROPRIATION DATA'; (d) cumulative-ceiling phrases like 'shall not exceed $3,500,000.00'; (e) Obligated Amount lines printed INSIDE the description (e.g. 'Obligated Amount: $0.00') — that lives in `description`, not here, unless column 24 also prints '$0.00' for the row. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.\n\n[PATCH-v4 — VERBATIM, do not add a leading '$'] CRITICAL VERBATIM RULE (clarifies the earlier 'extract VERBATIM' guidance): copy column 24 exactly as printed, including whether or not the printed cell has a leading '$' character. If the PDF prints '0.00' in column 24 (with NO leading '$' — this is common on OF-336 continuation sheets, e.g. PDF 0042 CLINs 0002-0005 all print '0.00' for option-year amounts), return the string '0.00' WITHOUT adding a '$'. If the PDF prints '$0.00' (with a leading '$'), return '$0.00'. NEVER substitute one for the other. NEVER add a '$' that is not in the printed cell. If both renderings appear in the SAME document on different rows, preserve the per-row verbatim form rather than canonicalizing all to one. The same rule applies to '$148,225.00' vs '148,225.00' and any other dollar-format mismatch in column 24. [PATCH-v5 — placeholder-only cells normalize to null] PLACEHOLDER-ONLY CELLS: if the cell contains ONLY a placeholder symbol with no numeric content (e.g. a lone '$' with no digits after it; a lone 'XX' or 'X' standing in for a digit; 'TBD' / '(TBD)' standing alone in the column with no monetary value; an em-dash '—' or hyphen '-' filler), return JSON `null`. The cell carries no extractable value. Do NOT return the placeholder character itself as the value. EXCEPTIONS — these are NOT placeholders and DO carry value: (a) 'NSP' (Not Separately Priced) — return 'NSP' verbatim per the NSP rule elsewhere in this description; (b) '(b)(4)' / '(b) (4)' — return the canonical '(b)(4)' token per the FOIA redaction rule elsewhere in this description; (c) '$0.00' / '0.00' — return verbatim per the option-year-zero rule. The placeholder→null rule is narrowly for cells that contain ONLY a non-informative symbol like a stray '$' or 'XX' character.", "title": "Amount"}}, "title": "ScheduleItem", "type": "object"}}, "properties": {"contract_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The contract / order PIID printed in block 2 'CONTRACT NO.' of the SF1449 form cover sheet. Examples: 'TOFS-16-D-0004', 'TOFS-12-B-0005 / 0353/12/201160', 'W911QY20P0195'. Label aliases: '2. CONTRACT NO.', '2. CONTRACT (Proc. Inst. Ident.) NO.', 'CONTRACT NO.'. Format requirement: copy VERBATIM from block 2 exactly as printed, preserving internal slashes, hyphens, spaces and casing (e.g. 'TOFS-12-B-0005/\\n0353/12/201160' may be rendered across two lines — collapse soft line wraps into a single space, preserving the slash separators). Do NOT append the contract administration office code (e.g. 'ARC/ASD/OFS') or any modification suffix. If the SF1449 is a SOLICITATION ONLY and block 2 is blank (no awarded contract yet), return null and let `solicitation_number` carry the identifier instead. Location hint: block 2 of the SF1449 cover page, immediately right of the document title. Do NOT confuse with: (a) the requisition number in block 1; (b) the solicitation number in block 5; (c) the order number in block 4; (d) the CONTRACT ADMINISTRATION OFFICE code that may appear in block 16/18a (e.g. 'ARC/ASD/APB', 'TDP-IRS'); (e) the contractor's CAGE/DUNS code in block 17a; (f) the SF33 form number 'SF33-...' that some RFP packets reference for offer submission. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Contract Number"}, "solicitation_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The solicitation identifier printed in block 5 'SOLICITATION NUMBER' of the SF1449 form cover sheet. Example: 'DE-SOL-0011826'. Label aliases: '5. SOLICITATION NUMBER', 'SOLICITATION NUMBER'. Format requirement: copy VERBATIM from block 5 (preserve hyphens, casing, leading zeros). NULL semantics: return null if block 5 is blank (typical for already-awarded contracts that no longer carry a separate solicitation number). Location hint: block 5 of the SF1449 cover page, upper-right area. Do NOT confuse with: (a) the contract number in block 2; (b) the requisition number in block 1; (c) the order number in block 4; (d) the contractor's quote/proposal number (which does not appear on the SF1449 cover); (e) the SOLICITATION ISSUE DATE in block 6 (that is the date, not the identifier). [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Solicitation Number"}, "requisition_number": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The requisition number printed in block 1 'REQUISITION NUMBER' of the SF1449 form cover sheet. Label aliases: '1. REQUISITION NUMBER', 'REQUISITION NUMBER'. Format requirement: copy VERBATIM from block 1 (preserve leading zeros, hyphens, internal slashes). NULL semantics: return null if block 1 is blank. Location hint: block 1 of the SF1449 cover page, immediately right of the document title. Do NOT confuse with: (a) the contract number in block 2; (b) the solicitation number in block 5; (c) the order number in block 4; (d) the PURCHASE REQUEST NUMBER that may also appear inside CLIN description bodies (those are per-CLIN PR numbers, while block 1 is the document-level requisition). [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Requisition Number"}, "issue_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The solicitation issue date printed in block 6 'SOLICITATION ISSUE DATE' of the SF1449 form cover sheet. Label aliases: '6. SOLICITATION ISSUE DATE', 'SOLICITATION ISSUE DATE'. Format requirement: extract EXACTLY as printed on the form — do NOT reformat. Common renderings include 'MM/DD/YYYY' (e.g. '09/26/2017'), 'DD-MMM-YYYY' (e.g. '12-Jun-2020'), 'DD MMM YYYY' (e.g. '17 APR 2020'); preserve slashes, dashes, casing, and zero-padding exactly. NULL semantics: return null if block 6 is blank (typical for awarded BPAs / IDIQ contracts where no separate solicitation issue date is recorded on the cover). Location hint: block 6 of the SF1449 cover page, upper-right corner. Do NOT confuse with: (a) the award/effective date in block 3; (b) the offer due date/local time in block 8 (that field combines a date with a time-of-day); (c) any 'date signed' in block 30c/31c at the bottom of the form; (d) the per-CLIN 'Delivery:' dates inside descriptions. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Issue Date"}, "award_effective_date": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The award / effective date printed in block 3 'AWARD/EFFECTIVE DATE' of the SF1449 form cover sheet. Label aliases: '3. AWARD/EFFECTIVE DATE', 'AWARD/EFFECTIVE DATE'. Format requirement: extract EXACTLY as printed — preserve the printed format (e.g. '01/14/2016', '3-6-2012', '03/09/2012'). NULL semantics: return null if the SF1449 is a SOLICITATION ONLY and block 3 is blank (no contract awarded yet). Location hint: block 3 of the SF1449 cover page, upper-left area between blocks 2 and 4. Do NOT confuse with: (a) the solicitation issue date in block 6; (b) date signed by offeror in block 30c; (c) date signed by contracting officer in block 31c (these may be the same as the effective date but live in different blocks); (d) Period-of-Performance start dates printed inside block 20 (e.g. 'Base Year - 3/9/2012 through 3/8/2013') — those describe periods, not the award date. [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Award Effective Date"}, "total_award_amount": {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null, "description": "The dollar total printed in block 26 'TOTAL AWARD AMOUNT (For Govt. Use Only)' of the SF1449 form cover sheet. Label aliases: '26. TOTAL AWARD AMOUNT (For Govt. Use Only)', '26. TOTAL AWARD AMOUNT', 'TOTAL AWARD AMOUNT'. Format requirement: extract VERBATIM, preserving the leading dollar sign, comma thousand-separators, and decimal places (e.g. '$148,225.00', '$0.00', '$6,305,320.00'). REDACTED values: '(b)(4)' or '(b) (4)' → return canonical '(b)(4)'. NULL semantics: return null ONLY if block 26 is genuinely blank. On IDIQ and BPA cover sheets block 26 commonly prints '$0.00' because the contract awards an indefinite quantity vehicle with no upfront obligation — return '$0.00' verbatim in that case (do NOT substitute the cumulative-ceiling phrase from later body text). Location hint: block 26 of the SF1449 cover page, lower-right side of the page. Do NOT confuse with: (a) per-line AMOUNT values in column 24 of the schedule (those are line totals, not the contract grand total); (b) cumulative-ceiling phrases printed in body sections (e.g. 'shall not exceed $3,500,000.00' — that is a ceiling, NOT what block 26 prints); (c) the OBLIGATION amount printed inside individual CLIN descriptions; (d) the SIZE STANDARD value in block 10 (a small-business threshold dollar amount, unrelated to the contract total). [PATCH-v3 — null-vs-empty-string]  NULL-vs-EMPTY-STRING CANONICALIZATION (universal): if the cell value is empty, whitespace-only, or otherwise contains no useful content after extraction, return JSON `null`. NEVER return an empty string `\"\"`. The evaluator treats `null` and `\"\"` as different values and using `\"\"` blocks ground-truth generation downstream. This rule applies to every nullable scalar in this schema and OVERRIDES any preserve-verbatim guidance below for the specific case of an empty cell.", "title": "Total Award Amount"}, "clin_items": {"anyOf": [{"items": {"$ref": "#/$defs/ScheduleItem"}, "type": "array"}, {"type": "null"}], "default": null, "description": "Ordered list of every line item that appears in the 'SCHEDULE OF SUPPLIES/SERVICES' for this SF1449 document. The schedule lives in (a) the Block 19-24 grid on the cover page of the SF1449 form, and (b) any attached Optional Form 336 'CONTINUATION SHEET' or Section B 'SUPPLIES OR SERVICES/PRICES' page that continues or restates the cover-page schedule. Each entry is one ScheduleItem row (see ROW BOUNDARIES in the PATCH-v3 clause below — a row may be either a printed-ITEM-NO row OR a blank-item_no deliverable sub-row beneath a parent CLIN). Order: preserve the on-page order — cover-page rows first (0001, 0002, ...), then continuation-sheet rows in printed order. INCLUDE: (i) priced lines (with explicit unit_price and amount), (ii) Not-Separately-Priced ('NSP') deliverable lines, (iii) Option Year line items even if amount is $0.00 (e.g. CLINs 0002-0005 'Legal Support Services - Option Year 1/2/3/4'), (iv) lines whose money columns are FOIA-redacted ('(b)(4)' / black-box), (v) RFP/solicitation CLINs printed in Section B.1 NARRATIVE (e.g. 'CLIN 001 - Joule HPC System Requirement (3-year lease) $(TBD)/Month') — for those, item_no is the printed CLIN code without the 'CLIN '/'SubCLIN ' prefix and the '$(TBD)' qualifier goes in `description` only; `unit_price` remains `null` unless column 23 is populated with a real numeric value. EXCLUDE: (a) PRIME/SUB contractor identification lines that some BPA cover sheets type into block 20 (e.g. 'PRIME: Small Business Administration', 'SUB: 807372839 INTEGRATED FEDERAL SOLUTIONS INC. 1818 LIBRARY ST STE 500 RESTON VA 20190-6274', and the trailing program-name label 'Troubled Asset Relief Program (TARP) Acquisition Support Blanket Purchase Agreement') — those are CONTRACTOR-IDENTIFICATION / SCOPE-LABEL text, not priced supplies/services, and DO NOT constitute a ScheduleItem; (b) Period-of-Performance lines printed in block 20 above CLIN 0001 (e.g. 'Base Year - 3/9/2012 through 3/8/2013', 'Period of Performance: 01/14/2016 to 01/13/2021', 'Option Year One - 3/9/2013 through 3/8/2014') — these are contract-wide POP rows, not per-item rows; (c) the Section C 'DESCRIPTION/SPECIFICATIONS' or 'STATEMENT OF WORK' narrative; (d) Section F deliveries; (e) Section H special clauses; (f) Section I FAR clauses by reference; (g) attached appendices, attachments, certifications, and conflict-of-interest forms; (h) any per-CLIN 'Accounting Info:' / cost-code lines printed above CLIN 0001. EMPTY SCHEDULE: if the SF1449 grid is intentionally blank AND there is no Section B narrative listing of CLINs (e.g. a pure BPA cover sheet whose schedule names only the program with no priced items and no narrative line-item enumeration anywhere in the document), return an empty list `[]`. Identity for each row: see repeated_structure.clin_items.identity_key — the composite `[parent_item_no, item_no, supplies_services]` (NOT plain item_no alone, since blank-item_no deliverable SLINs need lineage + title to be distinguishable).\n\n[PATCH-v3 — Section B boundary + deliverable SLINs + lineage + page-break]\nINCLUDE every priced or NSP-placeholder row that physically sits INSIDE the Section B Price Schedule grid (or its OF-336 continuation), REGARDLESS of whether the leftmost ITEM NO column is filled in. Specifically: deliverable sub-rows printed beneath a parent CLIN (e.g. on the FAI VA Services Platform pattern, parent CLIN '0001 — Agile Delivery' contains 23 deliverable rows such as 'Stable Pre-Production Environments', 'Automated Pipelines', 'ATO Documentation' each printed with its own qty / unit / unit_price / amount columns but with a BLANK item_no) ARE separate ScheduleItem entries in this list. Their `item_no` is null; their `parent_item_no` is the parent CLIN's item_no (e.g. '0001'); their other fields are extracted from the printed row.\n\nEXCLUDE narrative menus of available tasks that live OUTSIDE the Section B Price Schedule grid: Section C 'STATEMENT OF WORK' / 'DESCRIPTION/SPECIFICATIONS', Section H 'SPECIAL CONTRACT REQUIREMENTS', Section L 'INSTRUCTIONS TO OFFERORS', Section M 'EVALUATION CRITERIA', PWS / SOW task listings, attachments, the document table of contents, and any 'Optional Task N — <title>' menu paragraphs printed in PWS prose. The positional test is the boundary heading: a row counts ONLY if its grid line is between the 'SECTION B' / 'SCHEDULE OF SUPPLIES/SERVICES' / 'PRICE SCHEDULE' heading and the next major-section heading (typically 'SECTION C' or 'SECTION D'). Tasks named identically in PWS text are NOT separate clin_items entries — the deliverable rows IN Section B are the schedule; the PWS prose is a scope reference, not a price-table row.\n\nROW BOUNDARIES (page-break safe, simpler restatement of v2's row rule): a row STARTS at either (a) a printed ITEM NO cell in the leftmost column, or (b) for a blank-item_no deliverable sub-row, at the next printed qty/unit/unit_price/amount line inside the Section B grid below the parent CLIN's columns. A row ENDS at the next row-start boundary (a) or (b), or at the end of Section B (next major-section heading). EVERY text or column value printed between a row's start and its next boundary belongs to that row — including text that wraps across a page break. NEVER split a row at a page break. NEVER reassign continuation text to the next row just because the continuation begins at the top of a new page.\n\nIDENTITY: each row's identity for downstream alignment is the composite `[parent_item_no, item_no, supplies_services]` (see repeated_structure.clin_items.identity_key). For top-level CLINs `parent_item_no` is null; for deliverable sub-rows `parent_item_no` is the parent CLIN's `item_no` string and `item_no` is null.\n\n[PATCH-v4 — additional EXCLUDE guidance + Section B start rule]\n\nEXCLUDE (additional cases observed in real PDFs):\n(I) Period-of-Performance / Accounting-Info narrative blocks printed in column 20 ABOVE the first CLIN row. On some IDIQ continuation sheets (e.g. PDF 0042), the second page of the SF1449 begins with a block 20 cell that contains 'Option Year 2: ...', 'Option Year 3: ...', 'Total Potential Period of Performance: ...', and 'Accounting Info: -61000001---XXXXXXXXXX-...' BEFORE the first CLIN row ('0001 Legal Support Services - Base Year') appears. ALL of this above-CLIN-0001 narrative is NOT a ScheduleItem and MUST NOT be emitted as a separate row. The Section B grid starts at the first row whose ITEM NO cell is FILLED IN.\n(II) PWS / SOW / CDRL deliverable-listing pages that LOOK LIKE table rows but are OUTSIDE Section B. On PDF 0059, pages 4 and 50-90 print a CDRL-style listing of deliverable titles ('Monthly Progress Report', 'Sprint Reports', 'ATO Documentation', 'Stable pre-production environments', ...) and a parallel PWS section listing 'Optional Task 1 – Platform Operations and Maintenance', 'Optional Task 1.a.', etc. These titles look almost identical to deliverable sub-row titles in the Section B grid (sometimes differing only in casing or '–' vs '-'), but they are PWS/CDRL listings, NOT priced rows. They are EXCLUDED. The positional test (between 'SECTION B' heading and next major-section heading) is authoritative; the title-similarity-to-Section-B-row test is NOT.\n(III) TOC and table-of-deliverables-summary pages that enumerate deliverables without QUANTITY/UNIT/UNIT_PRICE/AMOUNT columns. If a candidate row has all of qty/unit/unit_price/amount null AND its location is outside the priced-grid heading boundaries, it is NOT a ScheduleItem.\n\nSECTION B START RULE: the first ScheduleItem in clin_items is the row at the FIRST printed ITEM NO cell after the 'SECTION B' / 'SCHEDULE OF SUPPLIES/SERVICES' / 'PRICE SCHEDULE' / 'PRICE/COST SCHEDULE' heading (or, on legacy SF1449 cover pages without an explicit Section B heading, the first ITEM NO cell in the Block 19-24 grid). Any narrative text that appears between the heading and the first ITEM NO cell is preamble (POP, Accounting Info, contract-wide notes) — preamble is NEVER a ScheduleItem.\n", "title": "Schedule Items"}}, "title": "SF1449 Schedule — v5 PATCH (placeholder→null + strict title-only)", "type": "object", "$comment": "v5 patch built from sa2 schema_v4 — see sa2_schema_v5_patch.md for the review log. Targets verifier-r3 findings on PDF 0059 (lone $ / XX placeholders + multi-paragraph CLIN title+description concatenation). NOT validated by re-extraction; v5 is the schema against which the hand-built GT for 0003 + 0059 will be written."}

Expected output:
{"contract_number": "TOFS-12-B-0005/ 0353/12/201160", "solicitation_number": null, "requisition_number": null, "issue_date": null, "award_effective_date": null, "total_award_amount": "$0.00", "clin_items": []}