@finsys/core 4.0.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -416,16 +416,34 @@ declare enum FileFieldTableType {
416
416
  * observedAt — ISO wall-clock of the extraction run
417
417
  * sourceRunId — the extraction run/job id that wrote it
418
418
  * origin — "extracted" (a real {value,confidence} leaf) vs "derived"
419
- * (computed / no-confidence path). A "derived" field must render
420
- * as "no confidence available", never a fabricated low score.
419
+ * (computed / no-confidence path) vs "manual" (SYS-2806, a
420
+ * lender-entered correction, committed once its edit overlay
421
+ * is approved). A "derived" field must render as "no
422
+ * confidence available", never a fabricated low score; a
423
+ * "manual" field must render as an edit indicator, not a
424
+ * confidence dot — confidence is always null for it too.
421
425
  */
426
+ /**
427
+ * Canonical origin values, single source of truth (Gemini-review finding:
428
+ * avoids duplicating the literal strings between the type and the runtime
429
+ * guard) -- mirrors the IhsStatus/IHS_VALID_STATUSES pattern in
430
+ * ihs-status.ts.
431
+ */
432
+ declare const IHS_FIELD_ORIGINS: readonly ["extracted", "derived", "manual"];
433
+ type IhsFieldOrigin = (typeof IHS_FIELD_ORIGINS)[number];
422
434
  interface IhsFieldProvenance {
423
435
  source: string;
424
436
  confidence: number | null;
425
437
  observedAt: string;
426
438
  sourceRunId: string | null;
427
- origin: 'extracted' | 'derived';
439
+ origin: IhsFieldOrigin;
428
440
  }
441
+ /**
442
+ * Type guard: narrows an unknown value to `IhsFieldOrigin` iff it is one of
443
+ * the three canonical origin strings. `origin` was previously validated
444
+ * only by the TS union — this is the first runtime check.
445
+ */
446
+ declare function isValidIhsFieldOrigin(origin: unknown): origin is IhsFieldOrigin;
429
447
  interface FileFieldTableItem {
430
448
  displayName: string;
431
449
  timePeriods: string[];
@@ -449,6 +467,22 @@ interface FileFieldTableData {
449
467
  items: FileFieldTableItem[];
450
468
  hasData: boolean;
451
469
  }
470
+ /**
471
+ * One sibling-table row as finsys-api's `docInstanceStorageService` writes
472
+ * it (SYS-2842) -- the unbounded counterpart to a T{n}-suffixed wide-table
473
+ * slot. `instanceKey` is the real, collision-free per-document key;
474
+ * `sourceLabel` is a human label when the doc type has one (e.g. a bank
475
+ * name); `timePeriod` is the same descriptive value column the legacy
476
+ * T{n} scheme used, kept for period-labeling and legacy provenance lookup
477
+ * (SYS-2886 Phase 5) -- no longer the row's key. Metric fields are the
478
+ * category's own base (unsuffixed) column names.
479
+ */
480
+ interface InstanceRow {
481
+ instanceKey: string;
482
+ sourceLabel?: string | null;
483
+ timePeriod?: string | null;
484
+ [metricKey: string]: unknown;
485
+ }
452
486
  /**
453
487
  * Per-document File metadata attached by finsys-api `getIhsDetailsById` as the
454
488
  * `documentMetadata` sibling map (SYS-2765), keyed by the document's raw stored
@@ -530,6 +564,31 @@ declare function groupColumnsByTimePeriod(columnNames: string[]): Record<string,
530
564
  declare function groupFieldsByPattern(fields: FieldData[]): Record<string, FieldData[]>;
531
565
  declare function getGroupDisplayNames(): Record<string, string>;
532
566
  declare function buildFileFieldTables(ihsData: Record<string, unknown>, fieldProvenance?: Record<string, IhsFieldProvenance>): Record<string, FileFieldTableData>;
567
+ /**
568
+ * Groups instance rows by base metric name -- the unbounded analog of
569
+ * groupColumnsByTimePeriod. `baseColumnNames` is the category's base
570
+ * (unsuffixed) field list; each returned group maps instance column
571
+ * label -> that metric's value on that row. Labels are disambiguated
572
+ * (see instanceColumnLabels) so two rows can never collide into the
573
+ * same key.
574
+ */
575
+ declare function groupColumnsByInstance(baseColumnNames: string[], instanceRows: InstanceRow[]): Record<string, Record<string, unknown>>;
576
+ /**
577
+ * Explicit base-column declaration for a category with NO catalog `file`
578
+ * spec -- e.g. invoice (SYS-2842 Phase 3), which was deliberately never
579
+ * registered in form-field-base-specs.json because getDocumentTypeGroups()
580
+ * is shared with resolveExtractionStatus, which assumes a category's wide-
581
+ * table columns exist to check "is this populated" against -- invoice has
582
+ * none (sibling-table only, no wideTableMirror). Registering it there would
583
+ * silently break resolveExtractionStatus's invoice status reporting. This
584
+ * override lets a category be instance-rendered without entering that
585
+ * shared registry at all.
586
+ */
587
+ interface CategorySpec {
588
+ displayName: string;
589
+ baseColumnNames: string[];
590
+ }
591
+ declare function buildFileFieldTablesFromInstances(instancesByCategory?: Record<string, InstanceRow[]>, fieldProvenance?: Record<string, IhsFieldProvenance>, categoryOverrides?: Record<string, CategorySpec>): Record<string, FileFieldTableData>;
533
592
  /** IHS doc-field key → human label (the fields that become document sections). */
534
593
  declare function getDocDisplayNames(): Record<string, string>;
535
594
  /** Doc types eligible for extraction (re-extract / view-JSON). */
@@ -652,11 +711,19 @@ declare function assertDocumentType(id: string): string;
652
711
  * Lender rejection is not represented by a distinct status: when a lender
653
712
  * rejects an application, finsys-api transitions the record back to
654
713
  * `APPLICATION_FINALIZED` from `LENDER_EVALUATION`.
714
+ *
715
+ * `EditingApplication` (SYS-2806) is a lender-scoped detour off
716
+ * `LenderEvaluation` for manually editing extracted field values — not
717
+ * reachable from `ApplicationFinalized`. A lender toggles into it and back
718
+ * out to `LenderEvaluation`; it never appears on a record no lender has
719
+ * claimed. See finsys-api's `updateIhsStatusByLender` for the transition
720
+ * guard.
655
721
  */
656
722
  declare enum IhsStatus {
657
723
  CreatingApplication = "CREATING_APPLICATION",
658
724
  ApplicationFinalized = "APPLICATION_FINALIZED",
659
725
  LenderEvaluation = "LENDER_EVALUATION",
726
+ EditingApplication = "EDITING_APPLICATION",
660
727
  Approved = "APPROVED",
661
728
  LouDelivered = "LOU_DELIVERED",
662
729
  AwaitingDisbursement = "AWAITING_DISBURSEMENT",
@@ -923,6 +990,30 @@ interface AdapterExtraction {
923
990
  * The canonical field values for this instance.
924
991
  */
925
992
  readonly values: CanonicalFieldValues;
993
+ /**
994
+ * SYS-2502: when this instance's data was OBSERVED at the source
995
+ * (ISO-8601) — the statement's own date, the partner snapshot's
996
+ * timestamp — as distinct from when the adapter RAN. Optional for
997
+ * backward compatibility with already-shipped adapters (the host
998
+ * falls back to the run's ranAt when absent, exactly the inference
999
+ * it always did), but new adapters should treat it as required:
1000
+ * ranAt-inference conflates "when we fetched" with "when it was
1001
+ * true", which corrupts recency ordering for backfilled or delayed
1002
+ * data. Expected to become mandatory at the next major version.
1003
+ */
1004
+ readonly observedAt?: string;
1005
+ /**
1006
+ * SYS-2502 (prototyped in finsys-api under SYS-2977): optional
1007
+ * per-field extraction confidence, 0..1, keyed by canonical field
1008
+ * name. This is the provenance slot SYS-2819 identified as the
1009
+ * missing precondition for FinXtract-as-adapter — probabilistic
1010
+ * extractors (OCR/LLM) carry real per-field confidence; partner-API
1011
+ * adapters (a telco returning a number) simply omit it. `null` marks
1012
+ * a field whose value is derived/computed rather than directly
1013
+ * extracted (renders as "no confidence" rather than low confidence,
1014
+ * matching IhsFieldProvenance.origin semantics).
1015
+ */
1016
+ readonly confidence?: Partial<Record<CanonicalFieldName, number | null>>;
926
1017
  }
927
1018
  /**
928
1019
  * Allowed value shapes for canonical fields. Per-field type narrowing
@@ -1316,8 +1407,47 @@ interface AdapterManifest {
1316
1407
  * code is loaded.
1317
1408
  * - `typescript` — TS/JS adapter; `entryPoint` is required, the
1318
1409
  * host imports it dynamically.
1410
+ * - `form-intake` — SYS-2501: data-only adapter declaring
1411
+ * form-field-id → canonical-field mappings. No code is loaded and
1412
+ * no fetch()/extract() ever runs; the host's form submission
1413
+ * handler IS the runtime, and this manifest is how a
1414
+ * borrower-entered scalar becomes a canonical, provenance-carrying
1415
+ * field instead of a hand-wired column write.
1416
+ * - `manual-override` — SYS-2501: data-only adapter declaring that
1417
+ * this category's fields may be operator-overridden
1418
+ * post-extraction. `produces` IS the override surface (a separate
1419
+ * list could only duplicate or contradict it); the host's
1420
+ * override endpoints gate on membership.
1421
+ */
1422
+ readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation;
1423
+ /**
1424
+ * SYS-2502: explicit instance cardinality.
1425
+ *
1426
+ * - `single` — at most one instance per applicant; extract() returns
1427
+ * one AdapterExtraction with `instanceKey: ""`.
1428
+ * - `multi` — unbounded instances per applicant, each with a stable,
1429
+ * non-empty instanceKey.
1430
+ *
1431
+ * OPTIONAL for backward compatibility: manifests written before this
1432
+ * field existed rely on the original implicit convention
1433
+ * (instanceKey `""` → single, non-empty → multi), and the host infers
1434
+ * accordingly when the field is absent. New manifests should declare
1435
+ * it — an explicit declaration lets the host REJECT a mismatched
1436
+ * extraction (a multi-keyed instance from a declared-single adapter,
1437
+ * or vice versa) at persistence time instead of silently storing it.
1438
+ */
1439
+ readonly cardinality?: "single" | "multi";
1440
+ /**
1441
+ * SYS-2502: per-applicant singleton fields on a multi-instance
1442
+ * category — fields whose value describes the APPLICANT (one value
1443
+ * regardless of how many instances exist) rather than the instance,
1444
+ * e.g. accountHolderName on bank statements. Every entry MUST also
1445
+ * appear in `produces` (host validates at registration, same as
1446
+ * `produces` ⊆ category fields). Only meaningful when cardinality is
1447
+ * `multi`; the host treats a singleton field's value as shared across
1448
+ * the instance set.
1319
1449
  */
1320
- readonly implementation: DeclarativeImplementation | TypescriptImplementation;
1450
+ readonly singletonFields?: ReadonlyArray<CanonicalFieldName>;
1321
1451
  /**
1322
1452
  * v2.7.0 — partner-specific identity fields the adapter needs from
1323
1453
  * the IHS row when fetch() is invoked. Strings name the keys that
@@ -1365,6 +1495,45 @@ interface TypescriptImplementation {
1365
1495
  */
1366
1496
  readonly entryPoint: string;
1367
1497
  }
1498
+ /**
1499
+ * SYS-2501: data-only implementation for borrower/operator form intake.
1500
+ * The manifest declares which form fields feed which canonical fields;
1501
+ * the host's form submission handler applies the mapping — no adapter
1502
+ * code exists to load, and neither fetch() nor extract() ever runs.
1503
+ */
1504
+ interface FormIntakeImplementation {
1505
+ readonly type: "form-intake";
1506
+ /**
1507
+ * form-field-id → canonical-field mappings. `formFieldId` is the form
1508
+ * spec's field name (the same identifier UnifiedFormConfig fields
1509
+ * carry); `canonical` MUST be declared by the adapter's category —
1510
+ * host validates at registration, exactly like declarative fieldMap
1511
+ * entries. Values arrive already typed from the form layer, so there
1512
+ * is deliberately no transform slot here: a form field needing value
1513
+ * transformation is a form-spec concern, not an adapter one.
1514
+ */
1515
+ readonly fieldMap: ReadonlyArray<FormIntakeFieldMapEntry>;
1516
+ }
1517
+ interface FormIntakeFieldMapEntry {
1518
+ /** The form spec's field name this mapping consumes. */
1519
+ readonly formFieldId: string;
1520
+ /**
1521
+ * Canonical field name this maps to. MUST be declared by the
1522
+ * adapter's category. Host validates at registration.
1523
+ */
1524
+ readonly canonical: CanonicalFieldName;
1525
+ }
1526
+ /**
1527
+ * SYS-2501: data-only implementation declaring that the adapter's
1528
+ * `produces` list is operator-overridable post-extraction. The manifest
1529
+ * gates the override surface; the host's override endpoints check
1530
+ * membership in `produces` before accepting a manual value. No code, no
1531
+ * fetch(), no extract() — the discriminator alone carries the meaning,
1532
+ * so this shape is intentionally empty beyond `type`.
1533
+ */
1534
+ interface ManualOverrideImplementation {
1535
+ readonly type: "manual-override";
1536
+ }
1368
1537
  interface FieldMapEntry {
1369
1538
  /**
1370
1539
  * JSONPath expression into the raw payload. E.g.
@@ -1392,4 +1561,4 @@ interface FieldMapEntry {
1392
1561
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1393
1562
  }
1394
1563
 
1395
- export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceValue, type PageConfig, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
1564
+ export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type CategorySpec, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, type FormIntakeFieldMapEntry, type FormIntakeImplementation, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_FIELD_ORIGINS, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldOrigin, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceRow, type InstanceValue, type ManualOverrideImplementation, type PageConfig, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, buildFileFieldTablesFromInstances, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByInstance, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsFieldOrigin, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
package/dist/index.d.ts CHANGED
@@ -416,16 +416,34 @@ declare enum FileFieldTableType {
416
416
  * observedAt — ISO wall-clock of the extraction run
417
417
  * sourceRunId — the extraction run/job id that wrote it
418
418
  * origin — "extracted" (a real {value,confidence} leaf) vs "derived"
419
- * (computed / no-confidence path). A "derived" field must render
420
- * as "no confidence available", never a fabricated low score.
419
+ * (computed / no-confidence path) vs "manual" (SYS-2806, a
420
+ * lender-entered correction, committed once its edit overlay
421
+ * is approved). A "derived" field must render as "no
422
+ * confidence available", never a fabricated low score; a
423
+ * "manual" field must render as an edit indicator, not a
424
+ * confidence dot — confidence is always null for it too.
421
425
  */
426
+ /**
427
+ * Canonical origin values, single source of truth (Gemini-review finding:
428
+ * avoids duplicating the literal strings between the type and the runtime
429
+ * guard) -- mirrors the IhsStatus/IHS_VALID_STATUSES pattern in
430
+ * ihs-status.ts.
431
+ */
432
+ declare const IHS_FIELD_ORIGINS: readonly ["extracted", "derived", "manual"];
433
+ type IhsFieldOrigin = (typeof IHS_FIELD_ORIGINS)[number];
422
434
  interface IhsFieldProvenance {
423
435
  source: string;
424
436
  confidence: number | null;
425
437
  observedAt: string;
426
438
  sourceRunId: string | null;
427
- origin: 'extracted' | 'derived';
439
+ origin: IhsFieldOrigin;
428
440
  }
441
+ /**
442
+ * Type guard: narrows an unknown value to `IhsFieldOrigin` iff it is one of
443
+ * the three canonical origin strings. `origin` was previously validated
444
+ * only by the TS union — this is the first runtime check.
445
+ */
446
+ declare function isValidIhsFieldOrigin(origin: unknown): origin is IhsFieldOrigin;
429
447
  interface FileFieldTableItem {
430
448
  displayName: string;
431
449
  timePeriods: string[];
@@ -449,6 +467,22 @@ interface FileFieldTableData {
449
467
  items: FileFieldTableItem[];
450
468
  hasData: boolean;
451
469
  }
470
+ /**
471
+ * One sibling-table row as finsys-api's `docInstanceStorageService` writes
472
+ * it (SYS-2842) -- the unbounded counterpart to a T{n}-suffixed wide-table
473
+ * slot. `instanceKey` is the real, collision-free per-document key;
474
+ * `sourceLabel` is a human label when the doc type has one (e.g. a bank
475
+ * name); `timePeriod` is the same descriptive value column the legacy
476
+ * T{n} scheme used, kept for period-labeling and legacy provenance lookup
477
+ * (SYS-2886 Phase 5) -- no longer the row's key. Metric fields are the
478
+ * category's own base (unsuffixed) column names.
479
+ */
480
+ interface InstanceRow {
481
+ instanceKey: string;
482
+ sourceLabel?: string | null;
483
+ timePeriod?: string | null;
484
+ [metricKey: string]: unknown;
485
+ }
452
486
  /**
453
487
  * Per-document File metadata attached by finsys-api `getIhsDetailsById` as the
454
488
  * `documentMetadata` sibling map (SYS-2765), keyed by the document's raw stored
@@ -530,6 +564,31 @@ declare function groupColumnsByTimePeriod(columnNames: string[]): Record<string,
530
564
  declare function groupFieldsByPattern(fields: FieldData[]): Record<string, FieldData[]>;
531
565
  declare function getGroupDisplayNames(): Record<string, string>;
532
566
  declare function buildFileFieldTables(ihsData: Record<string, unknown>, fieldProvenance?: Record<string, IhsFieldProvenance>): Record<string, FileFieldTableData>;
567
+ /**
568
+ * Groups instance rows by base metric name -- the unbounded analog of
569
+ * groupColumnsByTimePeriod. `baseColumnNames` is the category's base
570
+ * (unsuffixed) field list; each returned group maps instance column
571
+ * label -> that metric's value on that row. Labels are disambiguated
572
+ * (see instanceColumnLabels) so two rows can never collide into the
573
+ * same key.
574
+ */
575
+ declare function groupColumnsByInstance(baseColumnNames: string[], instanceRows: InstanceRow[]): Record<string, Record<string, unknown>>;
576
+ /**
577
+ * Explicit base-column declaration for a category with NO catalog `file`
578
+ * spec -- e.g. invoice (SYS-2842 Phase 3), which was deliberately never
579
+ * registered in form-field-base-specs.json because getDocumentTypeGroups()
580
+ * is shared with resolveExtractionStatus, which assumes a category's wide-
581
+ * table columns exist to check "is this populated" against -- invoice has
582
+ * none (sibling-table only, no wideTableMirror). Registering it there would
583
+ * silently break resolveExtractionStatus's invoice status reporting. This
584
+ * override lets a category be instance-rendered without entering that
585
+ * shared registry at all.
586
+ */
587
+ interface CategorySpec {
588
+ displayName: string;
589
+ baseColumnNames: string[];
590
+ }
591
+ declare function buildFileFieldTablesFromInstances(instancesByCategory?: Record<string, InstanceRow[]>, fieldProvenance?: Record<string, IhsFieldProvenance>, categoryOverrides?: Record<string, CategorySpec>): Record<string, FileFieldTableData>;
533
592
  /** IHS doc-field key → human label (the fields that become document sections). */
534
593
  declare function getDocDisplayNames(): Record<string, string>;
535
594
  /** Doc types eligible for extraction (re-extract / view-JSON). */
@@ -652,11 +711,19 @@ declare function assertDocumentType(id: string): string;
652
711
  * Lender rejection is not represented by a distinct status: when a lender
653
712
  * rejects an application, finsys-api transitions the record back to
654
713
  * `APPLICATION_FINALIZED` from `LENDER_EVALUATION`.
714
+ *
715
+ * `EditingApplication` (SYS-2806) is a lender-scoped detour off
716
+ * `LenderEvaluation` for manually editing extracted field values — not
717
+ * reachable from `ApplicationFinalized`. A lender toggles into it and back
718
+ * out to `LenderEvaluation`; it never appears on a record no lender has
719
+ * claimed. See finsys-api's `updateIhsStatusByLender` for the transition
720
+ * guard.
655
721
  */
656
722
  declare enum IhsStatus {
657
723
  CreatingApplication = "CREATING_APPLICATION",
658
724
  ApplicationFinalized = "APPLICATION_FINALIZED",
659
725
  LenderEvaluation = "LENDER_EVALUATION",
726
+ EditingApplication = "EDITING_APPLICATION",
660
727
  Approved = "APPROVED",
661
728
  LouDelivered = "LOU_DELIVERED",
662
729
  AwaitingDisbursement = "AWAITING_DISBURSEMENT",
@@ -923,6 +990,30 @@ interface AdapterExtraction {
923
990
  * The canonical field values for this instance.
924
991
  */
925
992
  readonly values: CanonicalFieldValues;
993
+ /**
994
+ * SYS-2502: when this instance's data was OBSERVED at the source
995
+ * (ISO-8601) — the statement's own date, the partner snapshot's
996
+ * timestamp — as distinct from when the adapter RAN. Optional for
997
+ * backward compatibility with already-shipped adapters (the host
998
+ * falls back to the run's ranAt when absent, exactly the inference
999
+ * it always did), but new adapters should treat it as required:
1000
+ * ranAt-inference conflates "when we fetched" with "when it was
1001
+ * true", which corrupts recency ordering for backfilled or delayed
1002
+ * data. Expected to become mandatory at the next major version.
1003
+ */
1004
+ readonly observedAt?: string;
1005
+ /**
1006
+ * SYS-2502 (prototyped in finsys-api under SYS-2977): optional
1007
+ * per-field extraction confidence, 0..1, keyed by canonical field
1008
+ * name. This is the provenance slot SYS-2819 identified as the
1009
+ * missing precondition for FinXtract-as-adapter — probabilistic
1010
+ * extractors (OCR/LLM) carry real per-field confidence; partner-API
1011
+ * adapters (a telco returning a number) simply omit it. `null` marks
1012
+ * a field whose value is derived/computed rather than directly
1013
+ * extracted (renders as "no confidence" rather than low confidence,
1014
+ * matching IhsFieldProvenance.origin semantics).
1015
+ */
1016
+ readonly confidence?: Partial<Record<CanonicalFieldName, number | null>>;
926
1017
  }
927
1018
  /**
928
1019
  * Allowed value shapes for canonical fields. Per-field type narrowing
@@ -1316,8 +1407,47 @@ interface AdapterManifest {
1316
1407
  * code is loaded.
1317
1408
  * - `typescript` — TS/JS adapter; `entryPoint` is required, the
1318
1409
  * host imports it dynamically.
1410
+ * - `form-intake` — SYS-2501: data-only adapter declaring
1411
+ * form-field-id → canonical-field mappings. No code is loaded and
1412
+ * no fetch()/extract() ever runs; the host's form submission
1413
+ * handler IS the runtime, and this manifest is how a
1414
+ * borrower-entered scalar becomes a canonical, provenance-carrying
1415
+ * field instead of a hand-wired column write.
1416
+ * - `manual-override` — SYS-2501: data-only adapter declaring that
1417
+ * this category's fields may be operator-overridden
1418
+ * post-extraction. `produces` IS the override surface (a separate
1419
+ * list could only duplicate or contradict it); the host's
1420
+ * override endpoints gate on membership.
1421
+ */
1422
+ readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation;
1423
+ /**
1424
+ * SYS-2502: explicit instance cardinality.
1425
+ *
1426
+ * - `single` — at most one instance per applicant; extract() returns
1427
+ * one AdapterExtraction with `instanceKey: ""`.
1428
+ * - `multi` — unbounded instances per applicant, each with a stable,
1429
+ * non-empty instanceKey.
1430
+ *
1431
+ * OPTIONAL for backward compatibility: manifests written before this
1432
+ * field existed rely on the original implicit convention
1433
+ * (instanceKey `""` → single, non-empty → multi), and the host infers
1434
+ * accordingly when the field is absent. New manifests should declare
1435
+ * it — an explicit declaration lets the host REJECT a mismatched
1436
+ * extraction (a multi-keyed instance from a declared-single adapter,
1437
+ * or vice versa) at persistence time instead of silently storing it.
1438
+ */
1439
+ readonly cardinality?: "single" | "multi";
1440
+ /**
1441
+ * SYS-2502: per-applicant singleton fields on a multi-instance
1442
+ * category — fields whose value describes the APPLICANT (one value
1443
+ * regardless of how many instances exist) rather than the instance,
1444
+ * e.g. accountHolderName on bank statements. Every entry MUST also
1445
+ * appear in `produces` (host validates at registration, same as
1446
+ * `produces` ⊆ category fields). Only meaningful when cardinality is
1447
+ * `multi`; the host treats a singleton field's value as shared across
1448
+ * the instance set.
1319
1449
  */
1320
- readonly implementation: DeclarativeImplementation | TypescriptImplementation;
1450
+ readonly singletonFields?: ReadonlyArray<CanonicalFieldName>;
1321
1451
  /**
1322
1452
  * v2.7.0 — partner-specific identity fields the adapter needs from
1323
1453
  * the IHS row when fetch() is invoked. Strings name the keys that
@@ -1365,6 +1495,45 @@ interface TypescriptImplementation {
1365
1495
  */
1366
1496
  readonly entryPoint: string;
1367
1497
  }
1498
+ /**
1499
+ * SYS-2501: data-only implementation for borrower/operator form intake.
1500
+ * The manifest declares which form fields feed which canonical fields;
1501
+ * the host's form submission handler applies the mapping — no adapter
1502
+ * code exists to load, and neither fetch() nor extract() ever runs.
1503
+ */
1504
+ interface FormIntakeImplementation {
1505
+ readonly type: "form-intake";
1506
+ /**
1507
+ * form-field-id → canonical-field mappings. `formFieldId` is the form
1508
+ * spec's field name (the same identifier UnifiedFormConfig fields
1509
+ * carry); `canonical` MUST be declared by the adapter's category —
1510
+ * host validates at registration, exactly like declarative fieldMap
1511
+ * entries. Values arrive already typed from the form layer, so there
1512
+ * is deliberately no transform slot here: a form field needing value
1513
+ * transformation is a form-spec concern, not an adapter one.
1514
+ */
1515
+ readonly fieldMap: ReadonlyArray<FormIntakeFieldMapEntry>;
1516
+ }
1517
+ interface FormIntakeFieldMapEntry {
1518
+ /** The form spec's field name this mapping consumes. */
1519
+ readonly formFieldId: string;
1520
+ /**
1521
+ * Canonical field name this maps to. MUST be declared by the
1522
+ * adapter's category. Host validates at registration.
1523
+ */
1524
+ readonly canonical: CanonicalFieldName;
1525
+ }
1526
+ /**
1527
+ * SYS-2501: data-only implementation declaring that the adapter's
1528
+ * `produces` list is operator-overridable post-extraction. The manifest
1529
+ * gates the override surface; the host's override endpoints check
1530
+ * membership in `produces` before accepting a manual value. No code, no
1531
+ * fetch(), no extract() — the discriminator alone carries the meaning,
1532
+ * so this shape is intentionally empty beyond `type`.
1533
+ */
1534
+ interface ManualOverrideImplementation {
1535
+ readonly type: "manual-override";
1536
+ }
1368
1537
  interface FieldMapEntry {
1369
1538
  /**
1370
1539
  * JSONPath expression into the raw payload. E.g.
@@ -1392,4 +1561,4 @@ interface FieldMapEntry {
1392
1561
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1393
1562
  }
1394
1563
 
1395
- export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceValue, type PageConfig, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };
1564
+ export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, type AdapterExtraction, type AdapterManifest, type AggregationOp, type ApplicantIdentity, BASE_FIELD_SPECS, BasicFormField, type CanonicalFieldName, type CanonicalFieldSpec, type CanonicalFieldValue, type CanonicalFieldValues, type Category, type CategorySchema, type CategorySpec, type Choice, DEFAULT_VALIDATOR_DEFINITIONS, type DeclarativeImplementation, type DocExtractionResult, DocExtractionStatus, type DocumentFileMetadata, type DocumentRow, type DocumentRowCapabilities, type DocumentTypeGroup, type DropdownOption, type EditorValidator, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldData, type FieldGroup, type FieldMapEntry, type FieldReference, FieldType, type FileFieldTableData, type FileFieldTableItem, FileFieldTableType, FileFormField, FormField, FormFieldCategory, type FormFieldInputType, type FormFieldType, type FormFieldTypeDefinitions, FormFieldValidator, type FormIntakeFieldMapEntry, type FormIntakeImplementation, FormSpec, type FormValidatorDefinitions, IHS_FAILURE_STATUSES, IHS_FIELD_ORIGINS, IHS_TERMINAL_STATUSES, IHS_VALID_STATUSES, type IhsDetailCategory, type IhsFieldDetail, type IhsFieldOrigin, type IhsFieldProvenance, IhsStatus, IhsValueFormat, type InstanceRow, type InstanceValue, type ManualOverrideImplementation, type PageConfig, type RHFSchemaOutput, type RHFStep, type RawPayload, type ResolvedField, Role, type SourceAdapter, type SurveyElementJSON, type SurveyJSON, type SurveyPageJSON, type TaggedFieldData, type TimePeriodUnit, type TypescriptImplementation, type UnifiedFormConfig, type Validator, type WireFormat, allCategories, applyAggregation, applyDynamicTitles, assertAdapterCategory, assertDocumentType, buildDocumentRows, buildFileFieldTables, buildFileFieldTablesFromInstances, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, formatDocumentSize, formatDocumentType, formatDocumentUploaded, generateRHFSchema, generateSurveyJson, getBaseCategories, getBaseFieldNames, getBaseFieldSpecMap, getBaseFieldSpecs, getCategoryName, getDisplayName, getDisplayNames, getDocDisplayNames, getDocumentTypeGroups, getExtractableDocTypes, getGroupDisplayNames, getPastMonthLabel, getPastYearLabel, getReuploadableDocTypes, getStepDefaultValues, getStepSchema, groupColumnsByInstance, groupColumnsByTimePeriod, groupDetailsByCategory, groupFieldsByCategory, groupFieldsByPattern, isAdapterCategory, isDocumentType, isFailureIhsStatus, isTerminalIhsStatus, isValidIhsFieldOrigin, isValidIhsStatus, parseFileField, processIhsDetails, resolveExtractionStatus, resolvePageFields, validateFormConfig, validateFormSpec, validatePagesConfig };