@finsys/core 4.7.0 → 4.9.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
@@ -855,6 +855,22 @@ interface CanonicalFieldSpec {
855
855
  * id. Uniquely-declared fields need no `fact` (but may carry one).
856
856
  */
857
857
  readonly fact?: string;
858
+ /**
859
+ * Field kind — a semantic refinement of `type`. Currently the only
860
+ * kind is `"enum"`: the field's value is one label out of a closed
861
+ * set. The category declares ONLY that the field is enumerated —
862
+ * never the values, never an ordering. Value sets are vendor
863
+ * territory: each adapter declares the exact labels it emits in its
864
+ * manifest's `enumValues` (host-validated), because two vendors
865
+ * implementing the same category may bucket differently. Ordering
866
+ * and scoring interpretation live even further out, in the consumer
867
+ * (an eval model's per-value mapping) — an enum label is data, what
868
+ * it is worth is opinion, and opinions don't belong in the data
869
+ * contract. An enum field MUST be `type: "string"` (labels are
870
+ * string-normalized) and MUST NOT declare a `range` (labels are
871
+ * unordered).
872
+ */
873
+ readonly kind?: "enum";
858
874
  }
859
875
  /**
860
876
  * Per-category schema bundle. Used by:
@@ -1518,8 +1534,18 @@ interface AdapterManifest {
1518
1534
  * records the adapter runs itself; the manifest exists purely as
1519
1535
  * the declaration plane (produces, cardinality,
1520
1536
  * fieldAuthorizations) for data the host was already producing.
1537
+ * - `external-assertion` — SYS-3036 (ownership moved here from a
1538
+ * host-local extension): declaration-only adapter that is executed
1539
+ * entirely OUTSIDE the host. An externally-orchestrated process
1540
+ * completes its own ceremony/extraction and PUSHES the result to
1541
+ * the host's assertion-ingest surface. No code is loaded and
1542
+ * neither fetch() nor extract() ever runs — the same
1543
+ * declaration-only shape as `form-intake`/`manual-override`/
1544
+ * `extraction-pipeline`, but data arrives via an external push
1545
+ * rather than the host's own pipeline, form submission, or a
1546
+ * dynamic-imported/declarative extract() call.
1521
1547
  */
1522
- readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation | ExtractionPipelineImplementation;
1548
+ readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation | ExtractionPipelineImplementation | ExternalAssertionImplementation;
1523
1549
  /**
1524
1550
  * SYS-2502: explicit instance cardinality.
1525
1551
  *
@@ -1629,6 +1655,45 @@ interface AdapterManifest {
1629
1655
  * adapter is implemented.
1630
1656
  */
1631
1657
  readonly periods?: ReadonlyArray<PeriodDeclaration>;
