@finsys/core 4.6.0 → 4.7.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
@@ -842,6 +842,19 @@ interface CanonicalFieldSpec {
842
842
  readonly unit?: string;
843
843
  readonly range?: readonly [number, number];
844
844
  readonly description: string;
845
+ /**
846
+ * Global fact identifier marking this field as an ATTESTATION of a
847
+ * shared real-world fact (e.g. a company has exactly one
848
+ * incorporation date, no matter which document it was extracted
849
+ * from). Multiple categories may declare the SAME field name iff
850
+ * every declaring category carries the same `fact` id — each
851
+ * category's value is then an independent attestation of one fact,
852
+ * comparable across sources (the future disagreement-comparison
853
+ * feature's unit of comparison). A `fact` id is bound to exactly one
854
+ * field name registry-wide; by convention the field name IS the fact
855
+ * id. Uniquely-declared fields need no `fact` (but may carry one).
856
+ */
857
+ readonly fact?: string;
845
858
  }
846
859
  /**
847
860
  * Per-category schema bundle. Used by:
@@ -883,11 +896,30 @@ declare function allCategories(): ReadonlyArray<CategorySchema>;
883
896
  /**
884
897
  * Reverse lookup: which category declares a given canonical field?
885
898
  * Returns null if the field name isn't declared by any category in
886
- * this version of finsys-core. Useful when the host app is reading
887
- * canonical field values back from storage + wants to identify the
888
- * producing category for rendering. O(1).
899
+ * this version of finsys-core AND for shared-fact names (declared by
900
+ * more than one category), where "the" category is genuinely ambiguous.
901
+ * The null is deliberate: a caller holding a shared-fact name must
902
+ * decide per-attestation, via `categoriesAttestingFact(factOf(name))`,
903
+ * rather than being handed one arbitrary declarer. Useful when the
904
+ * host app is reading canonical field values back from storage + wants
905
+ * to identify the producing category for rendering. O(1).
889
906
  */
890
907
  declare function categoryForField(field: CanonicalFieldName): AdapterCategory | null;
908
+ /**
909
+ * The fact id a canonical field attests, or null when the field
910
+ * declares no fact (or isn't declared at all). By convention the fact
911
+ * id equals the field name, but callers must not assume it — read it
912
+ * from here. O(1).
913
+ */
914
+ declare function factOf(field: CanonicalFieldName): string | null;
915
+ /**
916
+ * Every category attesting a given shared fact, in data-file order.
917
+ * Empty for an unknown fact id. This is the lookup the disagreement-
918
+ * comparison feature keys on: each attesting category's value for the
919
+ * fact's field is an independent observation of the same real-world
920
+ * fact, so cross-category mismatches are surfaceable.
921
+ */
922
+ declare function categoriesAttestingFact(factId: string): ReadonlyArray<AdapterCategory>;
891
923
  /**
892
924
  * Runtime membership check — is `id` a category declared by this
893
925
  * version of finsys-core? Use this at trust boundaries (parsing a
@@ -1740,4 +1772,4 @@ interface FieldMapEntry {
1740
1772
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1741
1773
  }
1742
1774
 
1743
- 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, 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 };
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 };
package/dist/index.d.ts CHANGED
@@ -842,6 +842,19 @@ interface CanonicalFieldSpec {
842
842
  readonly unit?: string;
843
843
  readonly range?: readonly [number, number];
844
844
  readonly description: string;
845
+ /**
846
+ * Global fact identifier marking this field as an ATTESTATION of a
847
+ * shared real-world fact (e.g. a company has exactly one
848
+ * incorporation date, no matter which document it was extracted
849
+ * from). Multiple categories may declare the SAME field name iff
850
+ * every declaring category carries the same `fact` id — each
851
+ * category's value is then an independent attestation of one fact,
852
+ * comparable across sources (the future disagreement-comparison
853
+ * feature's unit of comparison). A `fact` id is bound to exactly one
854
+ * field name registry-wide; by convention the field name IS the fact
855
+ * id. Uniquely-declared fields need no `fact` (but may carry one).
856
+ */
857
+ readonly fact?: string;
845
858
  }
846
859
  /**
847
860
  * Per-category schema bundle. Used by:
@@ -883,11 +896,30 @@ declare function allCategories(): ReadonlyArray<CategorySchema>;
883
896
  /**
884
897
  * Reverse lookup: which category declares a given canonical field?
885
898
  * Returns null if the field name isn't declared by any category in
886
- * this version of finsys-core. Useful when the host app is reading
887
- * canonical field values back from storage + wants to identify the
888
- * producing category for rendering. O(1).
899
+ * this version of finsys-core AND for shared-fact names (declared by
900
+ * more than one category), where "the" category is genuinely ambiguous.
901
+ * The null is deliberate: a caller holding a shared-fact name must
902
+ * decide per-attestation, via `categoriesAttestingFact(factOf(name))`,
903
+ * rather than being handed one arbitrary declarer. Useful when the
904
+ * host app is reading canonical field values back from storage + wants
905
+ * to identify the producing category for rendering. O(1).
889
906
  */
