ICPI Contract And Validation Surface
Status: ACTIVE
Sprint: Extraction Prep Sprint 45
Purpose
This document records the ICPI-owned contract and validation surface after the first code-boundary hardening pass.
It distinguishes:
- route-facing contracts
- internal repository/domain contracts
- ICPI-owned validation
- remaining duplication or transitional hosting
A. ICPI-Owned Contracts
Primary file:
services/svc-tenders/src/icpi/contracts.ts
Route-facing contracts
| Contract | Purpose | Notes |
| --- | --- | --- |
| IcpiPriceListResponse | GET /icpi/prices success payload | canonical read/list response shape inside svc-tenders ICPI code |
| IcpiSuggestionResponse | GET /icpi/suggest success payload | canonical suggestion response shape |
| IcpiLatestPricePointResponse | GET /icpi/latest/:itemCode success payload | canonical latest lookup response |
| IcpiEstimateResponse | GET /icpi/estimate success payload | canonical estimate response |
| IcpiUpsertResponse | POST /icpi/upsert success payload | canonical write result shape |
| IcpiUpsertResponseMeta | upsert metadata sub-shape | accepted/received/duplicates counters |
| IcpiRouteSupport | shell-to-route support contract | still shell-dependent, but now ICPI-owned as a contract surface |
Request/input contracts
| Contract | Purpose | Notes |
| --- | --- | --- |
| UpsertIcpiPriceRequestRow | incoming ICPI upsert row shape | pre-normalization request row |
| UpsertIcpiPriceRequest | incoming upsert request body | optional source metadata plus rows |
| IcpiListFilters | read-only filter surface without pagination internals | useful for count/read filter distinction |
| IcpiListOptions | repository read options including pagination | current list/read repository input |
Internal repository/domain-facing contracts
| Contract | Purpose | Notes |
| --- | --- | --- |
| IcpiQuarter | quarter enum-like scalar | reused across request, persistence, and response |
| IcpiPricePoint | canonical ICPI stored/read row shape | shared by repository and route responses |
| IcpiSuggestion | canonical suggestion/read shape | suggestion/latest-related read surface |
| UpsertIcpiPriceInput | normalized write input for repository | post-parse, post-normalization write shape |
| IcpiRepositoryPort | route -> repository dependency contract | narrows route dependency to ICPI-owned surface |
| IcpiEstimate | estimate payload sub-shape | route-facing but derived from repository read result |
| IcpiPriceListMeta | list response metadata | route-facing support shape |
B. ICPI-Owned Validation
Primary file:
services/svc-tenders/src/icpi/validation.ts
| Validation | Purpose | Previous host | Current verdict |
| --- | --- | --- | --- |
| icpiQuarterSchema | quarter scalar validation | mixed services/svc-tenders/src/validation.ts | now ICPI-owned |
| upsertIcpiPriceSchema | upsert request validation | mixed services/svc-tenders/src/validation.ts | now ICPI-owned |
C. Route-Facing Vs Internal Boundary
Route-facing
- success response contracts
- route-support contract
- upsert request body contract
Internal
- normalized repository write input
- repository list/read options
- repository-port contract
- canonical point/suggestion domain shapes
This is the truthful split today. ICPI still has one route file and one repository file, but the contract surface is no longer rooted in mixed non-ICPI files.
D. Remaining Transitional Notes
Root repository compatibility
VERIFIED
services/svc-tenders/src/repository.ts still:
- imports ICPI contract types from
src/icpi/contracts.ts - re-exports long-standing ICPI type names for compatibility
- delegates ICPI method calls to
IcpiRepository
This is transitional compatibility, not primary contract ownership.
Shell dependency still remains
VERIFIED
IcpiRouteSupport is now ICPI-owned as a contract, but its runtime implementation still comes from shell-owned helpers in services/svc-tenders/src/server.ts.
Web duplication still remains
VERIFIED
apps/web/src/portal/api.ts still defines local ICPI client-side shapes such as:
IcpiLatestPricePointIcpiSuggestionOptionIcpiPriceListFiltersIcpiPriceListMetaIcpiPriceListResponse
That duplication was not rewritten in this sprint.
E. Current Honest Surface Summary
After Sprint 45:
- ICPI-owned contracts now live in ICPI-owned code
- ICPI-owned validation now lives in ICPI-owned code
- remaining duplication is explicit
- remaining shell/runtime hosting is explicit
That is the right state for the next extraction-prep sprint.