1658
+ /**
1659
+ * Vendor-specific value sets for the enum-kind fields this adapter
1660
+ * produces. The category declares only THAT a field is enumerated
1661
+ * (`kind: "enum"` — no values, no ordering); the manifest declares
1662
+ * exactly WHICH labels this vendor emits, because two vendors
1663
+ * implementing the same category may bucket differently. Scoring
1664
+ * interpretation lives further out still, in the consumer (an eval
1665
+ * model's per-value mapping with a mandatory fallback) — never here.
1666
+ *
1667
+ * Host-validated at registration (same posture as `produces` ⊆
1668
+ * category fields):
1669
+ * - every key MUST appear in `produces`;
1670
+ * - every key MUST be declared `kind: "enum"` by the adapter's
1671
+ * category — a non-enum field with declared values is refused;
1672
+ * - every enum-kind field in `produces` MUST have an entry here —
1673
+ * an adapter that promises an enum field but not its labels
1674
+ * gives clients nothing to render or map against;
1675
+ * - each value set is a non-empty array of unique, string-
1676
+ * normalized labels (non-empty, no leading/trailing whitespace).
1677
+ *
1678
+ * At runtime the adapter emits labels from its declared set
1679
+ * VERBATIM; the host refuses out-of-set values at ingest, so a
1680
+ * vendor-side vocabulary change is a loud manifest-version bump,
1681
+ * never silent data drift. Clients (form-spec and eval-model
1682
+ * editors) read these sets through the registry-metadata surface to
1683
+ * offer the labels without hardcoding any vendor's vocabulary.
1684
+ *
1685
+ * Matching is EXACT-STRING — case and whitespace variations from a
1686
+ * declared label are treated as distinct (and therefore out-of-set),
1687
+ * deliberately. `uniqueItems` at the schema layer is likewise
1688
+ * exact-match, so e.g. `["High", "high"]` is a legal (if unusual)
1689
+ * two-label set; nothing here folds case or reconciles near-miss
1690
+ * spelling. Silently normalizing would band-aid over a vendor-side
1691
+ * inconsistency instead of surfacing it — a vendor emitting `"high"`
1692
+ * when its manifest declares `"High"` is a vendor bug that should be
1693
+ * refused loudly, not coerced into matching. Vendors own their exact
1694
+ * label byte-for-byte; hosts never guess at reconciliation.
1695
+ */
1696
+ readonly enumValues?: Readonly<Record<CanonicalFieldName, ReadonlyArray<string>>>;
1632
1697
  /**
1633
1698
  * Optional free-form notes — useful for partner-side documentation
1634
1699
  * (where to find the adapter's source, who owns it, what version of
@@ -1745,6 +1810,64 @@ interface ManualOverrideImplementation {
1745
1810
  interface ExtractionPipelineImplementation {
1746
1811
  readonly type: "extraction-pipeline";
1747
1812
  }
1813
+ /**
1814
+ * SYS-3036: declaration-only implementation for adapters that are
1815
+ * executed entirely OUTSIDE the host application. An externally-
1816
+ * orchestrated process (a partner-run ceremony, an out-of-band
1817
+ * verification flow, etc.) completes its own extraction and PUSHES the
1818
+ * result to the host's assertion-ingest surface, rather than the host
1819
+ * pulling it via `fetch()`/`extract()` or a form submission. No code,
1820
+ * no fetch(), no extract(); like `manual-override` and
1821
+ * `extraction-pipeline`, the discriminator alone carries the meaning —
1822
+ * the shape is intentionally empty beyond `type`.
1823
+ *
1824
+ * Ownership note: this type + its schema branch were previously a
1825
+ * host-local extension (a runtime clone of the compiled schema with one
1826
+ * extra `oneOf` branch bolted on) because core hadn't yet published the
1827
+ * concept. Publishing it here means every host validates the SAME
1828
+ * schema — no more per-host schema patches for this discriminator.
1829
+ */
1830
+ interface ExternalAssertionImplementation {
1831
+ readonly type: "external-assertion";
1832
+ }
1833
+ /**
1834
+ * SYS-3036: how a registered adapter participates at execution time,
1835
+ * derived purely from `implementation.type`. Published here (rather than
1836
+ * re-derived per host) so every host classifies manifests identically:
1837
+ *
1838
+ * - `Runnable` — the host loads (declarative) or dynamic-imports
1839
+ * (typescript) a `SourceAdapter`; the host's run loop executes it.
1840
+ * - `DeclarationOnly` — the manifest is pure declaration plane
1841
+ * (`form-intake`, `manual-override`, `extraction-pipeline`). No code
1842
+ * exists to load; the entry is registered so `list()`-style
1843
+ * consumers (field-authorization gating, provenance rendering,
1844
+ * diagnostics) see the manifest, and every execution path skips it.
1845
+ * - `ExternallyAsserted` — the manifest declares
1846
+ * `implementation.type: "external-assertion"`. Same "no code, host
1847
+ * never calls fetch()/extract()" shape as `DeclarationOnly`, but data
1848
+ * arrives via an external push rather than the host's own
1849
+ * extraction pipeline or form intake. Hosts that used to fork on
1850
+ * this case separately can safely fold it into the same "not
1851
+ * Runnable" branch that already skips `DeclarationOnly` entries.
1852
+ *
1853
+ * String values mirror the discriminators they classify so a logged
1854
+ * `executionMode` reads naturally alongside `implementation.type`.
1855
+ */
1856
+ declare enum AdapterExecutionMode {
1857
+ Runnable = "runnable",
1858
+ DeclarationOnly = "declaration-only",
1859
+ ExternallyAsserted = "externally-asserted"
1860
+ }
1861
+ /**
1862
+ * SYS-3036: classify a manifest's `implementation.type` into its
1863
+ * `AdapterExecutionMode`. Exhaustive over every discriminator this
1864
+ * version of `@finsys/core` publishes — the switch has an explicit case
1865
+ * per type and THROWS on anything else (Ajv should already have refused
1866
+ * an unrecognized discriminator at validation time, but a schema/host
1867
+ * version skew must surface as a loud refusal here too, never as a
1868
+ * silently-guessed mode; no fallback branch assigns one).
1869
+ */
1870
+ declare function executionModeOf(manifest: Pick<AdapterManifest, "implementation">): AdapterExecutionMode;
1748
1871
  interface FieldMapEntry {
1749
1872
  /**
1750
1873
  * JSONPath expression into the raw payload. E.g.
@@ -1772,4 +1895,4 @@ interface FieldMapEntry {
1772
1895
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1773
1896
  }
1774
1897
 
1775
- 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 ExtractionPipelineImplementation, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, 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 PeriodDeclaration, type PeriodValues, 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, categoriesAttestingFact, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, factOf, 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 };
1898
+ export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, AdapterExecutionMode, 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 ExternalAssertionImplementation, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionPipelineImplementation, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, 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 PeriodDeclaration, type PeriodValues, 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, categoriesAttestingFact, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, executionModeOf, extractTimePeriods, factOf, 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
@@ -855,6 +855,22 @@ interface CanonicalFieldSpec {
855
855
  * id. Uniquely-declared fields need no `fact` (but may carry one).
856
856
  */
857
857
  readonly fact?: string;
858
+ /**
859
+ * Field kind — a semantic refinement of `type`. Currently the only
860
+ * kind is `"enum"`: the field's value is one label out of a closed
861
+ * set. The category declares ONLY that the field is enumerated —
862
+ * never the values, never an ordering. Value sets are vendor
863
+ * territory: each adapter declares the exact labels it emits in its
864
+ * manifest's `enumValues` (host-validated), because two vendors
865
+ * implementing the same category may bucket differently. Ordering
866
+ * and scoring interpretation live even further out, in the consumer
867
+ * (an eval model's per-value mapping) — an enum label is data, what
868
+ * it is worth is opinion, and opinions don't belong in the data
869
+ * contract. An enum field MUST be `type: "string"` (labels are
870
+ * string-normalized) and MUST NOT declare a `range` (labels are
871
+ * unordered).
872
+ */
873
+ readonly kind?: "enum";
858
874
  }