890
907
  declare function categoryForField(field: CanonicalFieldName): AdapterCategory | null;
908
+ /**
909
+ * The fact id a canonical field attests, or null when the field
910
+ * declares no fact (or isn't declared at all). By convention the fact
911
+ * id equals the field name, but callers must not assume it — read it
912
+ * from here. O(1).
913
+ */
914
+ declare function factOf(field: CanonicalFieldName): string | null;
915
+ /**
916
+ * Every category attesting a given shared fact, in data-file order.
917
+ * Empty for an unknown fact id. This is the lookup the disagreement-
918
+ * comparison feature keys on: each attesting category's value for the
919
+ * fact's field is an independent observation of the same real-world
920
+ * fact, so cross-category mismatches are surfaceable.
921
+ */
922
+ declare function categoriesAttestingFact(factId: string): ReadonlyArray<AdapterCategory>;
891
923
  /**
892
924
  * Runtime membership check — is `id` a category declared by this
893
925
  * version of finsys-core? Use this at trust boundaries (parsing a
@@ -1740,4 +1772,4 @@ interface FieldMapEntry {
1740
1772
  readonly transform?: "identity" | "pct_to_ratio01" | "to_boolean" | "to_integer";
1741
1773
  }
1742
1774
 
1743
- 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, 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 };
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 };
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.0.0",
10214
+ schemaVersion: "1.1.0",
10215
10215
  categories: [
10216
10216
  {
10217
10217
  id: "telco-carrier",
@@ -10865,7 +10865,8 @@ var adapter_categories_default = {
10865
10865
  {
10866
10866
  name: "companyName",
10867
10867
  type: "string",
10868
- description: "Company name as stated on the document."
10868
+ fact: "companyName",
10869
+ description: "Company name as stated on the document. Attestation of the shared companyName fact \u2014 the SSM Form 9 extraction category attests the same fact from its own document."
10869
10870
  },
10870
10871
  {
10871
10872
  name: "financialYearEnd",
@@ -11584,6 +11585,121 @@ var adapter_categories_default = {
11584
11585
  description: "Cash-flow statement: cash and cash equivalents at the end of the financial year."
11585
11586
  }
11586
11587
  ]
11588
+ },
11589
+ {
11590
+ id: "finxtract-form9",
11591
+ displayName: "SSM Form 9 (Document Extraction)",
11592
+ description: "Fields extracted from an uploaded SSM Form 9 (Certificate of Incorporation of Private Company) document by the host's extraction pipeline. One instance per uploaded document. The company name and incorporation date are attestations of shared facts \u2014 the company-profile and financial-statement extraction categories attest the same real-world facts from their own documents.",
11593
+ canonicalTable: "ihs_alt_data_form9",
11594
+ fields: [
11595
+ {
11596
+ name: "companyName",
11597
+ type: "string",
11598
+ fact: "companyName",
11599
+ description: "Company name as printed on the certificate. Attestation of the shared companyName fact."
11600
+ },
11601
+ {
11602
+ name: "companyRegNo",
11603
+ type: "string",
11604
+ description: "Company registration number as printed on the certificate."
11605
+ },
11606
+ {
11607
+ name: "companyIncorporationDate",
11608
+ type: "string",
11609
+ fact: "companyIncorporationDate",
11610
+ description: "Date of incorporation as printed on the certificate, normalized to ISO YYYY-MM-DD. Attestation of the shared companyIncorporationDate fact \u2014 a company has exactly one incorporation date regardless of which document it was extracted from."
11611
+ }
11612
+ ]
11613
+ },
11614
+ {
11615
+ id: "finxtract-ssm",
11616
+ displayName: "SSM Company Profile (Document Extraction)",
11617
+ description: "Fields extracted from an uploaded SSM company-profile document (company or business registration extract) by the host's extraction pipeline. One instance per uploaded document. Covers registration identity, status, key dates, registered address, capital, and the officer/shareholder registers. The incorporation date is an attestation of a shared fact \u2014 the Form 9 extraction category attests the same real-world fact from its own document.",
11618
+ canonicalTable: "ihs_alt_data_ssm",
11619
+ fields: [
11620
+ {
11621
+ name: "ssmCompanyEntityType",
11622
+ type: "string",
11623
+ description: "Entity type stated on the profile (e.g. private limited company, enterprise)."
11624
+ },
11625
+ {
11626
+ name: "ssmCompanyName",
11627
+ type: "string",
11628
+ description: "Business or company name as stated on the profile."
11629
+ },
11630
+ {
11631
+ name: "ssmCompanyRegNo",
11632
+ type: "string",
11633
+ description: "Business or company registration number as stated on the profile."
11634
+ },
11635
+ {
11636
+ name: "companyStatus",
11637
+ type: "string",
11638
+ description: "Registration status as stated on the profile (e.g. existing, dissolved)."
11639
+ },
11640
+ {
11641
+ name: "businessOrigin",
11642
+ type: "string",
11643
+ description: "Business origin as stated on the profile."
11644
+ },
11645
+ {
11646
+ name: "companyIncorporationDate",
11647
+ type: "string",
11648
+ fact: "companyIncorporationDate",
11649
+ description: "Incorporation (or registration) date as stated on the profile, normalized to ISO YYYY-MM-DD. Attestation of the shared companyIncorporationDate fact \u2014 a company has exactly one incorporation date regardless of which document it was extracted from."
11650
+ },
11651
+ {
11652
+ name: "businessCommencementDate",
11653
+ type: "string",
11654
+ description: "Business commencement (or start) date as stated on the profile, normalized to ISO YYYY-MM-DD."
11655
+ },
11656
+ {
11657
+ name: "businessNature",
11658
+ type: "string",
11659
+ description: "Nature of business as stated on the profile."
11660
+ },
11661
+ {
11662
+ name: "registeredAddress",
11663
+ type: "string",
11664
+ description: "Registered business address as stated on the profile."
11665
+ },
11666
+ {
11667
+ name: "totalShareIssued",
11668
+ type: "number",
11669
+ description: "Total shares issued as stated on the profile."
11670
+ },
11671
+ {
11672
+ name: "ssmPaidUpCapital",
11673
+ type: "number",
11674
+ unit: "MYR",
11675
+ description: "Paid-up capital as stated on the profile (falls back to total shares issued when the profile omits an explicit paid-up figure)."
11676
+ },
11677
+ {
11678
+ name: "directors",
11679
+ type: "string",
11680
+ description: "JSON-encoded list of current directors/officers (for enterprises, the business owner normalized into the same shape)."
11681
+ },
11682
+ {
11683
+ name: "shareholders",
11684
+ type: "string",
11685
+ description: "JSON-encoded list of shareholders (for enterprises, the business owner normalized into the same shape)."
11686
+ },
11687
+ {
11688
+ name: "previousDirectors",
11689
+ type: "string",
11690
+ description: "JSON-encoded list of previous directors/officers."
11691
+ },
11692
+ {
11693
+ name: "companyLastOldName",
11694
+ type: "string",
11695
+ description: "The company's most recent former name, when the profile records a name change."
11696
+ },
11697
+ {
11698
+ name: "companyNameDateOfChange",
11699
+ type: "string",
11700
+ description: "Date of the most recent name change, normalized to ISO YYYY-MM-DD."
11701
+ }
11702
+ ]
11587
11703
  }
11588
11704
  ]
11589
11705
  };
@@ -11606,6 +11722,9 @@ function buildCategoryRegistry(raw) {
11606
11722
  }
11607
11723
  const byId = /* @__PURE__ */ new Map();
