Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
325fa1c
Harden test and tooling type boundaries
HardlyDifficult Jul 10, 2026
e720943
Merge branch 'codex/schema-cardinality-guardrails' into codex/typed-t…
HardlyDifficult Jul 10, 2026
125560b
Merge branch 'codex/schema-cardinality-guardrails' into codex/typed-t…
HardlyDifficult Jul 10, 2026
32ad56c
Merge remote-tracking branch 'origin/codex/schema-cardinality-guardra…
HardlyDifficult Jul 10, 2026
0fe31fc
Harden typed transaction tree fixtures
HardlyDifficult Jul 10, 2026
4a1dc8b
Merge commit 'e7ffd298f5cc27bbb596a08b3c41a9b60c70b95a' into codex/ty…
HardlyDifficult Jul 10, 2026
67f8e88
Merge commit '91a2f6f2776e654ee3ac45c3a5ade1602c09a29c' into codex/ty…
HardlyDifficult Jul 11, 2026
ba1d5e1
fix: close typed test boundary gaps
HardlyDifficult Jul 11, 2026
c137e56
Merge commit 'a0973148437e429c0cad192a29533271e74996ff' into codex/ty…
HardlyDifficult Jul 11, 2026
9c79a36
Merge commit '0cdc326526cd33463938082657198fac941efa1a' into codex/ty…
HardlyDifficult Jul 11, 2026
c207ae2
Merge prepared cardinality hardening into typed test infrastructure
HardlyDifficult Jul 11, 2026
173bb0e
Merge finalized cardinality stack into typed test infrastructure
HardlyDifficult Jul 11, 2026
34f4574
Merge centralized trigger validation into typed test infrastructure
HardlyDifficult Jul 11, 2026
094b581
Merge commit '787967fba0da994f48e98f23320b6b80231ef95d' into codex/ty…
HardlyDifficult Jul 11, 2026
a063d09
Merge commit '0dfc424ef470d7718eaa7aa00b3abf8a4ed7b7bd' into codex/ty…
HardlyDifficult Jul 11, 2026
885cdad
fix mock synchronizer fallback and legacy event tree lookup
Copilot Jul 11, 2026
f864d08
Merge commit '302162fe55590d1930dc8fb1de8f7bc6b3e479e5' into codex/ty…
HardlyDifficult Jul 11, 2026
3924254
Merge remote-tracking branch 'origin/codex/typed-test-infrastructure'…
HardlyDifficult Jul 11, 2026
a695d5a
Auto-fix: build changes
github-actions[bot] Jul 11, 2026
9644af6
Merge commit '99fa66060bc05e06d9bbd0c922af95f1f2af6fe1' into codex/ty…
HardlyDifficult Jul 11, 2026
91b8d62
Merge commit 'e5bdbdfe4bb500fd287e448937f033acecb66e03' into codex/ty…
HardlyDifficult Jul 11, 2026
da2bfce
Merge commit '319ef50f88c716e5868b092e9d7688bfb0459189' into codex/ty…
HardlyDifficult Jul 11, 2026
8d923bc
Merge commit 'e0354d2e8d95310f181fc39ac1c265f420932609' into codex/ty…
HardlyDifficult Jul 11, 2026
5bab355
Merge commit '2af4ec88fece128c9c13893f437121a277d8fd8f' into codex/ty…
HardlyDifficult Jul 11, 2026
cb2e289
Merge commit '0a2c6dff364b3bf695fc290f665759e80e8c0242' into codex/ty…
HardlyDifficult Jul 11, 2026
868fe9d
Harden declaration harness against false greens
HardlyDifficult Jul 12, 2026
689f0d2
Merge commit '8968c1f5f7f1e2e2435d66a50338f3b8a1748343' into codex/ty…
HardlyDifficult Jul 12, 2026
e819e38
Merge commit '1557d19b5ef42e2ec99dd8f875cb72f3fbac347c' into codex/ty…
HardlyDifficult Jul 12, 2026
8b2caa9
test: make config exactness any-resistant
HardlyDifficult Jul 12, 2026
f13f0a6
fix: align typed test mocks with runtime
HardlyDifficult Jul 12, 2026
49578de
Merge commit '98d65ded8aed104d2b0af03c119a901fa441ee0c' into codex/ty…
HardlyDifficult Jul 12, 2026
3726f80
test: harden package config exactness
HardlyDifficult Jul 12, 2026
cb4c3a5
test: refresh canonical type inventory
HardlyDifficult Jul 12, 2026
4dd4850
Merge commit '9352fc7438bcdb50ee066e0e785db9c1a7b823f1' into codex/ty…
HardlyDifficult Jul 12, 2026
22d8fb1
test: align schema fixture helper usage
HardlyDifficult Jul 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,28 @@ const eslintConfig = [
'**/node_modules/**',
'**/coverage/**',
'**/docs/**',
'**/test/declarations/**',
'**/*.js',
'**/*.mjs',
'**/libs/**',
// OCF schema submodule - contains TypeScript files not part of our codebase
'**/Open-Cap-Format-OCF/**',
],
},
// Fail closed when a TypeScript file is "disabled" by appending another suffix
// (for example, `example.test.ts.skip`). Such files otherwise escape both the
// TypeScript project and the `**/*.ts` ESLint configuration silently.
{
files: ['**/*.ts.*', '**/*.tsx.*'],
rules: {
'no-restricted-syntax': [
'error',
{
selector: 'Program',
message: 'TypeScript source files must end in .ts or .tsx; do not append a suffix after the extension.',
},
],
},
},
// Main configuration for TypeScript files
{
files: ['**/*.ts', '**/*.tsx'],
Expand All @@ -31,6 +45,7 @@ const eslintConfig = [
'./tsconfig.tests.json',
'./tsconfig.declaration-tests.json',
'./tsconfig.exact-public-config-tests.json',
'./tsconfig.package-consumer-tests.json',
],
ecmaVersion: 2020,
sourceType: 'module',
Expand Down Expand Up @@ -182,7 +197,6 @@ const eslintConfig = [
files: ['scripts/**/*', 'test/**/*'],
rules: {
'no-console': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@
"test": "npm run -s typecheck && jest --passWithNoTests",
"test:ci": "npm run -s typecheck && jest --runInBand --coverage",
"test:coverage": "jest --coverage --passWithNoTests",
"test:declarations": "ts-node --project tsconfig.tests.json scripts/check-declarations.ts && tsc -p tsconfig.declaration-tests.json --noEmit && npm run -s test:exact-public-config && node scripts/check-built-cardinality.cjs",
"test:declarations": "npm run -s clean && npm run -s build && ts-node --project tsconfig.tests.json scripts/check-declarations.ts && tsc -p tsconfig.declaration-tests.json --noEmit && npm run -s test:exact-public-config && node scripts/check-built-cardinality.cjs && npm run -s test:package-consumer",
"test:exact-public-config": "tsc -p tsconfig.exact-public-config-tests.json --noEmit",
"test:integration": "npm run -s typecheck && jest -c jest.integration.config.js --passWithNoTests",
"test:integration:ci": "npm run -s typecheck && jest -c jest.integration.config.js --runInBand",
"test:package-consumer": "tsc -p tsconfig.package-consumer-tests.json --noEmit",
"test:watch": "jest --watch",
"typecheck": "tsc -p tsconfig.tests.json --noEmit"
},
Expand Down
86 changes: 86 additions & 0 deletions scripts/check-declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {

const projectRoot = process.cwd();
const configPath = path.join(projectRoot, 'tsconfig.json');
const packageJsonPath = path.join(projectRoot, 'package.json');
const declarationEntryPoint = path.join(projectRoot, 'dist', 'index.d.ts');
const strictConsumerEntryPoint = path.join(projectRoot, 'test', 'declarations', 'publicApi.types.ts');
const declarationRoot = `${path.dirname(declarationEntryPoint)}${path.sep}`;
Expand All @@ -20,10 +21,95 @@ const diagnosticHost: ts.FormatDiagnosticsHost = {
getNewLine: () => ts.sys.newLine,
};

function asRecord(value: unknown, description: string): Record<string, unknown> {
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
throw new Error(`${description} must be an object`);
}
return value as Record<string, unknown>;
}

function requireString(record: Record<string, unknown>, property: string, description: string): string {
const value = record[property];
if (typeof value !== 'string' || value.length === 0) {
throw new Error(`${description}.${property} must be a non-empty string`);
}
return value;
}

function normalizedPackageTarget(target: string): string {
return target.startsWith('./') ? target.slice(2) : target;
}

function verifyPackageTarget(label: string, target: string, expectedExtension: '.d.ts' | '.js'): string {
const normalizedTarget = normalizedPackageTarget(target);
if (!normalizedTarget.startsWith(`dist${path.sep}`) && !normalizedTarget.startsWith('dist/')) {
throw new Error(`${label} must reference a generated dist artifact, received: ${target}`);
}
if (!normalizedTarget.endsWith(expectedExtension)) {
throw new Error(`${label} must end in ${expectedExtension}, received: ${target}`);
}

const absoluteTarget = path.resolve(projectRoot, normalizedTarget);
const distRoot = path.resolve(projectRoot, 'dist');
if (absoluteTarget !== distRoot && !absoluteTarget.startsWith(`${distRoot}${path.sep}`)) {
throw new Error(`${label} escapes the generated dist directory: ${target}`);
}
if (!fs.existsSync(absoluteTarget)) {
throw new Error(`${label} references a missing package artifact: ${target}`);
}
return absoluteTarget;
}

function verifyPackageEntryPoints(): void {
const packageJsonValue: unknown = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const packageJson = asRecord(packageJsonValue, 'package.json');
const exportsMap = asRecord(packageJson.exports, 'package.json exports');
const rootExport = asRecord(exportsMap['.'], 'package.json exports["."]');

const rootTypes = verifyPackageTarget(
'package.json exports["."].types',
requireString(rootExport, 'types', 'package.json exports["."]'),
'.d.ts'
);
const topLevelTypes = verifyPackageTarget(
'package.json types',
requireString(packageJson, 'types', 'package.json'),
'.d.ts'
);
if (rootTypes !== topLevelTypes || rootTypes !== declarationEntryPoint) {
throw new Error('package.json types and exports["."].types must both reference dist/index.d.ts');
}

const rootImport = verifyPackageTarget(
'package.json exports["."].import',
requireString(rootExport, 'import', 'package.json exports["."]'),
'.js'
);
const rootRequire = verifyPackageTarget(
'package.json exports["."].require',
requireString(rootExport, 'require', 'package.json exports["."]'),
'.js'
);
const rootDefault = verifyPackageTarget(
'package.json exports["."].default',
requireString(rootExport, 'default', 'package.json exports["."]'),
'.js'
);
const topLevelMain = verifyPackageTarget(
'package.json main',
requireString(packageJson, 'main', 'package.json'),
'.js'
);
if (rootImport !== rootRequire || rootImport !== rootDefault || rootImport !== topLevelMain) {
throw new Error('package.json main and exports["."] runtime targets must reference the same built entry point');
}
}

if (!fs.existsSync(declarationEntryPoint)) {
throw new Error(`Declaration entry point not found: ${declarationEntryPoint}. Run npm run build first.`);
}

verifyPackageEntryPoints();
const sourcePublicTypes = inventoryCanonicalOcfPublicTypes(projectRoot, 'source');
const builtPublicTypes = inventoryCanonicalOcfPublicTypes(projectRoot, 'built');
const publicTypeDrift = describeCanonicalOcfPublicTypeDrift(sourcePublicTypes, builtPublicTypes);
Expand Down
4 changes: 2 additions & 2 deletions scripts/optimize-fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ function runCoverage(): CoverageData {
});

return parseCoverage(output);
} catch (error: any) {
} catch (error: unknown) {
// Jest might exit with non-zero code even on successful coverage run
if (error.stdout) {
if (typeof error === 'object' && error !== null && 'stdout' in error && typeof error.stdout === 'string') {
return parseCoverage(error.stdout);
}
throw error;
Expand Down
6 changes: 2 additions & 4 deletions test/batch/generatedOperationConstruction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function loadEntityFixture<T extends OcfEntityType>(
entityType: T,
relativePath: string
): readonly [type: T, data: OcfWritableDataTypeFor<T>] {
const fixture = stripSourceMetadata(loadFixture<Record<string, unknown>>(relativePath));
const fixture = stripSourceMetadata(loadFixture(relativePath));
const canonicalFixture = parseOcfObject(fixture);
return [entityType, parseOcfEntityInput(entityType, canonicalFixture)];
}
Expand Down Expand Up @@ -183,9 +183,7 @@ describe('generated DAML batch operation construction', () => {
test('constructs correlated operation objects without rebuilding asserted tuples', () => {
const stakeholder = parseOcfEntityInput(
'stakeholder',
parseOcfObject(
stripSourceMetadata(loadFixture<Record<string, unknown>>('production/stakeholder/individual.json'))
)
parseOcfObject(stripSourceMetadata(loadFixture('production/stakeholder/individual.json')))
);
const { command } = buildUpdateCapTableCommand(
{ capTableContractId: 'cap-table-generated-operation-1' },
Expand Down
37 changes: 6 additions & 31 deletions test/converters/convertibleIssuanceConverters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import {
} from '../../src/functions/OpenCapTable/convertibleIssuance/createConvertibleIssuance';
import { damlConvertibleIssuanceDataToNative } from '../../src/functions/OpenCapTable/convertibleIssuance/getConvertibleIssuanceAsOcf';
import type { ConvertibleConversionTrigger } from '../../src/types/native';
import { parseOcfEntityInput } from '../../src/utils/ocfZodSchemas';
import { requireFirst } from '../../src/utils/requireDefined';
import { expectInvalidDate } from '../utils/dateValidationAssertions';
import { loadProductionFixture } from '../utils/productionFixtures';
import { loadProductionFixture, stripSourceMetadata } from '../utils/productionFixtures';

const BASE_INPUT = {
id: 'conv-001',
Expand Down Expand Up @@ -2022,37 +2023,11 @@ describe('convertible issuance write field boundaries', () => {
*/
describe('POST_MONEY SAFE – production fixture round-trip', () => {
it('preserves POST_MONEY timing, trigger type, converts_to_future_round, and cap_def_rules from production fixture', () => {
const fixture = loadProductionFixture<{
id: string;
date: string;
security_id: string;
custom_id: string;
stakeholder_id: string;
investment_amount: { amount: string; currency: string };
convertible_type: 'SAFE';
seniority: number;
security_law_exemptions: Array<{ description: string; jurisdiction: string }>;
conversion_triggers: Array<{
type: string;
trigger_id: string;
trigger_condition: string;
conversion_right: {
type: string;
converts_to_future_round: boolean;
conversion_mechanism: {
type: string;
conversion_timing: string;
conversion_mfn: boolean;
conversion_valuation_cap: { amount: string; currency: string };
capitalization_definition_rules: Record<string, boolean>;
};
};
}>;
}>('convertibleIssuance', 'safe-post-money');

const daml = convertibleIssuanceDataToDaml(
fixture as unknown as Parameters<typeof convertibleIssuanceDataToDaml>[0]
const fixture = parseOcfEntityInput(
'convertibleIssuance',
stripSourceMetadata(loadProductionFixture('convertibleIssuance', 'safe-post-money'))
);
const daml = convertibleIssuanceDataToDaml(fixture);
const result = damlConvertibleIssuanceDataToNative(daml);

const trigger = requireFirst(result.conversion_triggers, 'production fixture conversion trigger');
Expand Down
Loading