859
875
  /**
860
876
  * Per-category schema bundle. Used by:
@@ -1518,8 +1534,18 @@ interface AdapterManifest {
1518
1534
  * records the adapter runs itself; the manifest exists purely as
1519
1535
  * the declaration plane (produces, cardinality,
1520
1536
  * fieldAuthorizations) for data the host was already producing.
1537
+ * - `external-assertion` — SYS-3036 (ownership moved here from a
1538
+ * host-local extension): declaration-only adapter that is executed
1539
+ * entirely OUTSIDE the host. An externally-orchestrated process
1540
+ * completes its own ceremony/extraction and PUSHES the result to
1541
+ * the host's assertion-ingest surface. No code is loaded and
1542
+ * neither fetch() nor extract() ever runs — the same
1543
+ * declaration-only shape as `form-intake`/`manual-override`/
1544
+ * `extraction-pipeline`, but data arrives via an external push
1545
+ * rather than the host's own pipeline, form submission, or a
1546
+ * dynamic-imported/declarative extract() call.
1521
1547
  */
1522
- readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation | ExtractionPipelineImplementation;
1548
+ readonly implementation: DeclarativeImplementation | TypescriptImplementation | FormIntakeImplementation | ManualOverrideImplementation | ExtractionPipelineImplementation | ExternalAssertionImplementation;
1523
1549
  /**
1524
1550
  * SYS-2502: explicit instance cardinality.
1525
1551
  *
@@ -1629,6 +1655,45 @@ interface AdapterManifest {
1629
1655
  * adapter is implemented.
1630
1656
  */