11608
11724
  const fieldToCategory = /* @__PURE__ */ new Map();
11725
+ const fieldToFact = /* @__PURE__ */ new Map();
11726
+ const factToCategories = /* @__PURE__ */ new Map();
11727
+ const declarations = /* @__PURE__ */ new Map();
11609
11728
  const tables = /* @__PURE__ */ new Set();
11610
11729
  const all = [];
11611
11730
  for (const cat of raw.categories) {
@@ -11640,11 +11759,34 @@ function buildCategoryRegistry(raw) {
11640
11759
  if (typeof f.name !== "string" || f.name.length === 0) {
11641
11760
  throw new Error(`adapter category data: ${where} has a field with no name`);
11642
11761
  }
11643
- if (fieldToCategory.has(f.name)) {
11762
+ if (f.fact !== void 0 && (typeof f.fact !== "string" || f.fact.length === 0)) {
11644
11763
  throw new Error(
11645
- `adapter category data: canonical field "${f.name}" declared by more than one category (${fieldToCategory.get(f.name)} + ${cat.id}) \u2014 field names must be globally unique`
11764
+ `adapter category data: field "${f.name}" (${where}) has an invalid fact \u2014 expected a non-empty string`
11646
11765
  );
11647
11766
  }
11767
+ const prior = declarations.get(f.name);
11768
+ if (prior) {
11769
+ if (prior.categories.includes(cat.id)) {
11770
+ throw new Error(
11771
+ `adapter category data: ${where} declares field "${f.name}" more than once`
11772
+ );
11773
+ }
11774
+ if (prior.fact === void 0 || f.fact === void 0 || prior.fact !== f.fact) {
11775
+ const describeFact = (fact) => fact === void 0 ? "no fact" : `fact "${fact}"`;
11776
+ throw new Error(
11777
+ `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
+ );
11779
+ }
11780
+ }
11781
+ if (f.fact !== void 0) {
11782
+ for (const [otherName, otherFact] of fieldToFact) {
11783
+ if (otherFact === f.fact && otherName !== f.name) {
11784
+ throw new Error(
11785
+ `adapter category data: fact "${f.fact}" is carried by two different field names ("${otherName}" + "${f.name}") \u2014 a fact id must map to exactly one canonical field name`
11786
+ );
11787
+ }
11788
+ }
11789
+ }
11648
11790
  if (!VALID_FIELD_TYPES.includes(f.type)) {
11649
11791
  throw new Error(
11650
11792
  `adapter category data: field "${f.name}" (${where}) has invalid type "${f.type}"`
@@ -11667,10 +11809,26 @@ function buildCategoryRegistry(raw) {
11667
11809
  type: f.type,
11668
11810
  ...f.unit !== void 0 ? { unit: f.unit } : {},
11669
11811
  ...f.range !== void 0 ? { range: Object.freeze([f.range[0], f.range[1]]) } : {},
11670
- description: f.description
11812
+ description: f.description,
11813
+ ...f.fact !== void 0 ? { fact: f.fact } : {}
11671
11814
  });
11672
11815
  fields.push(spec);
11673
- fieldToCategory.set(f.name, cat.id);
11816
+ if (prior) {
11817
+ prior.categories.push(cat.id);
11818
+ fieldToCategory.delete(f.name);
11819
+ } else {
11820
+ declarations.set(f.name, { fact: f.fact, categories: [cat.id] });
11821
+ fieldToCategory.set(f.name, cat.id);
11822
+ }
11823
+ if (f.fact !== void 0) {
11824
+ fieldToFact.set(f.name, f.fact);
11825
+ const attesters = factToCategories.get(f.fact);
11826
+ if (attesters) {
11827
+ attesters.push(cat.id);
11828
+ } else {
11829
+ factToCategories.set(f.fact, [cat.id]);
11830
+ }
11831
+ }
11674
11832
  }
11675
11833
  const schema = Object.freeze({
11676
11834
  id: cat.id,
@@ -11687,7 +11845,14 @@ function buildCategoryRegistry(raw) {
11687
11845
  all: Object.freeze(all),
11688
11846
  ids: Object.freeze(all.map((c) => c.id)),
11689
11847
  byId,
11690
- fieldToCategory
11848
+ fieldToCategory,
11849
+ fieldToFact,
11850
+ factToCategories: new Map(
11851
+ [...factToCategories].map(([fact, cats]) => [
11852
+ fact,
11853
+ Object.freeze(cats)
11854
+ ])
11855
+ )
11691
11856
  });
11692
11857
  }
11693
11858
  var registry = buildCategoryRegistry(adapter_categories_default);
@@ -11710,6 +11875,12 @@ function allCategories() {
11710
11875
  function categoryForField(field) {
11711
11876
  return registry.fieldToCategory.get(field) ?? null;
11712
11877
  }
11878
+ function factOf(field) {
11879
+ return registry.fieldToFact.get(field) ?? null;
11880
+ }
11881
+ function categoriesAttestingFact(factId) {
11882
+ return registry.factToCategories.get(factId) ?? [];
11883
+ }
11713
11884
  function isAdapterCategory(id) {
11714
11885
  return registry.byId.has(id);
11715
11886
  }
@@ -11753,11 +11924,13 @@ export {
11753
11924
  buildDocumentRows,
11754
11925
  buildFileFieldTables,
11755
11926
  buildFileFieldTablesFromInstances,
11927
+ categoriesAttestingFact,
11756
11928
  categoryFieldsOf,
11757
11929
  categoryForField,
11758
11930
  categorySchemaOf,
11759
11931
  evaluateExpression,
11760
11932
  extractTimePeriods,
11933
+ factOf,
11761
11934
  formatDocumentSize,
11762
11935
  formatDocumentType,
11763
11936
  formatDocumentUploaded,