Run playwright UI tests

This commit is contained in:
2026-03-06 14:40:43 -05:00
parent 610fce8db3
commit 8e62c66677
37 changed files with 4430 additions and 643 deletions

View File

@@ -15,6 +15,19 @@ type FilingMetrics = {
debt: number | null;
};
type TaxonomyAssetType =
| 'instance'
| 'schema'
| 'presentation'
| 'label'
| 'calculation'
| 'definition'
| 'pdf'
| 'other';
type TaxonomyParseStatus = 'ready' | 'partial' | 'failed';
type TaxonomyMetricValidationStatus = 'not_run' | 'matched' | 'mismatch' | 'error';
type FilingAnalysis = {
provider?: string;
model?: string;
@@ -47,6 +60,7 @@ type FilingStatementPeriod = {
filingId: number;
accessionNumber: string;
filingDate: string;
periodStart: string | null;
periodEnd: string | null;
filingType: '10-K' | '10-Q';
periodLabel: string;
@@ -97,6 +111,55 @@ type DimensionStatementBundle = {
statements: Record<FinancialStatementKind, DimensionStatementSnapshotRow[]>;
};
type TaxonomyDimensionMember = {
axis: string;
member: string;
};
type TaxonomyStatementSnapshotRow = {
key: string;
label: string;
conceptKey: string;
qname: string;
namespaceUri: string;
localName: string;
isExtension: boolean;
statement: FinancialStatementKind;
roleUri: string | null;
order: number;
depth: number;
parentKey: string | null;
values: Record<string, number | null>;
units: Record<string, string | null>;
hasDimensions: boolean;
sourceFactIds: number[];
};
type TaxonomyStatementBundle = {
periods: FilingStatementPeriod[];
statements: Record<FinancialStatementKind, TaxonomyStatementSnapshotRow[]>;
};
type TaxonomyMetricValidationCheck = {
metricKey: keyof FilingMetrics;
taxonomyValue: number | null;
llmValue: number | null;
absoluteDiff: number | null;
relativeDiff: number | null;
status: TaxonomyMetricValidationStatus;
evidencePages: number[];
pdfUrl: string | null;
provider: string | null;
model: string | null;
error: string | null;
};
type TaxonomyMetricValidationResult = {
status: TaxonomyMetricValidationStatus;
checks: TaxonomyMetricValidationCheck[];
validatedAt: string | null;
};
const authDateColumn = {
mode: 'timestamp_ms'
} as const;
@@ -273,6 +336,121 @@ export const filingStatementSnapshot = sqliteTable('filing_statement_snapshot',
filingStatementStatusIndex: index('filing_stmt_status_idx').on(table.parse_status)
}));
export const filingTaxonomySnapshot = sqliteTable('filing_taxonomy_snapshot', {
id: integer('id').primaryKey({ autoIncrement: true }),
filing_id: integer('filing_id').notNull().references(() => filing.id, { onDelete: 'cascade' }),
ticker: text('ticker').notNull(),
filing_date: text('filing_date').notNull(),
filing_type: text('filing_type').$type<'10-K' | '10-Q'>().notNull(),
parse_status: text('parse_status').$type<TaxonomyParseStatus>().notNull(),
parse_error: text('parse_error'),
source: text('source').$type<'xbrl_instance' | 'xbrl_instance_with_linkbase' | 'legacy_html_fallback'>().notNull(),
periods: text('periods', { mode: 'json' }).$type<FilingStatementPeriod[]>(),
statement_rows: text('statement_rows', { mode: 'json' }).$type<TaxonomyStatementBundle['statements'] | null>(),
derived_metrics: text('derived_metrics', { mode: 'json' }).$type<FilingMetrics | null>(),
validation_result: text('validation_result', { mode: 'json' }).$type<TaxonomyMetricValidationResult | null>(),
facts_count: integer('facts_count').notNull().default(0),
concepts_count: integer('concepts_count').notNull().default(0),
dimensions_count: integer('dimensions_count').notNull().default(0),
created_at: text('created_at').notNull(),
updated_at: text('updated_at').notNull()
}, (table) => ({
filingTaxonomySnapshotFilingUnique: uniqueIndex('filing_taxonomy_snapshot_filing_uidx').on(table.filing_id),
filingTaxonomySnapshotTickerDateIndex: index('filing_taxonomy_snapshot_ticker_date_idx').on(table.ticker, table.filing_date),
filingTaxonomySnapshotStatusIndex: index('filing_taxonomy_snapshot_status_idx').on(table.parse_status)
}));
export const filingTaxonomyAsset = sqliteTable('filing_taxonomy_asset', {
id: integer('id').primaryKey({ autoIncrement: true }),
snapshot_id: integer('snapshot_id').notNull().references(() => filingTaxonomySnapshot.id, { onDelete: 'cascade' }),
asset_type: text('asset_type').$type<TaxonomyAssetType>().notNull(),
name: text('name').notNull(),
url: text('url').notNull(),
size_bytes: integer('size_bytes'),
score: numeric('score'),
is_selected: integer('is_selected', { mode: 'boolean' }).notNull().default(false),
created_at: text('created_at').notNull()
}, (table) => ({
filingTaxonomyAssetSnapshotIndex: index('filing_taxonomy_asset_snapshot_idx').on(table.snapshot_id),
filingTaxonomyAssetTypeIndex: index('filing_taxonomy_asset_type_idx').on(table.snapshot_id, table.asset_type)
}));
export const filingTaxonomyConcept = sqliteTable('filing_taxonomy_concept', {
id: integer('id').primaryKey({ autoIncrement: true }),
snapshot_id: integer('snapshot_id').notNull().references(() => filingTaxonomySnapshot.id, { onDelete: 'cascade' }),
concept_key: text('concept_key').notNull(),
qname: text('qname').notNull(),
namespace_uri: text('namespace_uri').notNull(),
local_name: text('local_name').notNull(),
label: text('label'),
is_extension: integer('is_extension', { mode: 'boolean' }).notNull().default(false),
statement_kind: text('statement_kind').$type<FinancialStatementKind>(),
role_uri: text('role_uri'),
presentation_order: numeric('presentation_order'),
presentation_depth: integer('presentation_depth'),
parent_concept_key: text('parent_concept_key'),
is_abstract: integer('is_abstract', { mode: 'boolean' }).notNull().default(false),
created_at: text('created_at').notNull()
}, (table) => ({
filingTaxonomyConceptSnapshotIndex: index('filing_taxonomy_concept_snapshot_idx').on(table.snapshot_id),
filingTaxonomyConceptStatementIndex: index('filing_taxonomy_concept_statement_idx').on(table.snapshot_id, table.statement_kind),
filingTaxonomyConceptUnique: uniqueIndex('filing_taxonomy_concept_uidx').on(
table.snapshot_id,
table.concept_key,
table.role_uri,
table.presentation_order
)
}));
export const filingTaxonomyFact = sqliteTable('filing_taxonomy_fact', {
id: integer('id').primaryKey({ autoIncrement: true }),
snapshot_id: integer('snapshot_id').notNull().references(() => filingTaxonomySnapshot.id, { onDelete: 'cascade' }),
concept_key: text('concept_key').notNull(),
qname: text('qname').notNull(),
namespace_uri: text('namespace_uri').notNull(),
local_name: text('local_name').notNull(),
statement_kind: text('statement_kind').$type<FinancialStatementKind>(),
role_uri: text('role_uri'),
context_id: text('context_id').notNull(),
unit: text('unit'),
decimals: text('decimals'),
value_num: numeric('value_num').notNull(),
period_start: text('period_start'),
period_end: text('period_end'),
period_instant: text('period_instant'),
dimensions: text('dimensions', { mode: 'json' }).$type<TaxonomyDimensionMember[]>().notNull(),
is_dimensionless: integer('is_dimensionless', { mode: 'boolean' }).notNull().default(true),
source_file: text('source_file'),
created_at: text('created_at').notNull()
}, (table) => ({
filingTaxonomyFactSnapshotIndex: index('filing_taxonomy_fact_snapshot_idx').on(table.snapshot_id),
filingTaxonomyFactConceptIndex: index('filing_taxonomy_fact_concept_idx').on(table.snapshot_id, table.concept_key),
filingTaxonomyFactPeriodIndex: index('filing_taxonomy_fact_period_idx').on(table.snapshot_id, table.period_end, table.period_instant),
filingTaxonomyFactStatementIndex: index('filing_taxonomy_fact_statement_idx').on(table.snapshot_id, table.statement_kind)
}));
export const filingTaxonomyMetricValidation = sqliteTable('filing_taxonomy_metric_validation', {
id: integer('id').primaryKey({ autoIncrement: true }),
snapshot_id: integer('snapshot_id').notNull().references(() => filingTaxonomySnapshot.id, { onDelete: 'cascade' }),
metric_key: text('metric_key').$type<keyof FilingMetrics>().notNull(),
taxonomy_value: numeric('taxonomy_value'),
llm_value: numeric('llm_value'),
absolute_diff: numeric('absolute_diff'),
relative_diff: numeric('relative_diff'),
status: text('status').$type<TaxonomyMetricValidationStatus>().notNull(),
evidence_pages: text('evidence_pages', { mode: 'json' }).$type<number[]>().notNull(),
pdf_url: text('pdf_url'),
provider: text('provider'),
model: text('model'),
error: text('error'),
created_at: text('created_at').notNull(),
updated_at: text('updated_at').notNull()
}, (table) => ({
filingTaxonomyMetricValidationSnapshotIndex: index('filing_taxonomy_metric_validation_snapshot_idx').on(table.snapshot_id),
filingTaxonomyMetricValidationStatusIndex: index('filing_taxonomy_metric_validation_status_idx').on(table.snapshot_id, table.status),
filingTaxonomyMetricValidationUnique: uniqueIndex('filing_taxonomy_metric_validation_uidx').on(table.snapshot_id, table.metric_key)
}));
export const filingLink = sqliteTable('filing_link', {
id: integer('id').primaryKey({ autoIncrement: true }),
filing_id: integer('filing_id').notNull().references(() => filing.id, { onDelete: 'cascade' }),
@@ -357,6 +535,11 @@ export const appSchema = {
holding,
filing,
filingStatementSnapshot,
filingTaxonomySnapshot,
filingTaxonomyAsset,
filingTaxonomyConcept,
filingTaxonomyFact,
filingTaxonomyMetricValidation,
filingLink,
taskRun,
taskStageEvent,