1631
1657
  readonly periods?: ReadonlyArray<PeriodDeclaration>;
1658
+ /**
1659
+ * Vendor-specific value sets for the enum-kind fields this adapter
1660
+ * produces. The category declares only THAT a field is enumerated
1661
+ * (`kind: "enum"` — no values, no ordering); the manifest declares
1662
+ * exactly WHICH labels this vendor emits, because two vendors
1663
+ * implementing the same category may bucket differently. Scoring
1664
+ * interpretation lives further out still, in the consumer (an eval
1665
+ * model's per-value mapping with a mandatory fallback) — never here.
1666
+ *
1667
+ * Host-validated at registration (same posture as `produces` ⊆
1668
+ * category fields):
1669
+ * - every key MUST appear in `produces`;
1670
+ * - every key MUST be declared `kind: "enum"` by the adapter's
1671
+ * category — a non-enum field with declared values is refused;
1672
+ * - every enum-kind field in `produces` MUST have an entry here —
1673
+ * an adapter that promises an enum field but not its labels
1674
+ * gives clients nothing to render or map against;
1675
+ * - each value set is a non-empty array of unique, string-
1676
+ * normalized labels (non-empty, no leading/trailing whitespace).
1677
+ *
1678
+ * At runtime the adapter emits labels from its declared set
1679
+ * VERBATIM; the host refuses out-of-set values at ingest, so a
1680
+ * vendor-side vocabulary change is a loud manifest-version bump,
1681
+ * never silent data drift. Clients (form-spec and eval-model
1682
+ * editors) read these sets through the registry-metadata surface to
1683
+ * offer the labels without hardcoding any vendor's vocabulary.
1684
+ *
1685
+ * Matching is EXACT-STRING — case and whitespace variations from a
1686
+ * declared label are treated as distinct (and therefore out-of-set),
1687
+ * deliberately. `uniqueItems` at the schema layer is likewise
1688
+ * exact-match, so e.g. `["High", "high"]` is a legal (if unusual)
1689
+ * two-label set; nothing here folds case or reconciles near-miss
1690
+ * spelling. Silently normalizing would band-aid over a vendor-side
1691
+ * inconsistency instead of surfacing it — a vendor emitting `"high"`
1692
+ * when its manifest declares `"High"` is a vendor bug that should be
1693
+ * refused loudly, not coerced into matching. Vendors own their exact
1694
+ * label byte-for-byte; hosts never guess at reconciliation.
1695
+ */
1696
+ readonly enumValues?: Readonly<Record<CanonicalFieldName, ReadonlyArray<string>>>;
1632
1697
  /**
1633
1698
  * Optional free-form notes — useful for partner-side documentation
1634
1699
  * (where to find the adapter's source, who owns it, what version of
@@ -1745,6 +1810,64 @@ interface ManualOverrideImplementation {
1745
1810
  interface ExtractionPipelineImplementation {
1746
1811
  readonly type: "extraction-pipeline";
1747
1812
  }
1813
+ /**
1814
+ * SYS-3036: declaration-only implementation for adapters that are
1815
+ * executed entirely OUTSIDE the host application. An externally-
1816
+ * orchestrated process (a partner-run ceremony, an out-of-band
1817
+ * verification flow, etc.) completes its own extraction and PUSHES the
1818
+ * result to the host's assertion-ingest surface, rather than the host
1819
+ * pulling it via `fetch()`/`extract()` or a form submission. No code,
1820
+ * no fetch(), no extract(); like `manual-override` and
1821
+ * `extraction-pipeline`, the discriminator alone carries the meaning —
1822
+ * the shape is intentionally empty beyond `type`.
1823
+ *
1824
+ * Ownership note: this type + its schema branch were previously a
1825
+ * host-local extension (a runtime clone of the compiled schema with one
1826
+ * extra `oneOf` branch bolted on) because core hadn't yet published the
1827
+ * concept. Publishing it here means every host validates the SAME
1828
+ * schema — no more per-host schema patches for this discriminator.
1829
+ */
1830
+ interface ExternalAssertionImplementation {
1831
+ readonly type: "external-assertion";
1832
+ }
1833
+ /**
1834
+ * SYS-3036: how a registered adapter participates at execution time,
1835
+ * derived purely from `implementation.type`. Published here (rather than
1836
+ * re-derived per host) so every host classifies manifests identically:
1837
+ *
1838
+ * - `Runnable` — the host loads (declarative) or dynamic-imports
1839
+ * (typescript) a `SourceAdapter`; the host's run loop executes it.
1840
+ * - `DeclarationOnly` — the manifest is pure declaration plane
1841
+ * (`form-intake`, `manual-override`, `extraction-pipeline`). No code
1842
+ * exists to load; the entry is registered so `list()`-style
1843
+ * consumers (field-authorization gating, provenance rendering,
1844
+ * diagnostics) see the manifest, and every execution path skips it.
1845
+ * - `ExternallyAsserted` — the manifest declares
1846
+ * `implementation.type: "external-assertion"`. Same "no code, host
1847
+ * never calls fetch()/extract()" shape as `DeclarationOnly`, but data
1848
+ * arrives via an external push rather than the host's own
1849
+ * extraction pipeline or form intake. Hosts that used to fork on
1850
+ * this case separately can safely fold it into the same "not
1851
+ * Runnable" branch that already skips `DeclarationOnly` entries.
1852
+ *
1853
+ * String values mirror the discriminators they classify so a logged
1854
+ * `executionMode` reads naturally alongside `implementation.type`.
1855
+ */
1856
+ declare enum AdapterExecutionMode {
1857
+ Runnable = "runnable",
1858
+ DeclarationOnly = "declaration-only",
1859
+ ExternallyAsserted = "externally-asserted"
1860
+ }
1861
+ /**
1862
+ * SYS-3036: classify a manifest's `implementation.type` into its
1863
+ * `AdapterExecutionMode`. Exhaustive over every discriminator this
1864
+ * version of `@finsys/core` publishes — the switch has an explicit case
1865
+ * per type and THROWS on anything else (Ajv should already have refused
1866
+ * an unrecognized discriminator at validation time, but a schema/host
1867
+ * version skew must surface as a loud refusal here too, never as a
1868
+ * silently-guessed mode; no fallback branch assigns one).
1869
+ */
1870
+ declare function executionModeOf(manifest: Pick<AdapterManifest, "implementation">): AdapterExecutionMode;
1748
1871
  interface FieldMapEntry {
1749
1872
  /**
1750
1873
  * JSONPath expression into the raw payload. E.g.
@@ -1772,4 +1895,4 @@ interface FieldMapEntry {
1772
1895
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1773
1896
  }
1774
1897
 
1775
- 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 ExtractionPipelineImplementation, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, 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 PeriodDeclaration, type PeriodValues, 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, categoriesAttestingFact, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, extractTimePeriods, factOf, 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 };
1898
+ export { ADAPTER_CATEGORY_IDS, ALL_AGGREGATION_OPS, type AdapterCategory, AdapterError, type AdapterErrorReason, AdapterExecutionMode, 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 ExternalAssertionImplementation, type ExtractionFileType, type ExtractionJobRecord, ExtractionJobStatus, type ExtractionPipelineImplementation, type ExtractionStatusResult, FIELD_TYPE_DEFINITIONS, type FieldAuthorization, 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 PeriodDeclaration, type PeriodValues, 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, categoriesAttestingFact, categoryFieldsOf, categoryForField, categorySchemaOf, evaluateExpression, executionModeOf, extractTimePeriods, factOf, 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.js CHANGED
@@ -10211,7 +10211,7 @@ function applyAggregation(op, instances) {
10211
10211
 
10212
10212
  // src/data/adapter-categories.json
10213
10213
  var adapter_categories_default = {
10214
- schemaVersion: "1.1.0",
10214
+ schemaVersion: "1.2.0",
10215
10215
  categories: [
10216
10216
  {
10217
10217
  id: "telco-carrier",
@@ -10263,6 +10263,30 @@ var adapter_categories_default = {
10263
10263
  unit: "MYR",
10264
10264
  range: [0, 1e4],
10265
10265
  description: "Average Revenue Per User (monthly) in Malaysian Ringgit. Coarse spending-capacity proxy."
10266
+ },
10267
+ {
10268
+ name: "telcoPaymentReliabilityTier",
10269
+ type: "string",
10270
+ kind: "enum",
10271
+ description: "Coarse bill-payment reliability bucket, for partners that return a tier label instead of a continuous ratio. Parallel signal to telcoOnTimePaymentRatio24m. Labels are vendor-declared (see the adapter manifest's enumValues); ordering and scoring live in the consumer's per-value mapping."
10272
+ },
10273
+ {
10274
+ name: "telcoTenureTier",
10275
+ type: "string",
10276
+ kind: "enum",
10277
+ description: "Coarse account-age bucket, for partners that return a tenure tier label instead of a continuous month count. Parallel signal to telcoTenureMonths. Labels are vendor-declared (see the adapter manifest's enumValues)."
10278
+ },
10279
+ {
10280
+ name: "telcoDistressTier",
10281
+ type: "string",
10282
+ kind: "enum",
10283
+ description: "Coarse account-distress bucket, for partners that return a distress tier label instead of discrete counts. Parallel signal to telcoSuspensionsCount24m / telcoLateDays24m. Labels are vendor-declared (see the adapter manifest's enumValues)."
10284
+ },
10285
+ {
10286
+ name: "telcoHandsetRiskTier",
10287
+ type: "string",
10288
+ kind: "enum",
10289
+ description: "Coarse handset-financing risk bucket, for partners that return a tier label instead of the discrete handset flags. Parallel signal to telcoHandsetFinancingActive / telcoHandsetFinancingDelinquent. Labels are vendor-declared (see the adapter manifest's enumValues)."
10266
10290
  }
10267
10291
  ]
10268
10292
  },
@@ -11710,6 +11734,7 @@ var VALID_FIELD_TYPES = [
11710
11734
  "boolean",
11711
11735
  "string"
11712
11736
  ];
11737
+ var VALID_FIELD_KINDS = ["enum"];
11713
11738
  function buildCategoryRegistry(raw) {
11714
11739
  if (!raw || typeof raw !== "object") {
11715
11740
  throw new Error("adapter category data: expected an object");
@@ -11777,6 +11802,12 @@ function buildCategoryRegistry(raw) {
11777
11802
  `adapter category data: canonical field "${f.name}" declared by more than one category (${prior.categories.join(" + ")} with ${describeFact(prior.fact)} + ${cat.id} with ${describeFact(f.fact)}) \u2014 field names must be globally unique unless every declaring category attests the same fact`
11778
11803
  );
11779
11804
  }
11805
+ if (prior.kind !== f.kind) {
11806
+ const describeKind = (kind) => kind === void 0 ? "no kind" : `kind "${kind}"`;
11807
+ throw new Error(
11808
+ `adapter category data: canonical field "${f.name}" declared with ${describeKind(prior.kind)} by ${prior.categories.join(" + ")} but ${describeKind(f.kind)} by ${cat.id} \u2014 shared-fact attestations must agree on kind`
11809
+ );
11810
+ }
11780
11811
  }
11781
11812
  if (f.fact !== void 0) {
11782
11813
  for (const [otherName, otherFact] of fieldToFact) {
@@ -11792,6 +11823,23 @@ function buildCategoryRegistry(raw) {
11792
11823
  `adapter category data: field "${f.name}" (${where}) has invalid type "${f.type}"`
11793
11824
  );
11794
11825
  }
11826
+ if (f.kind !== void 0) {
11827
+ if (!VALID_FIELD_KINDS.includes(f.kind)) {
11828
+ throw new Error(
11829
+ `adapter category data: field "${f.name}" (${where}) has invalid kind "${String(f.kind)}"`
11830
+ );
11831
+ }
11832
+ if (f.type !== "string") {
11833
+ throw new Error(
11834
+ `adapter category data: field "${f.name}" (${where}) is kind "enum" but type "${f.type}" \u2014 enum labels are string-normalized, so an enum field must be type "string"`
11835
+ );
11836
+ }
11837
+ if (f.range !== void 0) {
11838
+ throw new Error(
11839
+ `adapter category data: field "${f.name}" (${where}) is kind "enum" but declares a range \u2014 enum labels are unordered; ordering belongs to the consumer, never the data contract`
11840
+ );
11841
+ }
11842
+ }
11795
11843
  if (typeof f.description !== "string" || f.description.length === 0) {
11796
11844
  throw new Error(
11797
11845
  `adapter category data: field "${f.name}" (${where}) needs a non-empty description`
@@ -11810,14 +11858,15 @@ function buildCategoryRegistry(raw) {
11810
11858
  ...f.unit !== void 0 ? { unit: f.unit } : {},
11811
11859
  ...f.range !== void 0 ? { range: Object.freeze([f.range[0], f.range[1]]) } : {},
11812
11860
  description: f.description,
11813
- ...f.fact !== void 0 ? { fact: f.fact } : {}
11861
+ ...f.fact !== void 0 ? { fact: f.fact } : {},
11862
+ ...f.kind !== void 0 ? { kind: f.kind } : {}
11814
11863
  });
11815
11864
  fields.push(spec);
11816
11865
  if (prior) {
11817
11866
  prior.categories.push(cat.id);
11818
11867
  fieldToCategory.delete(f.name);
11819
11868
  } else {
11820
- declarations.set(f.name, { fact: f.fact, categories: [cat.id] });
11869
+ declarations.set(f.name, { fact: f.fact, kind: f.kind, categories: [cat.id] });
11821
11870
  fieldToCategory.set(f.name, cat.id);
11822
11871
  }
11823
11872
  if (f.fact !== void 0) {
@@ -11892,10 +11941,37 @@ function assertAdapterCategory(id) {
11892
11941
  }
11893
11942
  return id;
11894
11943
  }
11944
+
11945
+ // src/adapter-manifest.ts
11946
+ var AdapterExecutionMode = /* @__PURE__ */ ((AdapterExecutionMode2) => {
11947
+ AdapterExecutionMode2["Runnable"] = "runnable";
11948
+ AdapterExecutionMode2["DeclarationOnly"] = "declaration-only";
11949
+ AdapterExecutionMode2["ExternallyAsserted"] = "externally-asserted";
11950
+ return AdapterExecutionMode2;
11951
+ })(AdapterExecutionMode || {});
11952
+ function executionModeOf(manifest) {
11953
+ const implementationType = manifest.implementation.type;
11954
+ switch (implementationType) {
11955
+ case "declarative":
11956
+ case "typescript":
11957
+ return "runnable" /* Runnable */;
11958
+ case "form-intake":
11959
+ case "manual-override":
11960
+ case "extraction-pipeline":
11961
+ return "declaration-only" /* DeclarationOnly */;
11962
+ case "external-assertion":
11963
+ return "externally-asserted" /* ExternallyAsserted */;
11964
+ default: {
11965
+ const unhandled = implementationType;
11966
+ throw new Error(`unknown adapter implementation type: ${String(unhandled)}`);
11967
+ }
11968
+ }
11969
+ }
11895
11970
  export {
11896
11971
  ADAPTER_CATEGORY_IDS,
11897
11972
  ALL_AGGREGATION_OPS,
11898
11973
  AdapterError,
11974
+ AdapterExecutionMode,
11899
11975
  BASE_FIELD_SPECS,
11900
11976
  BasicFormField,
11901
11977
  DEFAULT_VALIDATOR_DEFINITIONS,
@@ -11929,6 +12005,7 @@ export {
11929
12005
  categoryForField,
11930
12006
  categorySchemaOf,
11931
12007
  evaluateExpression,
12008
+ executionModeOf,
11932
12009
  extractTimePeriods,
11933
12010
  factOf,
11934
12011
  formatDocumentSize,