chore(lint): guard validation ownership and asynchronous assertions

This commit is contained in:
morluto committed 2026-10-25 07:57:07 +08:00
1 parent ed86f9c3bb
commit 76afdd35ae
69 files changed
+2384 -190

No files matched your search

+68 -4
View File
@@ -1,7 +1,6 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "import", "unicorn", "oxc"],
"jsPlugins": [{ "name": "rea", "specifier": "./scripts/lint/index.mjs" }],
"plugins": ["typescript", "import", "unicorn", "oxc", "vitest"],
"rules": {
"rea/no-buffer-deep-equality": "error",
"rea/cancellation-cause": "error",
@@ -29,7 +28,37 @@
"max-params": ["warn", 4],
"no-var": "warn",
"no-var-requires": "error",
"typescript/no-import-type-side-effects": "error"
"typescript/no-import-type-side-effects": "error",
"vitest/no-standalone-expect": "off",
"vitest/no-conditional-expect": "off",
"vitest/expect-expect": "off",
"vitest/no-disabled-tests": "off",
"vitest/require-mock-type-parameters": "off",
"vitest/require-to-throw-message": "off",
"import/no-duplicates": [
"warn",
{
"preferInline": false
}
],
"vitest/valid-expect": [
"warn",
{
"maxArgs": 2
}
],
"rea/no-evidence-json-preadmission": "error",
"rea/no-positional-tool-contract": "error",
"rea/no-fixture-root-cleanup": "error",
"typescript/no-floating-promises": "warn",
"typescript/no-misused-promises": "warn",
"typescript/return-await": ["warn", "error-handling-correctness-only"],
"typescript/switch-exhaustiveness-check": [
"warn",
{
"considerDefaultExhaustiveForUnions": false
}
]
},
"overrides": [
{
@@ -42,6 +71,12 @@
"no-var-requires": "off"
}
},
{
"files": ["src/**/*.ts"],
"rules": {
"typescript/no-misused-promises": "error"
}
},
{
"files": ["tests/**/*.ts", "src/**/*.test.ts", "src/**/*.fixture.ts"],
"rules": {
@@ -53,7 +88,8 @@
"skipBlankLines": true,
"skipComments": true
}
]
],
"typescript/no-misused-promises": "warn"
}
},
{
@@ -97,6 +133,25 @@
}
]
}
},
{
"files": ["tests/**/*.test.ts", "src/**/*.test.ts"],
"rules": {
"vitest/valid-expect": [
"warn",
{
"maxArgs": 2
}
],
"vitest/valid-expect-in-promise": "error",
"vitest/no-focused-tests": "error"
}
},
{
"files": ["src/**/*.test.ts"],
"rules": {
"typescript/no-floating-promises": "error"
}
}
],
"env": {
@@ -115,5 +170,14 @@
".devin",
".factory",
"third_party"
],
"options": {
"reportUnusedDisableDirectives": "error"
},
"jsPlugins": [
{
"name": "rea",
"specifier": "./scripts/lint/index.mjs"
}
]
}
+25 -7
View File
@@ -159,13 +159,31 @@ cause when a directly checked caller `AbortSignal` is converted to an
follow indirect cancellation helpers, or prove that an explicit cause equals
the caller's reason. Keep focused boundary and lifecycle tests for those facts.
Type-aware linting remains outside the routine gate: a full source, test, and
script scan exceeded the bounded process-family memory envelope, including
with Go runtime limits. Future scoped evaluation can consider
`typescript/no-floating-promises`, `typescript/return-await` with
`error-handling-correctness-only`, `typescript/no-misused-promises`, and
`typescript/switch-exhaustiveness-check`. None replaces behavioral checks for
source identity, omission versus unknown, or Evidence provenance.
`rea/no-evidence-json-preadmission` rejects direct generic JSON parses in
`createEvidence` payload expressions; it does not analyze intermediate values.
`rea/no-positional-tool-contract` rejects catalog indices used to select
operation names, schemas or types; display-only selection remains allowed.
`rea/no-fixture-root-cleanup` follows `const` fixture-root aliases into teardown
deletion; mutable bindings and mixed root arrays remain outside its scope.
Focused `.only` declarations, broken assertion promise chains, and unused disable
directives are errors. `vitest/valid-expect` warns (`maxArgs: 2`) because valid stored and
collected assertions can be awaited later. `import/no-duplicates` warns with
`preferInline: false`, preserving separate type imports.
Fast lint stays syntax-based. `npm run lint:typed` runs serially with pinned
`oxlint-tsgolint` 7.0.2005 and records native plus typed diagnostics in
`.cache/static-checks/typed-oxlint.json`. Production `src` treats
`no-misused-promises` as an error; tests/fixtures warn. `no-floating-promises` is
an error in `src/**/*.test.ts`; other scopes, return-await and exhaustiveness
findings warn pending triage.
`npm run knip:production` writes advisory candidates to
`.cache/static-checks/production-reachability.json`; execution/report errors fail.
Ordinary Knip remains. `check`, `check:pr`, and `check:ci:deep` run reachability
then typed lint sequentially after cached work. Typed lint builds the project
type graph and stays separate from fast feedback. Its default Go settings are
`GOMAXPROCS=2` and `GOMEMLIMIT=1024MiB`; caller-selected settings take precedence.
Routine iterations and rebases need focused regressions and relevant checks.
Before handing off a PR, run `npm run check` and generated-document checks when
+35
View File
@@ -0,0 +1,35 @@
{
"$schema": "./node_modules/knip/schema.json",
"entry": [
"src/main.ts!",
"src/cli.ts!",
"src/cliOutput.ts!",
"src/cliBuiltinArguments.ts!",
"src/cli/cliResultOutput.ts!",
"src/mcpDoctor.ts!",
"src/composition/javascriptAnalysisWorkerProcess.ts!",
"src/composition/webBundleAnalysisWorkerProcess.ts!",
"src/sqlite/SqliteDatabaseWorker.ts!",
"src/evm/EvmoleInterfaceWorker.ts!",
"src/browser/history/NodeCaptureProcess.ts!",
"src/javascript/sourceMaps/SourceMapCodecProcess.ts!",
"scripts/rea.mjs!",
"scripts/rea-android-workspace-guardian.mjs!",
"scripts/electron-active-hook.cjs!",
"scripts/prepack.mjs!",
"scripts/prepare.mjs!",
"scripts/verify-windows-native-artifact.mjs!"
],
"project": ["src/**/*.ts!", "!src/**/*.test.ts", "!src/**/*.fixture.ts"],
"ignoreExportsUsedInFile": true,
"include": [
"files",
"exports",
"nsExports",
"types",
"nsTypes",
"enumMembers",
"namespaceMembers",
"duplicates"
]
}
+36 -1
View File
@@ -2,7 +2,7 @@ REA npm dependency inventory
Prepared from the root package-lock.json; refresh this inventory when locked dependencies change.
License identifiers are upstream lockfile declarations, not a legal assessment.
Runtime includes transitive and optional platform packages; development includes build, test and website tooling.
Locked package entries: 956; runtime: 180.
Locked package entries: 963; runtime: 180.
Full runtime copyright/license/NOTICE texts: npm-runtime-notices.txt.
@algolia/abtesting@1.25.0 | development | MIT
@@ -1100,6 +1100,36 @@ commander@13.1.0 | runtime | MIT
Package: https://www.npmjs.com/package/@oxfmt/binding-win32-x64-msvc/v/0.72.0
Archive: https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.72.0.tgz
Integrity: sha512-uhooIN+DCzWX5uH7mQkSVCsODqsGluGJ4n3ch4+mITtWKpESMDjUJUSDBAVFuYQDwqY2McPDKdKJbM0oZVW/Qw==
@oxlint-tsgolint/darwin-arm64@7.0.2005 | development, optional | MIT
Lockfile path: node_modules/@oxlint-tsgolint/darwin-arm64
Package: https://www.npmjs.com/package/@oxlint-tsgolint/darwin-arm64/v/7.0.2005
Archive: https://registry.npmjs.org/@oxlint-tsgolint/darwin-arm64/-/darwin-arm64-7.0.2005.tgz
Integrity: sha512-VqDZxcZVjlonNLuuvraVNgDQt+1ndwa4yJo8OqsK4HYh/61ba9IlMStCVfi/aaIqRoDhNbAKC8gdcTrXqnb+Ug==
@oxlint-tsgolint/darwin-x64@7.0.2005 | development, optional | MIT
Lockfile path: node_modules/@oxlint-tsgolint/darwin-x64
Package: https://www.npmjs.com/package/@oxlint-tsgolint/darwin-x64/v/7.0.2005
Archive: https://registry.npmjs.org/@oxlint-tsgolint/darwin-x64/-/darwin-x64-7.0.2005.tgz
Integrity: sha512-4kUfLRNYoVpv0Tm3jPYrvxyfOc/LmdvFC3pKZ4tL6K7lA7K/VS81SAtmxRzbYXYSyb3SBWhwsuX+df4neqzxxA==
@oxlint-tsgolint/linux-arm64@7.0.2005 | development, optional | MIT
Lockfile path: node_modules/@oxlint-tsgolint/linux-arm64
Package: https://www.npmjs.com/package/@oxlint-tsgolint/linux-arm64/v/7.0.2005
Archive: https://registry.npmjs.org/@oxlint-tsgolint/linux-arm64/-/linux-arm64-7.0.2005.tgz
Integrity: sha512-rhUNcPsBlKvhXtrbhbBUidtRBRdJ8fbEHN9H5Q5N59gby18ruGuDA7KUxl7oRnUzp797uykYQhkBDm+0KpfK/Q==
@oxlint-tsgolint/linux-x64@7.0.2005 | development, optional | MIT
Lockfile path: node_modules/@oxlint-tsgolint/linux-x64
Package: https://www.npmjs.com/package/@oxlint-tsgolint/linux-x64/v/7.0.2005
Archive: https://registry.npmjs.org/@oxlint-tsgolint/linux-x64/-/linux-x64-7.0.2005.tgz
Integrity: sha512-tKs9yinDQZOHygM0e8EJnjTU3mzJtdfkOZP6Udu82iLMePUSHOhTJ9zzU/mSd1hQxURI4LTRRiFhfzC+PzwdNA==
@oxlint-tsgolint/win32-arm64@7.0.2005 | development, optional | MIT
Lockfile path: node_modules/@oxlint-tsgolint/win32-arm64
Package: https://www.npmjs.com/package/@oxlint-tsgolint/win32-arm64/v/7.0.2005
Archive: https://registry.npmjs.org/@oxlint-tsgolint/win32-arm64/-/win32-arm64-7.0.2005.tgz
Integrity: sha512-VYPnu1gjfbSv+ROhuyNfMs382D4zQU2ZRc8Uc3nuEZo1k2kf+1KfTrg4hrlWh73h9GI+dUWyo+DYCQzUBlPwcQ==
@oxlint-tsgolint/win32-x64@7.0.2005 | development, optional | MIT
Lockfile path: node_modules/@oxlint-tsgolint/win32-x64
Package: https://www.npmjs.com/package/@oxlint-tsgolint/win32-x64/v/7.0.2005
Archive: https://registry.npmjs.org/@oxlint-tsgolint/win32-x64/-/win32-x64-7.0.2005.tgz
Integrity: sha512-ekU89cTGy9fpQzuvxIsFHrnoP8XoFjGIRgPEW6eqgY2NYjGy9pwpjF79o04WXRMJFKRrcaVqkZXUUBdLsqpQDw==
@oxlint/binding-android-arm-eabi@1.87.0 | development, optional | MIT
Lockfile path: node_modules/@oxlint/binding-android-arm-eabi
Package: https://www.npmjs.com/package/@oxlint/binding-android-arm-eabi/v/1.87.0
@@ -3540,6 +3570,11 @@ oxlint@1.87.0 | development | MIT
Package: https://www.npmjs.com/package/oxlint/v/1.87.0
Archive: https://registry.npmjs.org/oxlint/-/oxlint-1.87.0.tgz
Integrity: sha512-drxVlaW7Oqq7wSy1CN25znRu00aRq8n57Q2wniJRxCmtYVz07ufCm7EVDPQFZURrTgQIjzKrVEHAD/HcvJXObg==
oxlint-tsgolint@7.0.2005 | development | MIT
Lockfile path: node_modules/oxlint-tsgolint
Package: https://www.npmjs.com/package/oxlint-tsgolint/v/7.0.2005
Archive: https://registry.npmjs.org/oxlint-tsgolint/-/oxlint-tsgolint-7.0.2005.tgz
Integrity: sha512-6ccPGu4u4J9bwYPHXBFPee3RZrX3BboRdU7k14zRDDB1lvN3O7J/vPRFdaEfa1+CWx4xnQQOp4ctoaF66oO0uw==
p-limit@2.3.0 | development | MIT
Lockfile path: node_modules/p-limit
Package: https://www.npmjs.com/package/p-limit/v/2.3.0
+103
View File
@@ -73,6 +73,7 @@
"lint-staged": "16.4.0",
"oxfmt": "0.72.0",
"oxlint": "1.87.0",
"oxlint-tsgolint": "7.0.2005",
"release-please": "17.3.0",
"rolldown": "1.2.12",
"tsrs": "0.18.0-ts7.1.0-dev.20260929",
@@ -3491,6 +3492,90 @@
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@oxlint-tsgolint/darwin-arm64": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-arm64/-/darwin-arm64-7.0.2005.tgz",
"integrity": "sha512-VqDZxcZVjlonNLuuvraVNgDQt+1ndwa4yJo8OqsK4HYh/61ba9IlMStCVfi/aaIqRoDhNbAKC8gdcTrXqnb+Ug==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oxlint-tsgolint/darwin-x64": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-x64/-/darwin-x64-7.0.2005.tgz",
"integrity": "sha512-4kUfLRNYoVpv0Tm3jPYrvxyfOc/LmdvFC3pKZ4tL6K7lA7K/VS81SAtmxRzbYXYSyb3SBWhwsuX+df4neqzxxA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@oxlint-tsgolint/linux-arm64": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-arm64/-/linux-arm64-7.0.2005.tgz",
"integrity": "sha512-rhUNcPsBlKvhXtrbhbBUidtRBRdJ8fbEHN9H5Q5N59gby18ruGuDA7KUxl7oRnUzp797uykYQhkBDm+0KpfK/Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxlint-tsgolint/linux-x64": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-x64/-/linux-x64-7.0.2005.tgz",
"integrity": "sha512-tKs9yinDQZOHygM0e8EJnjTU3mzJtdfkOZP6Udu82iLMePUSHOhTJ9zzU/mSd1hQxURI4LTRRiFhfzC+PzwdNA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@oxlint-tsgolint/win32-arm64": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-arm64/-/win32-arm64-7.0.2005.tgz",
"integrity": "sha512-VYPnu1gjfbSv+ROhuyNfMs382D4zQU2ZRc8Uc3nuEZo1k2kf+1KfTrg4hrlWh73h9GI+dUWyo+DYCQzUBlPwcQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@oxlint-tsgolint/win32-x64": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-x64/-/win32-x64-7.0.2005.tgz",
"integrity": "sha512-ekU89cTGy9fpQzuvxIsFHrnoP8XoFjGIRgPEW6eqgY2NYjGy9pwpjF79o04WXRMJFKRrcaVqkZXUUBdLsqpQDw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@oxlint/binding-android-arm-eabi": {
"version": "1.87.0",
"resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.87.0.tgz",
@@ -10137,6 +10222,24 @@
}
}
},
"node_modules/oxlint-tsgolint": {
"version": "7.0.2005",
"resolved": "https://registry.npmjs.org/oxlint-tsgolint/-/oxlint-tsgolint-7.0.2005.tgz",
"integrity": "sha512-6ccPGu4u4J9bwYPHXBFPee3RZrX3BboRdU7k14zRDDB1lvN3O7J/vPRFdaEfa1+CWx4xnQQOp4ctoaF66oO0uw==",
"dev": true,
"license": "MIT",
"bin": {
"tsgolint": "bin/tsgolint.js"
},
"optionalDependencies": {
"@oxlint-tsgolint/darwin-arm64": "7.0.2005",
"@oxlint-tsgolint/darwin-x64": "7.0.2005",
"@oxlint-tsgolint/linux-arm64": "7.0.2005",
"@oxlint-tsgolint/linux-x64": "7.0.2005",
"@oxlint-tsgolint/win32-arm64": "7.0.2005",
"@oxlint-tsgolint/win32-x64": "7.0.2005"
}
},
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+7 -4
View File
@@ -112,7 +112,7 @@
"prebuild": "npm run deps:check",
"build": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run artifacts:skills --force",
"precheck": "npm run deps:check",
"check": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check && npm run verify:architecture-guards",
"check": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check && npm run verify:architecture-guards && npm run knip:production && npm run lint:typed",
"precheck:fast": "npm run deps:check",
"check:fast": "node scripts/run-turbo.mjs run typecheck lint --output-logs=errors-only",
"precheck:changed": "npm run deps:check",
@@ -120,14 +120,14 @@
"precheck:test": "npm run deps:check",
"check:test": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check test:run",
"precheck:pr": "npm run deps:check",
"check:pr": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check test:run && npm run test:python && npm run docs:check && npm run jscpd && npm run scan:todos",
"check:pr": "node scripts/run-exclusive.mjs artifacts node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check test:run && npm run test:python && npm run docs:check && npm run jscpd && npm run scan:todos && npm run knip:production && npm run lint:typed",
"precheck:ci": "npm run deps:check",
"precheck:ci:fast": "npm run deps:check",
"precheck:ci:deep": "npm run deps:check",
"check:ci": "npm run check:ci:fast && npm run check:ci:deep",
"check:ci:fast": "node scripts/run-exclusive.mjs artifacts npm run check:ci:fast:tasks",
"check:ci:fast:tasks": "node scripts/run-turbo.mjs run typecheck lint:built format:check",
"check:ci:deep": "node scripts/run-exclusive.mjs artifacts npm run check:ci:deep:tasks && npm run verify:architecture-guards && npm run verify:test-discovery && npm run test:python",
"check:ci:deep": "node scripts/run-exclusive.mjs artifacts npm run check:ci:deep:tasks && npm run verify:architecture-guards && npm run verify:test-discovery && npm run test:python && npm run knip:production && npm run lint:typed",
"check:ci:deep:tasks": "node scripts/run-turbo.mjs run knip metadata:check jscpd scan:todos",
"check:ci:tasks": "node scripts/run-turbo.mjs run typecheck lint:built format:check knip metadata:check jscpd scan:todos",
"ci:static-context": "node scripts/ci/static-task-context.mjs",
@@ -326,7 +326,9 @@
"docs:prepare": "node scripts/generate-package-metadata.mjs && node scripts/run-turbo.mjs run artifacts:product-catalog artifacts:managed-evidence artifacts:error-schema",
"verify:web:qlog": "npm run build:cached && node scripts/verify-qlog-captures.mjs",
"licenses:generate": "node scripts/generate-third-party-inventory.mjs",
"licenses:check": "node scripts/generate-third-party-inventory.mjs --check"
"licenses:check": "node scripts/generate-third-party-inventory.mjs --check",
"lint:typed": "node scripts/ci/static-check-report.mjs typed-lint",
"knip:production": "node scripts/ci/production-reachability-report.mjs"
},
"lint-staged": {
"*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}": [
@@ -404,6 +406,7 @@
"lint-staged": "16.4.0",
"oxfmt": "0.72.0",
"oxlint": "1.87.0",
"oxlint-tsgolint": "7.0.2005",
"release-please": "17.3.0",
"rolldown": "1.2.12",
"tsrs": "0.18.0-ts7.1.0-dev.20260929",
+1 -1
View File
@@ -108,7 +108,7 @@ function classifyPackage(base, head) {
continue;
}
if (
/^(test(?::|$)|check(?::|$)|lint(?::|$)|format(?::|$)|knip$|jscpd$)/.test(
/^(test(?::|$)|check(?::|$)|lint(?::|$)|format(?::|$)|knip(?::|$)|jscpd$)/.test(
script,
)
)
@@ -0,0 +1,33 @@
export interface ProductionReachabilityFinding {
readonly name: string;
readonly namespace?: string;
readonly kind?: string;
readonly specifier?: string;
readonly line?: number;
readonly col?: number;
readonly pos?: number;
}
export interface ProductionReachabilityIssue {
readonly file: string;
readonly owners?: readonly { readonly name: string }[];
readonly files?: readonly ProductionReachabilityFinding[];
readonly exports?: readonly ProductionReachabilityFinding[];
readonly nsExports?: readonly ProductionReachabilityFinding[];
readonly types?: readonly ProductionReachabilityFinding[];
readonly nsTypes?: readonly ProductionReachabilityFinding[];
readonly enumMembers?: readonly ProductionReachabilityFinding[];
readonly namespaceMembers?: readonly ProductionReachabilityFinding[];
readonly duplicates?: readonly (readonly ProductionReachabilityFinding[])[];
}
export interface ProductionReachabilityReport {
readonly issues: readonly ProductionReachabilityIssue[];
}
export function parseProductionReachabilityReport(
text: string,
): ProductionReachabilityReport;
export function recordProductionReachabilityReport(
root?: string,
): Promise<ProductionReachabilityReport>;
@@ -0,0 +1,86 @@
import { spawnSync } from "node:child_process";
import { mkdir, rm, writeFile } from "node:fs/promises";
import { createRequire } from "node:module";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { z } from "zod";
const require = createRequire(import.meta.url);
const finding = z.object({
name: z.string(),
namespace: z.string().optional(),
kind: z.string().optional(),
specifier: z.string().optional(),
line: z.number().optional(),
col: z.number().optional(),
pos: z.number().optional(),
});
const issue = z.strictObject({
file: z.string(),
owners: z.array(z.object({ name: z.string() })).optional(),
files: z.array(finding).optional(),
exports: z.array(finding).optional(),
nsExports: z.array(finding).optional(),
types: z.array(finding).optional(),
nsTypes: z.array(finding).optional(),
enumMembers: z.array(finding).optional(),
namespaceMembers: z.array(finding).optional(),
duplicates: z.array(z.array(finding)).optional(),
});
const reportSchema = z.strictObject({ issues: z.array(issue) });
/** Admit the installed Knip JSON reporter's candidate records. */
export const parseProductionReachabilityReport = (text) =>
reportSchema.parse(JSON.parse(text));
/** Run production reachability without turning candidates into failures. */
export const recordProductionReachabilityReport = async (
root = process.cwd(),
) => {
const reportDirectory = join(root, ".cache", "static-checks");
const reportPath = join(reportDirectory, "production-reachability.json");
// Findings are advisory. Execution, configuration and report-admission failures
// still fail, and must never leave an older successful report at this path.
await mkdir(reportDirectory, { recursive: true });
await rm(reportPath, { force: true });
const result = spawnSync(
process.execPath,
[
join(dirname(require.resolve("knip")), "..", "bin", "knip.js"),
"--config",
"knip.production.json",
"--production",
"--reporter",
"json",
"--no-exit-code",
],
{ cwd: root, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 },
);
if (result.stderr) process.stderr.write(result.stderr);
if (result.error !== undefined) throw result.error;
if (result.status !== 0) {
if (result.stdout) process.stderr.write(result.stdout);
throw new Error(
result.status === null
? `Production reachability analysis terminated by ${result.signal}`
: `Production reachability analysis failed with status ${result.status}`,
);
}
const report = parseProductionReachabilityReport(result.stdout);
await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`);
console.log(
`Production reachability: ${report.issues.length} files with advisory candidates.`,
);
console.log(`Full report: ${reportPath}`);
console.log(
"Candidates require runtime, verifier and published-contract review before removal; ordinary Knip remains separate.",
);
return report;
};
if (
process.argv[1] !== undefined &&
resolve(process.argv[1]) === fileURLToPath(import.meta.url)
)
await recordProductionReachabilityReport();
+35 -11
View File
@@ -48,7 +48,12 @@ const duplicateReport = z
})
.passthrough();
const run = (packageName, entrypoint, arguments_) => {
const run = (
packageName,
entrypoint,
arguments_,
environment = process.env,
) => {
const executable = join(
dirname(require.resolve(`${packageName}/package.json`)),
entrypoint,
@@ -56,6 +61,7 @@ const run = (packageName, entrypoint, arguments_) => {
const result = spawnSync(process.execPath, [executable, ...arguments_], {
encoding: "utf8",
maxBuffer: 32 * 1024 * 1024,
env: environment,
});
if (result.stderr) process.stderr.write(result.stderr);
if (result.error !== undefined) throw result.error;
@@ -66,14 +72,30 @@ const run = (packageName, entrypoint, arguments_) => {
try {
await mkdir(reportRoot, { recursive: true });
if (mode === "lint") {
const reportPath = join(reportRoot, "oxlint.json");
if (mode === "lint" || mode === "typed-lint") {
const typed = mode === "typed-lint";
const reportPath = join(
reportRoot,
typed ? "typed-oxlint.json" : "oxlint.json",
);
await rm(reportPath, { force: true });
const result = run("oxlint", "bin/oxlint", [
...extraArguments,
"--format",
"json",
]);
const result = run(
"oxlint",
"bin/oxlint",
[
...(typed ? ["--type-aware", "--threads", "1"] : []),
...extraArguments,
"--format",
"json",
],
typed
? {
...process.env,
GOMAXPROCS: process.env.GOMAXPROCS ?? "2",
GOMEMLIMIT: process.env.GOMEMLIMIT ?? "1024MiB",
}
: process.env,
);
let report;
try {
report = lintReport.parse(JSON.parse(result.stdout));
@@ -89,7 +111,7 @@ try {
({ severity }) => severity === "error",
);
console.log(
`Lint: ${report.number_of_files} files, ${errors.length} errors, ${warnings.length} warnings.`,
`${typed ? "Typed lint" : "Lint"}: ${report.number_of_files} files, ${errors.length} errors, ${warnings.length} warnings.`,
);
for (const diagnostic of errors) {
const location = diagnostic.labels[0]?.span;
@@ -106,7 +128,9 @@ try {
)
.slice(0, 8))
console.log(` ${rule}: ${count} warnings`);
console.log(`Full diagnostics: ${reportPath}; npm run lint:details`);
console.log(
`Full diagnostics: ${reportPath}${typed ? "" : "; npm run lint:details"}`,
);
process.exitCode = result.status;
} else if (mode === "duplicates") {
const output = join(reportRoot, "jscpd");
@@ -143,7 +167,7 @@ try {
console.log(`Full diagnostics: ${reportPath}; npm run jscpd:details`);
process.exitCode = result.status;
} else {
throw new Error("Expected lint or duplicates");
throw new Error("Expected lint, typed-lint or duplicates");
}
} catch (cause) {
console.error(cause instanceof Error ? cause.message : String(cause));
+7
View File
@@ -1,10 +1,17 @@
import noBufferDeepEquality from "./no-buffer-deep-equality.mjs";
import cancellationCause from "./cancellation-cause.mjs";
import noEvidenceJsonPreadmission from "./rules/no-evidence-json-preadmission.mjs";
import noFixtureRootCleanup from "./rules/no-fixture-root-cleanup.mjs";
import noPositionalToolContract from "./rules/no-positional-tool-contract.mjs";
export default {
meta: { name: "rea" },
rules: {
"no-buffer-deep-equality": noBufferDeepEquality,
"cancellation-cause": cancellationCause,
"no-evidence-json-preadmission": noEvidenceJsonPreadmission,
"no-fixture-root-cleanup": noFixtureRootCleanup,
"no-positional-tool-contract": noPositionalToolContract,
},
};
+4
View File
@@ -0,0 +1,4 @@
export declare const resolveImportSource: (
filename: string,
specifier: unknown,
) => string | undefined;
+20
View File
@@ -0,0 +1,20 @@
import { dirname, isAbsolute, resolve } from "node:path";
import { fileURLToPath } from "node:url";
/** Resolve local import spellings without assigning local meaning to bare or HTTP imports. */
export const resolveImportSource = (filename, specifier) => {
if (typeof specifier !== "string") return undefined;
if (isAbsolute(specifier)) return resolve(specifier);
if (specifier.startsWith("file:")) {
try {
const url = new URL(specifier);
if (url.search !== "" || url.hash !== "") return undefined;
return fileURLToPath(url);
} catch {
return undefined;
}
}
if (specifier.startsWith("./") || specifier.startsWith("../"))
return resolve(dirname(filename), specifier);
return undefined;
};
@@ -0,0 +1,4 @@
import type { RuleTester } from "oxlint/plugins-dev";
declare const rule: Parameters<RuleTester["run"]>[1];
export default rule;
@@ -0,0 +1,137 @@
import { findBinding } from "../bindings.mjs";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { resolveImportSource } from "./import-source.mjs";
const domain = fileURLToPath(new URL("../../../src/domain/", import.meta.url));
const payloadFields = new Set(["parameters", "result", "rawResult"]);
const propertyName = (node) => {
if (!node.computed && node.property?.type === "Identifier")
return node.property.name;
if (
node.property?.type === "Literal" &&
typeof node.property.value === "string"
)
return node.property.value;
return undefined;
};
const fieldName = (node) => {
if (node.type !== "Property") return undefined;
if (!node.computed && node.key.type === "Identifier") return node.key.name;
if (node.key.type === "Literal" && typeof node.key.value === "string")
return node.key.value;
return undefined;
};
const importedBinding = (sourceCode, node) => {
if (node.type !== "Identifier") return undefined;
const variable = findBinding(sourceCode, node);
if (!variable || variable.defs.length !== 1) return undefined;
const definition = variable.defs[0];
return definition.type === "ImportBinding" ? definition : undefined;
};
const isImported = (context, node, module, names) => {
const member = node.type === "MemberExpression" && !node.optional;
const binding = importedBinding(
context.sourceCode,
member ? node.object : node,
);
if (!binding || binding.parent?.type !== "ImportDeclaration") return false;
const declaration = binding.parent;
if (declaration.importKind === "type" || binding.node.importKind === "type")
return false;
const specifier = declaration.source.value;
const target = resolveImportSource(
context.physicalFilename ?? context.filename,
specifier,
);
if (
target !== resolve(domain, `${module}.js`) &&
target !== resolve(domain, `${module}.ts`)
)
return false;
if (member)
return (
binding.node.type === "ImportNamespaceSpecifier" &&
names.has(propertyName(node))
);
if (binding.node.type !== "ImportSpecifier") return false;
return names.has(binding.node.imported.name ?? binding.node.imported.value);
};
const evidenceCreator = new Set(["createEvidence"]);
const genericJsonSchemas = new Set(["jsonValueSchema", "jsonObjectSchema"]);
export default {
meta: {
type: "suggestion",
docs: {
description:
"Leave ordinary Evidence JSON payload admission with createEvidence.",
},
schema: [],
messages: {
redundantJsonAdmission:
"Pass the {{field}} payload directly to createEvidence; it owns generic JSON admission. Keep semantic validation at its own boundary.",
},
},
create(context) {
return {
CallExpression(node) {
if (
node.optional ||
!isImported(context, node.callee, "evidence", evidenceCreator)
)
return;
const observation = node.arguments[2];
if (observation?.type !== "ObjectExpression") return;
for (const [index, property] of observation.properties.entries()) {
const field = fieldName(property);
if (
!payloadFields.has(field) ||
property.kind !== "init" ||
property.method
)
continue;
// A later spread or unknown key may replace this field before admission.
if (
observation.properties
.slice(index + 1)
.some(
(later) =>
later.type !== "Property" ||
fieldName(later) === undefined ||
fieldName(later) === field,
)
)
continue;
const parsed = property.value;
if (
parsed.type !== "CallExpression" ||
parsed.optional ||
parsed.arguments.length !== 1
)
continue;
const parse = parsed.callee;
if (
parse.type !== "MemberExpression" ||
parse.optional ||
propertyName(parse) !== "parse"
)
continue;
if (
isImported(context, parse.object, "jsonValue", genericJsonSchemas)
)
context.report({
node: parsed,
messageId: "redundantJsonAdmission",
data: { field },
});
}
},
};
},
};
@@ -0,0 +1,3 @@
import type { RuleTester } from "oxlint/plugins-dev";
declare const rule: Parameters<RuleTester["run"]>[1];
export default rule;
@@ -0,0 +1,149 @@
import { findBinding } from "../bindings.mjs";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { resolveImportSource } from "./import-source.mjs";
const root = fileURLToPath(new URL("../../../", import.meta.url));
const fixtureModule = resolve(root, "tests/fixtures/temporaryDirectory");
const workspaceModule = resolve(
root,
"tests/support/workspace/workspaceFixture",
);
const hooks = new Set(["afterEach", "afterAll", "onTestFinished"]);
const unwrap = (node) => {
while (
node &&
[
"AwaitExpression",
"TSAsExpression",
"TSNonNullExpression",
"ChainExpression",
].includes(node.type)
)
node = node.argument ?? node.expression;
return node;
};
const isFunction = (node) =>
node &&
[
"FunctionDeclaration",
"FunctionExpression",
"ArrowFunctionExpression",
].includes(node.type);
export default {
meta: {
type: "problem",
docs: {
description: "Let createTestTempDirectory own removal of its root.",
},
schema: [],
messages: {
duplicate:
"createTestTempDirectory already owns root cleanup; remove the duplicate teardown deletion, retaining cleanup of other resources.",
},
},
create(context) {
const sourceCode = context.sourceCode;
const filename = context.physicalFilename ?? context.filename;
const calls = [];
const variable = (node) => findBinding(sourceCode, node);
const imported = (node) => {
const member = node?.type === "MemberExpression" ? node : undefined;
const binding = member ? member.object : node;
if (binding?.type !== "Identifier") return undefined;
const definition = variable(binding)?.defs[0];
if (
definition?.type !== "ImportBinding" ||
(member
? definition.node.type !== "ImportNamespaceSpecifier"
: definition.node.type !== "ImportSpecifier")
)
return undefined;
const declaration = definition.parent ?? definition.node.parent;
const specifier = declaration.source?.value;
if (typeof specifier !== "string") return undefined;
return {
name: member
? member.computed
? member.property.value
: member.property.name
: (definition.node.imported.name ?? definition.node.imported.value),
module:
resolveImportSource(filename, specifier)?.replace(
/\.(?:[cm]?[jt]s)$/u,
"",
) ?? specifier,
};
};
const fixtureRoot = (raw, seen = new Set()) => {
const node = unwrap(raw);
if (node?.type === "CallExpression") {
const identity = imported(node.callee);
return (
identity?.module === fixtureModule &&
identity.name === "createTestTempDirectory"
);
}
if (node?.type !== "Identifier") return false;
const binding = variable(node);
if (!binding || seen.has(binding)) return false;
seen.add(binding);
const definition = binding.defs[0];
// Mutable ownership and mixed root registries require flow analysis, not
// a guess based on the variable name or one assignment.
return (
definition?.type === "Variable" &&
definition.parent.kind === "const" &&
definition.node.id.type === "Identifier" &&
fixtureRoot(definition.node.init, seen)
);
};
const callback = (raw) => {
const node = unwrap(raw);
if (isFunction(node)) return node;
if (node?.type !== "Identifier") return undefined;
const definition = variable(node)?.defs[0];
if (definition?.type === "FunctionName") return definition.node;
if (
definition?.type === "Variable" &&
definition.parent.kind === "const"
) {
const value = unwrap(definition.node.init);
if (isFunction(value)) return value;
}
return undefined;
};
return {
CallExpression(node) {
calls.push(node);
},
"Program:exit"() {
const teardowns = new Set();
for (const call of calls) {
const identity = imported(call.callee);
if (identity?.module === "vitest" && hooks.has(identity.name)) {
const body = callback(call.arguments[0]);
if (body) teardowns.add(body);
}
}
for (const call of calls) {
const identity = imported(call.callee);
if (!identity) continue;
const removesRoot =
(identity.module === "node:fs/promises" &&
["rm", "rmdir"].includes(identity.name)) ||
(identity.module === "node:fs" &&
["rm", "rmSync", "rmdir", "rmdirSync"].includes(identity.name)) ||
(identity.module === workspaceModule &&
identity.name === "removeTestWorkspace");
if (!removesRoot || !fixtureRoot(call.arguments[0])) continue;
let parent = call.parent;
while (parent && !isFunction(parent)) parent = parent.parent;
if (teardowns.has(parent))
context.report({ node: call, messageId: "duplicate" });
}
},
};
},
};
@@ -0,0 +1,3 @@
import type { RuleTester } from "oxlint/plugins-dev";
declare const rule: Parameters<RuleTester["run"]>[1];
export default rule;
@@ -0,0 +1,218 @@
import { findBinding } from "../bindings.mjs";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { collectToolCatalogSources } from "./tool-catalog-sources.mjs";
import { resolveImportSource } from "./import-source.mjs";
const root = fileURLToPath(new URL("../../../", import.meta.url));
const catalogs = collectToolCatalogSources(
resolve(root, "src/contracts/toolContracts.ts"),
);
const unwrap = (node) => {
while (
node &&
[
"TSAsExpression",
"TSSatisfiesExpression",
"TSNonNullExpression",
"ChainExpression",
].includes(node.type)
)
node = node.expression;
return node;
};
const numeric = (node) =>
(node?.type === "Literal" &&
(typeof node.value === "number" ||
(typeof node.value === "string" &&
/^(?:0|[1-9][0-9]*)$/u.test(node.value)))) ||
(node?.type === "UnaryExpression" &&
["+", "-"].includes(node.operator) &&
node.argument.type === "Literal" &&
typeof node.argument.value === "number");
export default {
meta: {
type: "problem",
docs: {
description:
"Select canonical tool contracts by name, never catalog position.",
},
schema: [],
messages: {
positional:
"Select a named tool contract; catalog ordering must not select an operation or schema.",
},
},
create(context) {
const sourceCode = context.sourceCode;
const filename = context.physicalFilename ?? context.filename;
const variable = (node) => findBinding(sourceCode, node);
const imported = (node) => {
if (node?.type !== "Identifier") return undefined;
const definition = variable(node)?.defs[0];
if (definition?.type !== "ImportBinding") return undefined;
const declaration = definition.parent ?? definition.node.parent;
const specifier = declaration.source?.value;
const path = resolveImportSource(filename, specifier)?.replace(
/\.(?:[cm]?[jt]s)$/u,
"",
);
const expected = catalogs.get(path);
if (expected === undefined) return undefined;
return { definition, expected };
};
const isCatalog = (raw, seen = new Set()) => {
const node = unwrap(raw);
if (!node) return false;
if (node.type === "Identifier") {
const binding = variable(node);
if (!binding || seen.has(binding)) return false;
seen.add(binding);
const identity = imported(node);
if (identity) {
const specifier = identity.definition.node;
return (
specifier.type === "ImportSpecifier" &&
identity.expected.has(
specifier.imported.name ?? specifier.imported.value,
)
);
}
const definition = binding.defs[0];
return (
definition?.type === "Variable" &&
definition.parent.kind === "const" &&
definition.node.id.type === "Identifier" &&
isCatalog(definition.node.init, seen)
);
}
if (node.type === "MemberExpression" || node.type === "TSQualifiedName") {
const object =
node.type === "MemberExpression" ? node.object : node.left;
const identity = imported(object);
if (identity?.definition.node.type !== "ImportNamespaceSpecifier")
return false;
const property =
node.type === "MemberExpression" ? node.property : node.right;
const name = node.computed ? property.value : property.name;
return identity.expected.has(name);
}
return false;
};
const selectedContract = (raw, seen = new Set()) => {
const node = unwrap(raw);
if (!node) return undefined;
if (
node.type === "MemberExpression" &&
node.computed &&
numeric(node.property) &&
isCatalog(node.object)
)
return node;
if (node.type === "CallExpression") {
const callee = unwrap(node.callee);
if (
callee?.type === "MemberExpression" &&
(callee.computed ? callee.property.value : callee.property.name) ===
"at" &&
numeric(node.arguments[0]) &&
isCatalog(callee.object)
)
return node;
}
if (node.type !== "Identifier") return undefined;
const binding = variable(node);
if (!binding || seen.has(binding)) return undefined;
seen.add(binding);
const definition = binding.defs[0];
if (definition?.type !== "Variable" || definition.parent.kind !== "const")
return undefined;
if (definition.node.id.type === "Identifier")
return selectedContract(definition.node.init, seen);
if (
definition.node.id.type === "ArrayPattern" &&
definition.node.id.elements.some(
(element) =>
element?.type === "Identifier" && element.name === node.name,
) &&
isCatalog(definition.node.init)
)
return definition.node;
return undefined;
};
const bindingFields = new Set(["name", "inputSchema", "outputSchema"]);
const isRegistrationOptions = (node) => {
if (node?.type !== "Identifier") return false;
const definition = variable(node)?.defs[0];
if (
definition?.type !== "ImportBinding" ||
definition.node.type !== "ImportSpecifier"
)
return false;
const declaration = definition.parent ?? definition.node.parent;
const specifier = declaration.source?.value;
const path = resolveImportSource(filename, specifier)?.replace(
/\.(?:[cm]?[jt]s)$/u,
"",
);
const name =
definition.node.imported.name ?? definition.node.imported.value;
return (
path === resolve(root, "src/server/toolRegistrationOptions") &&
[
"toolRegistrationOptions",
"applicationToolRegistrationOptions",
].includes(name)
);
};
const reported = new Set();
const reportSelection = (raw) => {
const node = selectedContract(raw);
if (node && !reported.has(node)) {
reported.add(node);
context.report({ node, messageId: "positional" });
}
};
return {
MemberExpression(node) {
const name = node.computed ? node.property.value : node.property.name;
const parent = node.parent;
const writesProperty =
(parent?.type === "AssignmentExpression" && parent.left === node) ||
parent?.type === "UpdateExpression" ||
(parent?.type === "UnaryExpression" && parent.operator === "delete");
if (bindingFields.has(name) && !writesProperty)
reportSelection(node.object);
},
CallExpression(node) {
if (isRegistrationOptions(unwrap(node.callee)))
reportSelection(node.arguments[0]);
},
VariableDeclarator(node) {
if (
node.id.type === "ObjectPattern" &&
node.id.properties.some(
(property) =>
property.type === "Property" &&
bindingFields.has(
property.computed ? property.key.value : property.key.name,
),
)
)
reportSelection(node.init);
},
TSIndexedAccessType(node) {
if (
node.objectType.type === "TSTypeQuery" &&
node.indexType.type === "TSLiteralType" &&
numeric(node.indexType.literal) &&
isCatalog(node.objectType.exprName)
)
context.report({ node, messageId: "positional" });
},
};
},
};
@@ -0,0 +1,4 @@
export declare const collectToolCatalogSources: (
entryPath: string,
readSource?: (path: string) => string,
) => ReadonlyMap<string, ReadonlySet<string>>;
+118
View File
@@ -0,0 +1,118 @@
import { parse } from "@babel/parser";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
const withoutExtension = (path) => path.replace(/\.(?:[cm]?[jt]s)$/u, "");
const arrayExpression = (raw) => {
let node = raw;
while (
node &&
["TSAsExpression", "TSSatisfiesExpression"].includes(node.type)
)
node = node.expression;
return node;
};
/** Read only source composition, never execute the runtime contract catalog. */
export const collectToolCatalogSources = (
entryPath,
readSource = (path) => readFileSync(path, "utf8"),
) => {
const catalogs = new Map();
const modules = new Map();
const active = new Set();
const complete = new Set();
const moduleFacts = (path) => {
let facts = modules.get(path);
if (facts) return facts;
// Read/parse errors intentionally escape: a broken inventory cannot disable
// the rule by presenting an empty set of catalog bindings.
const ast = parse(readSource(path), {
sourceType: "module",
plugins: ["typescript"],
});
const imports = new Map();
const exports = new Map();
const locals = new Map();
for (const statement of ast.program.body) {
if (statement.type === "ImportDeclaration") {
for (const specifier of statement.specifiers) {
if (specifier.type === "ImportSpecifier")
imports.set(specifier.local.name, {
source: statement.source.value,
name: specifier.imported.name ?? specifier.imported.value,
});
}
}
const declarations =
statement.type === "ExportNamedDeclaration"
? statement.declaration
: statement;
if (declarations?.type === "VariableDeclaration")
for (const declaration of declarations.declarations)
if (declaration.id.type === "Identifier") {
locals.set(declaration.id.name, declaration.init);
if (statement.type === "ExportNamedDeclaration")
exports.set(declaration.id.name, declaration.init);
}
}
facts = { imports, exports, locals };
modules.set(path, facts);
return facts;
};
const visit = (path, name) => {
const key = JSON.stringify([path, name]);
if (complete.has(key)) return;
if (active.has(key))
throw new Error(`Cyclic tool catalog composition: ${path}#${name}`);
active.add(key);
const facts = moduleFacts(path);
const array = arrayExpression(facts.exports.get(name));
if (array?.type !== "ArrayExpression")
throw new Error(`Expected exported tool catalog array: ${path}#${name}`);
const source = withoutExtension(path);
const names = catalogs.get(source) ?? new Set();
names.add(name);
catalogs.set(source, names);
const composition = (raw, localPath = new Set()) => {
const expression = arrayExpression(raw);
if (expression?.type === "ArrayExpression") {
for (const element of expression.elements)
if (element?.type === "SpreadElement")
composition(element.argument, localPath);
return;
}
// Calls such as HOPPER_MEMORY_TOOL_DEFINITIONS.map(official) construct
// entries locally; they are not imported catalog arrays. Do not execute
// or infer catalog ownership from arbitrary computed expressions.
if (expression?.type !== "Identifier") return;
const binding = facts.imports.get(expression.name);
if (binding) {
if (!binding.source.startsWith("."))
throw new Error(`Expected local catalog module: ${path}#${name}`);
visit(
`${withoutExtension(resolve(dirname(path), binding.source))}.ts`,
binding.name,
);
return;
}
if (localPath.has(expression.name))
throw new Error(
`Cyclic local catalog composition: ${path}#${expression.name}`,
);
if (!facts.locals.has(expression.name))
throw new Error(
`Unresolved local catalog spread: ${path}#${expression.name}`,
);
composition(
facts.locals.get(expression.name),
new Set([...localPath, expression.name]),
);
};
composition(array);
active.delete(key);
complete.add(key);
};
visit(entryPath, "TOOL_CONTRACTS");
return catalogs;
};
@@ -3,7 +3,6 @@ import { describe, expect, it } from "vitest";
import { JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE } from "../contracts/javascript/javascriptRuntimeReconciliationExample.js";
import { createEvidence } from "../domain/evidence.js";
import { createEvidenceBundle } from "../domain/evidenceBundle.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
import { javascriptApplicationAnalysisResultSchema } from "../domain/javascript/javascriptApplicationAnalysis.js";
import { artifactEvidence } from "../domain/javascript/javascriptApplicationGraph.fixture.js";
import {
@@ -108,7 +107,7 @@ const semanticApplication = (
predicateType: example.predicate_type,
operation: example.operation,
parameters: example.parameters,
result: jsonValueSchema.parse({ ...base, semantic_graph: graph }),
result: { ...base, semantic_graph: graph },
confidence: "derived",
authority: "shipped-artifact",
},
@@ -33,7 +33,6 @@ import {
createJavaScriptApplicationGraph,
createJavaScriptApplicationNode,
} from "../domain/javascript/javascriptApplicationGraph.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
import { MANAGED_WORKFLOW_PROVIDER } from "../domain/investigationProviders.js";
import { createProcessCaptureEvidence } from "./process/ProcessEvidence.js";
@@ -90,7 +89,7 @@ const applicationWithUnknowns = (
predicateType: "rea.managed-application-graph",
operation: "project_managed_application_graph",
parameters: {},
result: jsonValueSchema.parse({
result: {
projection_id: `magp_${"a".repeat(64)}`,
root_artifact_sha256: APPLICATION_GRAPH_DIGESTS.asar,
source_evidence: {
@@ -113,7 +112,7 @@ const applicationWithUnknowns = (
coverage: { status: "complete-within-inputs" },
evidence_links: [source.evidence_id],
limitations: [],
}),
},
confidence: "inferred",
authority: "analyst-inference",
evidenceLinks: [source.evidence_id],
@@ -212,7 +211,7 @@ describe("reconstruction obligation candidates", () => {
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: {},
result: jsonValueSchema.parse({
result: {
...rest,
manifest,
exit: {
@@ -224,7 +223,7 @@ describe("reconstruction obligation candidates", () => {
],
},
},
}),
},
});
const generated = deriveCandidates(createEvidenceBundle([evidence]), []);
@@ -308,7 +307,7 @@ it("keeps each semantic candidate bound to its own file and authority context",
predicateType: example.predicate_type,
operation: example.operation,
parameters: example.parameters,
result: jsonValueSchema.parse({ ...base, semantic_graph: semanticGraph }),
result: { ...base, semantic_graph: semanticGraph },
confidence: "derived",
authority: "shipped-artifact",
evidenceLinks: sourceRecords.map(({ evidence_id }) => evidence_id),
@@ -415,7 +414,7 @@ it("falls back to a kind-based title when a semantic node label is blank", () =>
predicateType: example.predicate_type,
operation: example.operation,
parameters: example.parameters,
result: jsonValueSchema.parse({ ...base, semantic_graph: semanticGraph }),
result: { ...base, semantic_graph: semanticGraph },
confidence: "derived",
authority: "shipped-artifact",
evidenceLinks: [source.evidence_id],
@@ -9,7 +9,6 @@ import { compareArtifacts } from "../../domain/artifactComparison.js";
import { parseArtifactInventoryEvidence } from "../../domain/artifactInventoryEvidence.js";
import { projectAppleInventory } from "../../domain/apple/appleApplication.js";
import { createEvidence } from "../../domain/evidence.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import { thinMach } from "../../domain/binaryTarget.fixture.js";
import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js";
@@ -32,7 +31,7 @@ const observeArchive = async (order: readonly string[]) => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventory),
result: inventory,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -128,7 +127,7 @@ describe("content identity and occurrence facts", () => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventory),
result: inventory,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -19,7 +19,6 @@ import {
import { readPyzArchive } from "./PyzArchive.js";
import { marshalCode } from "../../python/PythonPyc.fixture.js";
import { createEvidence } from "../../domain/evidence.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import { parseArtifactInventoryEvidence } from "../../domain/artifactInventoryEvidence.js";
import {
ArtifactReaderFailure,
@@ -365,7 +364,7 @@ it.each([true, false])(
parameters: { page: index },
confidence: "observed",
authority: "shipped-artifact",
result: jsonValueSchema.parse({
result: {
...inventory,
nodes: index === 0 ? inventory.nodes : [],
edges: index === 0 ? inventory.edges : [],
@@ -378,7 +377,7 @@ it.each([true, false])(
row,
]
: [row],
}),
},
},
),
);
@@ -373,7 +373,6 @@ const emitDeepLink = (
);
/** Read the current Electron windows, metrics, and hook snapshot. */
// oxlint-disable-next-line max-lines-per-function -- one state read must share one capture boundary.
export const readApplicationState = async (
application: ElectronApplication,
): Promise<{
+2 -3
View File
@@ -10,7 +10,6 @@ import { AnalysisInputError } from "../analysisErrorCore.js";
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
import { digestCanonicalValue } from "../canonicalDigest.js";
import { createEvidence, type Evidence } from "../evidence.js";
import { jsonValueSchema } from "../jsonValue.js";
type EntryKind = "file" | "directory" | "symlink" | "slice";
type RootFormat = "ipa" | "zip" | "dmg" | "directory" | "asar";
@@ -136,7 +135,7 @@ const inventoryEvidence = (
parameters: {},
confidence: "observed",
authority: "shipped-artifact",
result: jsonValueSchema.parse({
result: {
manifest: {
manifest_id: `agm_${digestCanonicalValue(
{ root_artifact_id: rootId, graph_sha256: graphSha256 },
@@ -157,7 +156,7 @@ const inventoryEvidence = (
integrity_contradictions: [],
coverage: { scope: "container-entries", status: "complete" },
limitations: [],
}),
},
},
);
};
+3 -4
View File
@@ -14,7 +14,6 @@ import {
parseArtifactInspectionInventoryResult,
} from "./artifactInventoryEvidence.js";
import { createEvidence } from "./evidence.js";
import { jsonValueSchema } from "./jsonValue.js";
const inventoryEvidence = ARTIFACT_COMPARISON_EXAMPLE.left;
const target = inventoryEvidence.subject;
@@ -31,7 +30,7 @@ const inspectionEvidence = (result: unknown, subject = target) =>
{
operation: "inspect_artifact",
parameters: {},
result: jsonValueSchema.parse(result),
result,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -152,12 +151,12 @@ it("keeps a commitment failure discovered across individually incomplete pages a
parameters: {},
confidence: "observed",
authority: "shipped-artifact",
result: jsonValueSchema.parse({
result: {
...complete,
manifest,
nodes: includeNodes ? complete.nodes : [],
occurrences: includeNodes ? [] : complete.occurrences,
}),
},
},
);
const nodes = page(true);
+6 -8
View File
@@ -7,7 +7,7 @@ import {
} from "./changedBehavior.js";
import { createEvidence, type Evidence } from "./evidence.js";
import { functionComparisonResultSchema } from "./functionComparisonSchemas.js";
import { jsonValueSchema, type JsonValue } from "./jsonValue.js";
import type { JsonValue } from "./jsonValue.js";
const source = (digit: string): Evidence =>
createEvidence(
@@ -350,13 +350,11 @@ describe("changed-behavior input and Evidence validation", () => {
predicateType: base.predicate_type,
operation: base.operation,
parameters: base.parameters,
result: jsonValueSchema.parse(
functionComparisonResultSchema.parse({
...result,
dimensions,
changes: dimensions.filter(({ status }) => status !== "unchanged"),
}),
),
result: functionComparisonResultSchema.parse({
...result,
dimensions,
changes: dimensions.filter(({ status }) => status !== "unchanged"),
}),
confidence: base.confidence,
authority: base.authority,
evidenceLinks: base.evidence_links,
+1 -1
View File
@@ -664,7 +664,7 @@ describe("function comparison ordering controls", () => {
parameters: enhancedInputSchemas.analyze_function.parse({
procedure: "dispatch",
}),
result: jsonValueSchema.parse(result),
result,
confidence: "derived",
authority: "shipped-artifact",
relationshipCoverage: { status: "complete" },
+6 -8
View File
@@ -35,11 +35,9 @@ const artifactComparison = createEvidence(
left_evidence_ids: [ARTIFACT_COMPARISON_EXAMPLE.left.evidence_id],
right_evidence_ids: [ARTIFACT_COMPARISON_EXAMPLE.right.evidence_id],
},
result: jsonValueSchema.parse(
compareArtifacts(
ARTIFACT_COMPARISON_EXAMPLE.left,
ARTIFACT_COMPARISON_EXAMPLE.right,
),
result: compareArtifacts(
ARTIFACT_COMPARISON_EXAMPLE.left,
ARTIFACT_COMPARISON_EXAMPLE.right,
),
confidence: "derived",
authority: "analyst-inference",
@@ -157,10 +155,10 @@ it("keeps text, assembly and unavailable CFG caveats on their selected correlati
{
operation: source.operation,
parameters: source.parameters,
result: jsonValueSchema.parse({
result: {
...functionDossierSchema.parse(source.normalized_result),
basic_blocks: [{ start: "0x1000", end: "0x1000", successors: [] }],
}),
},
confidence: source.confidence,
authority: source.authority,
},
@@ -178,7 +176,7 @@ it("keeps text, assembly and unavailable CFG caveats on their selected correlati
left_evidence_id: left.evidence_id,
right_evidence_id: right.evidence_id,
},
result: jsonValueSchema.parse(computed),
result: computed,
confidence: "derived",
authority: "analyst-inference",
limitations: computed.limitations,
+1 -2
View File
@@ -6,7 +6,6 @@ import {
parseEvidenceBundle,
serializeEvidenceBundle,
} from "./evidenceBundle.js";
import { jsonValueSchema } from "./jsonValue.js";
import {
webMcpDiscoverySchema,
type WebMcpDiscovery,
@@ -106,7 +105,7 @@ describe("WebMCP discovery consequential annotation", () => {
predicateType: "rea.webmcp-discovery",
operation: "discover_webmcp_tools",
parameters: {},
result: jsonValueSchema.parse(result),
result,
});
const bundle = createEvidenceBundle([evidence]);
const reread = parseEvidenceBundle(
@@ -14,7 +14,7 @@ import {
parseEvidence,
type Evidence,
} from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest, type TestCli } from "../../support/cli/cliFixture.js";
@@ -75,7 +75,7 @@ const assertCoverageControls = async ({
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(result),
result: result,
confidence: "derived",
authority: "shipped-artifact",
},
@@ -1,4 +1,4 @@
import { rm, writeFile } from "node:fs/promises";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
@@ -145,7 +145,6 @@ it("closes an Electron inspection session when cleanup is cancelled", async () =
});
onTestFinished(async () => {
await browser.close();
await rm(root, { recursive: true, force: true });
});
const controller = new AbortController();
const pending = new CdpElectronProvider().inspectPage(
@@ -204,7 +203,6 @@ it("classifies cancellation that arrives during final Electron detach", async ()
});
onTestFinished(async () => {
await browser.close();
await rm(root, { recursive: true, force: true });
});
const result = await new CdpElectronProvider().inspectPage(
@@ -283,7 +281,6 @@ it.each(
closing.mockRestore();
await provider.close();
await browser.close();
await rm(root, { recursive: true, force: true });
});
const result =
provider instanceof CdpBrowserProvider
@@ -1,4 +1,4 @@
import { rm, writeFile } from "node:fs/promises";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
@@ -52,7 +52,6 @@ it.each([
| undefined;
if (closeProvider !== undefined) await closeProvider.call(provider);
await browser.close();
await rm(root, { recursive: true, force: true });
});
const close = vi
@@ -36,7 +36,7 @@ const observe = async (path: string) => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventory),
result: inventory,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -62,7 +62,7 @@ const inspectPages = (
{
operation: "inspect_artifact",
parameters: {},
result: jsonValueSchema.parse({
result: {
inspection_id: `ai_${"f".repeat(64)}`,
subject: {
manifest_id: inventory.manifest.manifest_id,
@@ -96,7 +96,7 @@ const inspectPages = (
},
evidence_links: pages.map(({ evidence_id }) => evidence_id),
limitations: [],
}),
},
confidence: "observed",
authority: "shipped-artifact",
},
@@ -144,7 +144,7 @@ describe("leaf artifact comparison", () => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(withoutCoverage),
result: withoutCoverage,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -306,11 +306,11 @@ describe("artifact inventory coverage", () => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse({
result: {
...graph,
coverage: { scope: "root", status: "unknown" },
limitations: ["No extra child entries were observed."],
}),
},
confidence: "derived",
authority: "shipped-artifact",
},
@@ -348,10 +348,10 @@ describe("artifact inventory coverage", () => {
{
operation: "inventory_artifact",
parameters: fragment.parameters,
result: jsonValueSchema.parse({
result: {
...fragmentGraph,
coverage: { ...fragmentGraph.coverage, status: "unknown" },
}),
},
confidence: "derived",
authority: "shipped-artifact",
},
@@ -448,10 +448,10 @@ describe("artifact comparison", () => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse({
result: {
...completeInventory,
nodes: [],
}),
},
confidence: "observed",
authority: "shipped-artifact",
limitations: ["Inventory node observations are unavailable."],
@@ -496,10 +496,10 @@ describe("artifact comparison completeness", () => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse({
result: {
...inventory,
coverage: { scope: "root", status: "complete" },
}),
},
confidence: "derived",
authority: "shipped-artifact",
},
@@ -862,10 +862,10 @@ describe("artifact comparison fragment integrity", () => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse({
result: {
...artifactInventoryResultSchema.parse(fragment.normalized_result),
coverage: { scope: "root", status: "complete" },
}),
},
},
);
expect(() =>
@@ -6,7 +6,7 @@ import { describe, expect, it } from "vitest";
import { inventoryArtifact } from "../../fixtures/artifactInventory.js";
import { compareArtifacts } from "../../../src/domain/artifactComparison.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const observe = async (
@@ -30,7 +30,7 @@ const observe = async (
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventory),
result: inventory,
confidence: partial ? "derived" : "observed",
authority: "shipped-artifact",
},
@@ -10,7 +10,7 @@ import { inventoryArtifact } from "../../fixtures/artifactInventory.js";
import { compareArtifacts } from "../../../src/domain/artifactComparison.js";
import type { ArtifactInventoryResult } from "../../../src/domain/artifactGraph.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const observeZip = async (entries: readonly (readonly [string, string])[]) => {
@@ -32,7 +32,7 @@ const observeZip = async (entries: readonly (readonly [string, string])[]) => {
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventory),
result: inventory,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -1360,6 +1360,30 @@ it.each([
},
);
it.each(["knip:production", "lint:typed"])(
"keeps the %s analysis command within static checks",
async (script) => {
const { directory } = await fixture();
const base = await change(
directory,
["package.json"],
JSON.stringify({ scripts: { [script]: "node scripts/old.mjs" } }),
);
const head = await change(
directory,
["package.json"],
JSON.stringify({ scripts: { [script]: "node scripts/new.mjs" } }),
);
expect(await classify(directory, base, head)).toMatchObject({
code: true,
runtime: false,
package: false,
evm: false,
browser: false,
});
},
);
it("retains a broad fallback when a provider script adds shared shell work", async () => {
const { directory } = await fixture();
const before = {
@@ -14,7 +14,7 @@ import {
import { reconcileJavaScriptRuntimeEvidence } from "../../../src/application/javascript/JavaScriptRuntimeReconciliationService.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { AnalysisInputError } from "../../../src/domain/analysisErrorCore.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { javascriptApplicationAnalysisResultSchema } from "../../../src/domain/javascript/javascriptApplicationAnalysis.js";
import {
applicationVersionComparisonResultSchema,
@@ -377,10 +377,10 @@ describe("Application graph Evidence envelopes", () => {
predicateType: source.predicate_type,
operation: source.operation,
parameters: source.parameters,
result: jsonValueSchema.parse({
result: {
...result,
evidence_links: [...result.evidence_links, extraLink],
}),
},
rawResult: source.raw_result,
confidence: source.confidence,
authority: source.authority,
@@ -479,7 +479,7 @@ describe("JavaScript application workflow error diagnostics", () => {
predicateType: evidence.predicate_type,
operation: evidence.operation,
parameters: evidence.parameters,
result: jsonValueSchema.parse(malformedResult),
result: malformedResult,
confidence: evidence.confidence,
authority: evidence.authority,
limitations: evidence.limitations,
@@ -0,0 +1,270 @@
import { parse } from "@babel/parser";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { expect } from "vitest";
import { z } from "zod";
import { writeRepositoryOxlintConfiguration } from "../../fixtures/oxlintConfiguration.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { processTest } from "../../support/process/processFixture.js";
const repository = fileURLToPath(new URL("../../../", import.meta.url));
const oxlint = join(repository, "node_modules/oxlint/bin/oxlint");
const applicationSource = "src/application/lintRuleAcceptance.ts";
const testSource = "tests/boundary/lintRuleAcceptance.test.ts";
interface AcceptanceCase {
readonly name: string;
readonly filename: string;
readonly source: string;
readonly exitCode: number;
readonly diagnostics: readonly {
readonly code?: string;
readonly severity: "error" | "warning";
readonly message?: string;
}[];
}
const cases: readonly AcceptanceCase[] = [
{
name: "enables imported Evidence JSON admission errors through the repository plugin",
filename: applicationSource,
source: `
import { createEvidence as record } from "../domain/evidence.js";
import { jsonValueSchema as json } from "../domain/jsonValue.js";
export const evidence = record(undefined, {}, { result: json.parse({ ready: true }) });
`,
exitCode: 1,
diagnostics: [
{ code: "rea(no-evidence-json-preadmission)", severity: "error" },
],
},
{
name: "recognizes canonical Evidence owners imported through file URLs",
filename: applicationSource,
source: `
import { createEvidence as record } from ${JSON.stringify(pathToFileURL(join(repository, "src/domain/evidence.js")).href)};
import { jsonValueSchema as json } from ${JSON.stringify(pathToFileURL(join(repository, "src/domain/jsonValue.js")).href)};
export const evidence = record(undefined, {}, { result: json.parse({ ready: true }) });
`,
exitCode: 1,
diagnostics: [
{ code: "rea(no-evidence-json-preadmission)", severity: "error" },
],
},
{
name: "allows semantic schema admission and stored JSON contracts",
filename: applicationSource,
source: `
import { z } from "zod";
import { createEvidence } from "../domain/evidence.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
const semanticSchema = z.object({ ready: z.boolean() });
export const semantic = createEvidence(undefined, {}, { result: semanticSchema.parse({ ready: true }) });
const result = jsonValueSchema.parse({ ready: true });
export const stored = createEvidence(undefined, {}, { result });
`,
exitCode: 0,
diagnostics: [],
},
{
name: "enables positional catalog type errors through the repository plugin",
filename: applicationSource,
source: `
import { GPU_TOOL_CONTRACTS as contracts } from "../contracts/gpu/gpuToolContracts.js";
export type Selected = (typeof contracts)[0];
`,
exitCode: 1,
diagnostics: [
{ code: "rea(no-positional-tool-contract)", severity: "error" },
],
},
{
name: "enables duplicate fixture root teardown errors through the repository plugin",
filename: testSource,
source: `
import { afterEach } from "vitest";
import { rm } from "node:fs/promises";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
const root = await createTestTempDirectory("rea-lint-rule-");
afterEach(() => rm(root, { recursive: true, force: true }));
`,
exitCode: 1,
diagnostics: [{ code: "rea(no-fixture-root-cleanup)", severity: "error" }],
},
{
name: "allows explicit root deletion outside fixture teardown",
filename: testSource,
source: `
import { rm } from "node:fs/promises";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
const root = await createTestTempDirectory("rea-lint-rule-");
await rm(root, { recursive: true, force: true });
`,
exitCode: 0,
diagnostics: [],
},
{
name: "rejects an unreturned promise callback containing assertions",
filename: testSource,
source: `
import { expect, it } from "vitest";
it("unjoined assertion", () => {
Promise.resolve("ready").then(value => { expect(value).toBe("ready"); });
});
`,
exitCode: 1,
diagnostics: [
{ code: "vitest(valid-expect-in-promise)", severity: "error" },
],
},
{
name: "rejects focused tests through the repository Vitest configuration",
filename: testSource,
source: `
import { expect, it } from "vitest";
it.only("focused assertion", () => { expect("ready").toBe("ready"); });
`,
exitCode: 1,
diagnostics: [{ code: "vitest(no-focused-tests)", severity: "error" }],
},
{
name: "keeps native stored assertion limitations at warning severity",
filename: testSource,
source: `
import { expect, it } from "vitest";
it("joins a stored assertion", async () => {
const assertion = expect(Promise.reject(new Error("controlled"))).rejects.toThrow("controlled");
await assertion;
});
`,
exitCode: 0,
diagnostics: [{ code: "vitest(valid-expect)", severity: "warning" }],
},
{
name: "allows an assertion diagnostic message",
filename: testSource,
source: `
import { expect, it } from "vitest";
it("keeps diagnostic context", () => {
expect("ready", "controlled diagnostic context").toBe("ready");
});
`,
exitCode: 0,
diagnostics: [],
},
{
name: "rejects unused suppression directives through the repository configuration",
filename: testSource,
source: `
// oxlint-disable-next-line no-var
export const ready = true;
`,
exitCode: 1,
diagnostics: [
{
severity: "error",
message: "Unused oxlint-disable directive (no problems were reported).",
},
],
},
];
const reportSchema = z.object({
diagnostics: z.array(
z.object({
code: z.string().optional(),
severity: z.enum(["error", "warning"]),
message: z.string(),
}),
),
});
const relocateImports = (scenario: AcceptanceCase, path: string): string => {
const source = scenario.source;
const parsed = parse(source, {
sourceType: "module",
plugins: ["typescript"],
});
const replacements = [];
for (const statement of parsed.program.body) {
if (
statement.type !== "ImportDeclaration" ||
!statement.source.value.startsWith(".")
)
continue;
const target = resolve(
repository,
dirname(scenario.filename),
statement.source.value,
);
const relativePath = relative(dirname(path), target);
const specifier = isAbsolute(relativePath)
? pathToFileURL(target).href
: relativePath.startsWith(".")
? relativePath.split(sep).join("/")
: `./${relativePath.split(sep).join("/")}`;
const { start, end } = statement.source;
if (
start === null ||
start === undefined ||
end === null ||
end === undefined
)
throw new Error("Authored lint fixture import has no source range");
replacements.push({
start,
end,
specifier,
});
}
let relocated = source;
for (const replacement of replacements.reverse())
relocated =
relocated.slice(0, replacement.start) +
JSON.stringify(replacement.specifier) +
relocated.slice(replacement.end);
return relocated;
};
for (const scenario of cases) {
processTest(scenario.name, async ({ processes }) => {
const project = await createTestTempDirectory("rea-lint-configuration-");
const configuration = await writeRepositoryOxlintConfiguration(project);
const path = join(project, scenario.filename);
await mkdir(dirname(path), { recursive: true });
await writeFile(path, relocateImports(scenario, path));
const result = await processes.run(
process.execPath,
[
oxlint,
"--config",
configuration,
"--threads",
"1",
"--format",
"json",
scenario.filename,
],
{
cwd: project,
timeoutMs: 15_000,
},
);
expect(result.signal, result.stderr).toBeNull();
expect(result.exitCode, result.stderr || result.stdout).toBe(
scenario.exitCode,
);
const { diagnostics } = reportSchema.parse(JSON.parse(result.stdout));
expect(
diagnostics.map(({ code, severity }) => ({ code, severity })),
).toEqual(
scenario.diagnostics.map(({ code, severity }) => ({ code, severity })),
);
for (const [index, expected] of scenario.diagnostics.entries()) {
if (expected.message !== undefined)
expect(diagnostics[index]?.message).toBe(expected.message);
}
});
}
@@ -0,0 +1,117 @@
import { spawnSync } from "node:child_process";
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, it } from "vitest";
import { parseProductionReachabilityReport } from "../../../scripts/ci/production-reachability-report.mjs";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const script = fileURLToPath(
new URL(
"../../../scripts/ci/production-reachability-report.mjs",
import.meta.url,
),
);
const configuration = new URL("../../../knip.production.json", import.meta.url);
const reportPath = (root: string) =>
join(root, ".cache/static-checks/production-reachability.json");
const invoke = (root: string) =>
spawnSync(process.execPath, [script], {
cwd: root,
encoding: "utf8",
timeout: 15_000,
});
it("reports test-only candidates without losing dynamic, worker or published roots", async () => {
const root = await createTestTempDirectory("rea-production-reachability-");
const files = {
"package.json": JSON.stringify({
name: "reachability-fixture",
type: "module",
bin: { fixture: "scripts/rea.mjs" },
exports: { "./published": "./src/published.ts" },
}),
"src/main.ts":
'import { live } from "./facts.js"; console.log(live); void import("./lazy.js");',
"src/facts.ts": "export const live = 1; export const testOnly = 2;",
"src/lazy.ts": "console.log('dynamic production module');",
"src/testOnly.ts": "export const retired = 3;",
"src/published.ts": "export const publicContract = 4;",
"src/composition/javascriptAnalysisWorkerProcess.ts":
'import { workerFact } from "../workerFacts.js"; console.log(workerFact);',
"src/workerFacts.ts": "export const workerFact = 5;",
"scripts/rea.mjs": 'import "../src/main.js";',
"tests/facts.test.ts":
'import { testOnly } from "../src/facts.js"; import { retired } from "../src/testOnly.js"; console.log(testOnly, retired);',
};
for (const [path, content] of Object.entries(files)) {
const destination = join(root, path);
await mkdir(dirname(destination), { recursive: true });
await writeFile(destination, content);
}
await writeFile(
join(root, "knip.production.json"),
await readFile(configuration, "utf8"),
);
const result = invoke(root);
expect(result.error).toBeUndefined();
expect(result.status, result.stderr).toBe(0);
expect(result.stdout).toContain("advisory candidates");
const { issues } = parseProductionReachabilityReport(
await readFile(reportPath(root), "utf8"),
);
expect(issues).toEqual(
expect.arrayContaining([
expect.objectContaining({
file: "src/facts.ts",
exports: expect.arrayContaining([
expect.objectContaining({ name: "testOnly" }),
]),
}),
expect.objectContaining({ file: "src/testOnly.ts" }),
]),
);
const reached = [
"src/main.ts",
"src/lazy.ts",
"src/published.ts",
"src/workerFacts.ts",
"src/composition/javascriptAnalysisWorkerProcess.ts",
"tests/facts.test.ts",
];
expect(issues.filter(({ file }) => reached.includes(file))).toEqual([]);
expect(
issues.flatMap(({ exports: findings = [] }) =>
findings.map(({ name }) => name),
),
).not.toContain("live");
});
it("fails on Knip configuration errors and removes a stale candidate report", async () => {
const root = await createTestTempDirectory(
"rea-production-reachability-error-",
);
await writeFile(join(root, "package.json"), '{"name":"broken-config"}');
await writeFile(join(root, "knip.production.json"), "{");
await mkdir(dirname(reportPath(root)), { recursive: true });
await writeFile(reportPath(root), '{"issues":[]}');
const result = invoke(root);
expect(result.error).toBeUndefined();
expect(result.status).not.toBe(0);
expect(result.stderr).toContain("Production reachability analysis failed");
await expect(access(reportPath(root))).rejects.toMatchObject({
code: "ENOENT",
});
});
it.each([
"not JSON",
'{"issues":[{"file":"src/facts.ts","exports":[{"name":42}]}]}',
'{"issues":[{"file":"src/facts.ts","unrecognized":[]}]}',
])("rejects malformed checker output: %s", (text) => {
expect(() => parseProductionReachabilityReport(text)).toThrow();
});
@@ -1,10 +1,11 @@
import { spawnSync } from "node:child_process";
import { access, cp, mkdir, readFile, writeFile } from "node:fs/promises";
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname, join, sep } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, it } from "vitest";
import { z } from "zod";
import { writeRepositoryOxlintConfiguration } from "../../fixtures/oxlintConfiguration.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const script = fileURLToPath(
@@ -149,11 +150,11 @@ it("keeps lint errors failing and visible alongside the retained warnings", asyn
it("excludes translation staging while retaining authored website errors", async () => {
const root = await fixture();
for (const name of [".gitignore", ".oxlintrc.json"])
await writeFile(join(root, name), await readFile(join(repository, name)));
await cp(join(repository, "scripts/lint"), join(root, "scripts/lint"), {
recursive: true,
});
await writeFile(
join(root, ".gitignore"),
await readFile(join(repository, ".gitignore")),
);
await writeRepositoryOxlintConfiguration(root);
const authored = "website/public/assets/authored.js";
const staged =
"website/.i18n-regression/site/examples/notes-electron/main.js";
@@ -166,7 +167,7 @@ it("excludes translation staging while retaining authored website errors", async
);
}
const result = invoke(root, "lint", "website");
const result = invoke(root, "lint");
expect(result.error).toBeUndefined();
expect(result.status).toBe(1);
expect(result.stdout).toContain("1 errors, 0 warnings");
@@ -0,0 +1,192 @@
import { mkdir, readFile, symlink, writeFile } from "node:fs/promises";
import { dirname, isAbsolute, join, relative, sep } from "node:path";
import { fileURLToPath } from "node:url";
import { expect } from "vitest";
import { z } from "zod";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { writeRepositoryOxlintConfiguration } from "../../fixtures/oxlintConfiguration.js";
import { processTest } from "../../support/process/processFixture.js";
const dependencies = fileURLToPath(
new URL("../../../node_modules", import.meta.url),
);
const reporter = fileURLToPath(
new URL("../../../scripts/ci/static-check-report.mjs", import.meta.url),
);
const sources = {
"src/unjoined.test.ts": `
import { expect, it } from "vitest";
const cliTest = it.extend<{ label: string }>({ label: "owned" });
it("forgets the assertion promise", () => {
expect(Promise.resolve("ready")).resolves.toBe("ready");
});
cliTest("forgets the assertion in an extended callback", ({ label }) => {
expect(Promise.resolve(label)).resolves.toBe("owned");
});
`,
"src/joined.test.ts": `
import { expect, it } from "vitest";
const cliTest = it.extend<{ label: string }>({ label: "owned" });
it("joins a stored assertion promise", async () => {
const assertion = expect(Promise.resolve("ready")).resolves.toBe("ready");
await assertion;
});
cliTest("joins a stored assertion in an extended callback", async ({ label }) => {
const assertion = expect(Promise.resolve(label)).resolves.toBe("owned");
await assertion;
});
export async function finishBeforeCleanup(): Promise<string> {
try {
return await Promise.resolve("ready");
} finally {
await Promise.resolve();
}
}
`,
"src/misused.ts": `
export function promiseCondition(): string {
if (Promise.resolve(false)) return "ready";
return "pending";
}
`,
"src/nonexhaustive.ts": `
type Outcome = { kind: "open" } | { kind: "closed" };
export function describeOutcome(outcome: Outcome): string {
switch (outcome.kind) {
case "open": return "open";
default: return "unknown";
}
}
`,
"src/unawaited-finally.ts": `
export async function cleanupBeforeCompletion(): Promise<string> {
try {
return Promise.resolve("ready");
} finally {
await Promise.resolve();
}
}
`,
"src/test-misused.test.ts": `
import { it } from "vitest";
it("keeps test-only promise conditions advisory", () => {
if (Promise.resolve(false)) throw new Error("test fixture");
});
`,
"tests/unjoined.test.ts": `
import { expect, it } from "vitest";
const cliTest = it.extend<{ label: string }>({ label: "owned" });
it("warns about an unjoined boundary-test assertion", () => {
expect(Promise.resolve("ready")).resolves.toBe("ready");
});
cliTest("warns in an extended boundary-test callback", ({ label }) => {
expect(Promise.resolve(label)).resolves.toBe("owned");
});
`,
};
processTest(
"runs typed promise and exhaustiveness rules on an isolated real TypeScript project",
async ({ processes }) => {
const root = await createTestTempDirectory("rea-typed-lint-");
await symlink(
dependencies,
join(root, "node_modules"),
process.platform === "win32" ? "junction" : "dir",
);
await Promise.all(
Object.keys(sources).map((name) =>
mkdir(dirname(join(root, name)), { recursive: true }),
),
);
await writeRepositoryOxlintConfiguration(root);
await Promise.all([
writeFile(join(root, "package.json"), '{"type":"module"}\n'),
writeFile(
join(root, "tsconfig.json"),
JSON.stringify({
compilerOptions: {
strict: true,
noEmit: true,
skipLibCheck: true,
module: "NodeNext",
moduleResolution: "NodeNext",
target: "ES2023",
types: ["node"],
},
files: Object.keys(sources),
}),
),
...Object.entries(sources).map(([name, source]) =>
writeFile(join(root, name), source),
),
]);
const result = await processes.run(
process.execPath,
[reporter, "typed-lint", ...Object.keys(sources)],
{
cwd: root,
timeoutMs: 20_000,
env: { ...process.env, GOMAXPROCS: "2", GOMEMLIMIT: "1GiB" },
},
);
expect(result.signal, result.stderr).toBeNull();
expect(result.exitCode, result.stderr || result.stdout).toBe(1);
const { diagnostics } = z
.object({
diagnostics: z.array(
z.object({
code: z.string(),
severity: z.enum(["error", "warning"]),
filename: z.string(),
}),
),
})
.parse(
JSON.parse(
await readFile(
join(root, ".cache/static-checks/typed-oxlint.json"),
"utf8",
),
),
);
expect(
diagnostics
.filter(({ code }) =>
[
"typescript(no-floating-promises)",
"typescript(no-misused-promises)",
"typescript(return-await)",
"typescript(switch-exhaustiveness-check)",
].includes(code),
)
.map(
({ code, filename, severity }) =>
`${(isAbsolute(filename) ? relative(root, filename) : filename).split(sep).join("/")}: ${severity}: ${code}`,
)
.sort(),
).toEqual([
"src/misused.ts: error: typescript(no-misused-promises)",
"src/nonexhaustive.ts: warning: typescript(switch-exhaustiveness-check)",
"src/test-misused.test.ts: warning: typescript(no-misused-promises)",
"src/unawaited-finally.ts: warning: typescript(return-await)",
"src/unjoined.test.ts: error: typescript(no-floating-promises)",
"src/unjoined.test.ts: error: typescript(no-floating-promises)",
"tests/unjoined.test.ts: warning: typescript(no-floating-promises)",
"tests/unjoined.test.ts: warning: typescript(no-floating-promises)",
]);
expect(
diagnostics.filter(({ severity }) => severity === "error"),
).toHaveLength(3);
},
);
@@ -1,4 +1,4 @@
import { mkdir, rm, writeFile } from "node:fs/promises";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it, onTestFinished, vi } from "vitest";
@@ -43,12 +43,11 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
it("retains cancelled source read ownership until service close retries it", async () => {
const root = await createTestTempDirectory("rea-web-artifact-read-owner-");
onTestFinished(async () => {
onTestFinished(() => {
injected.sourcePath = undefined;
injected.abortController = undefined;
injected.failClose = false;
injected.closeAttempts = 0;
await rm(root, { recursive: true, force: true });
});
const source = 'import "./dep.js";';
const fixture = webModuleArtifactsFixture(source);
@@ -20,7 +20,7 @@ import {
} from "../../../src/domain/evidence.js";
import { artifactInspectionResultSchema } from "../../../src/domain/artifactInspection.js";
import { artifactInventoryResultSchema } from "../../../src/domain/artifactGraph.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import {
analysisViewResultSchema,
type AnalysisViewResult,
@@ -446,10 +446,10 @@ it.each(["full", "compact"] as const)(
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse({
result: {
...graph,
occurrences: graph.occurrences.slice(0, 1),
}),
},
},
);
const partialReply = await client.callTool({
+4 -4
View File
@@ -12,7 +12,7 @@ import {
} from "../../../src/domain/evidence.js";
import { EvidenceIntegrityError } from "../../../src/domain/evidenceErrors.js";
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { artifactInventoryResultSchema } from "../../../src/domain/artifactGraph.js";
import {
artifactEdgeId,
@@ -468,7 +468,7 @@ it("records an explicitly continued mismatch, preserves verified siblings, and n
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventoryWithoutCoverage),
result: inventoryWithoutCoverage,
},
);
const retainedComparison = await client.callTool({
@@ -913,7 +913,7 @@ const withForeignMetadataAndNestedZipMember = (
parameters: evidence.parameters,
confidence: evidence.confidence,
authority: evidence.authority,
result: jsonValueSchema.parse({
result: {
...inventory,
occurrences,
edges,
@@ -924,7 +924,7 @@ const withForeignMetadataAndNestedZipMember = (
graph_sha256: graphSha256,
manifest_id: manifestId,
},
}),
},
},
);
};
@@ -12,7 +12,7 @@ import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { createAnalysisProfile } from "../../../src/domain/analysisProfile.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { ANALYSIS_SNAPSHOT_TARGET } from "../../../src/domain/analysisSnapshot.fixture.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { EMPTY_PROCESS_CAPTURE_EXAMPLE } from "../../../src/domain/process/processCaptureExample.js";
import { PROCESS_PROVIDER } from "../../../src/domain/process/processEvidenceProvider.js";
import { createServer } from "../../../src/server/createServer.js";
@@ -195,7 +195,7 @@ const createBundleSourceSession = () => {
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: {},
result: jsonValueSchema.parse(EMPTY_PROCESS_CAPTURE_EXAMPLE),
result: EMPTY_PROCESS_CAPTURE_EXAMPLE,
confidence: "observed",
authority: "controlled-replay",
}),
@@ -14,7 +14,7 @@ import {
type FunctionComparisonResult,
} from "../../../src/domain/functionComparisonSchemas.js";
import { summarize } from "../../../src/domain/functionComparisonResults.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
@@ -165,7 +165,7 @@ it.each([
predicateType: base.predicate_type,
operation: base.operation,
parameters: base.parameters,
result: jsonValueSchema.parse(scenario.result(result)),
result: scenario.result(result),
confidence: base.confidence,
authority: base.authority,
limitations: base.limitations,
@@ -9,7 +9,6 @@ import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarnes
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { createEvidenceBundle } from "../../../src/domain/evidenceBundle.js";
import { compareFunctions } from "../../../src/domain/functionComparison.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { FUNCTION_COMPARISON_EXAMPLE } from "../../../src/contracts/functionComparisonExample.js";
@@ -74,7 +73,7 @@ it.each([
{
operation: "analyze_function",
parameters: { procedure: entry },
result: jsonValueSchema.parse(value),
result: value,
confidence: "derived",
relationshipCoverage: { status: "complete" },
},
@@ -532,14 +531,14 @@ it.each([
};
const consistent = createEvidence(undefined, provider, {
...observation,
result: jsonValueSchema.parse(result),
result: result,
});
const inconsistent =
status === "unchanged"
? null
: createEvidence(undefined, provider, {
...observation,
result: jsonValueSchema.parse({ ...result, status: "unchanged" }),
result: { ...result, status: "unchanged" },
});
const directory = await createTestTempDirectory("rea-function-status-");
const path = join(directory, "bundle.json");
@@ -11,7 +11,7 @@ import {
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { functionComparisonResultSchema } from "../../../src/domain/functionComparisonSchemas.js";
import { functionDossierSchema } from "../../../src/domain/hopperValues.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { reconstructionVerificationResultSchema } from "../../../src/domain/reconstructionVerificationSchemas.js";
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
@@ -147,7 +147,7 @@ const evidence = (
? {}
: { analysisProfile: options.profile ?? profile }),
parameters: { ...example.parameters, observation: id },
result: jsonValueSchema.parse({
result: {
...dossier,
procedure: {
...dossier.procedure,
@@ -162,7 +162,7 @@ const evidence = (
callers: [...(options.callers ?? [])],
incoming_references: [...(options.incoming ?? [])],
outgoing_references: [...outgoing],
}),
},
confidence: "derived",
authority: "shipped-artifact",
relationshipCoverage: { status: "complete" },
@@ -8,7 +8,7 @@ import {
functionComparisonResultSchema,
type FunctionComparisonResult as Comparison,
} from "../../../src/domain/functionComparisonSchemas.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createServer } from "../../../src/server/createServer.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
@@ -30,7 +30,7 @@ const evidence = (
{
operation: "analyze_function",
parameters: { ...template.parameters, observation: id },
result: jsonValueSchema.parse({
result: {
...base,
referenced_strings: [...strings],
swift_string_literals:
@@ -47,7 +47,7 @@ const evidence = (
},
],
swift_string_literal_omissions: [],
}),
},
confidence: template.confidence,
authority: template.authority,
relationshipCoverage: { status: "complete" },
@@ -1,4 +1,4 @@
import { parseEvidence } from "../../../src/domain/evidence.js";
import { parseEvidence, createEvidence } from "../../../src/domain/evidence.js";
import { ok as resultOk } from "../../../src/domain/result.js";
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { expect, it } from "vitest";
@@ -14,18 +14,14 @@ import {
} from "../../../src/application/AnalysisProvider.js";
import type { BinarySession } from "../../../src/application/binary/BinarySession.js";
import { FUNCTION_COMPARISON_EXAMPLE } from "../../../src/contracts/functionComparisonExample.js";
import { INVESTIGATION_EXAMPLES } from "../../../src/contracts/investigationExamples.js";
import {
INVESTIGATION_EXAMPLES,
FUNCTION_COMPARISON_EVIDENCE,
PROCESS_CAPTURE_RECONSTRUCTION,
PROCESS_CAPTURE_REFERENCE,
PROCESS_COMPARISON_EVIDENCE,
} from "../../../src/contracts/investigationExamples.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import {
jsonObjectSchema,
jsonValueSchema,
} from "../../../src/domain/jsonValue.js";
import { jsonObjectSchema } from "../../../src/domain/jsonValue.js";
import { createServer } from "../../../src/server/createServer.js";
import { observed } from "../../fixtures/analysisExecution.js";
import type { RelationshipCoverage } from "../../../src/domain/relationshipCoverage.js";
@@ -217,7 +213,7 @@ const dossierWithCallees = (addresses: readonly string[]) => {
predicateType: base.predicate_type,
operation: base.operation,
parameters: base.parameters,
result: jsonValueSchema.parse({
result: {
...jsonObjectSchema.parse(base.normalized_result),
callees: addresses.map((address) => ({
address,
@@ -228,7 +224,7 @@ const dossierWithCallees = (addresses: readonly string[]) => {
reason: "The fixture has no callee body-extent observation.",
},
})),
}),
},
rawResult: base.raw_result,
confidence: base.confidence,
authority: base.authority,
@@ -5,7 +5,7 @@ import {
MANAGED_RECONSTRUCTION_IMPORT_EXAMPLE,
} from "../../../src/contracts/managed/managedWorkflowExamples.js";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import {
managedMemberInspectionSchema,
managedNativeBoundaryInspectionSchema,
@@ -34,7 +34,7 @@ const emptyExportEvidence = () => {
{
operation: "inspect_macho",
parameters: original.parameters,
result: jsonValueSchema.parse({
result: {
...result,
exports: {
items: [],
@@ -42,7 +42,7 @@ const emptyExportEvidence = () => {
exhaustive: true,
limitations: [],
},
}),
},
rawResult: null,
limitations: [],
},
@@ -63,7 +63,7 @@ const secondDeclaration = () => {
return createEvidence(undefined, original.provider, {
operation: "inspect_managed_native_boundaries",
parameters: original.parameters,
result: jsonValueSchema.parse({
result: {
...result,
pinvoke_imports: [
{
@@ -74,7 +74,7 @@ const secondDeclaration = () => {
import_name: "open_native_again",
},
],
}),
},
rawResult: null,
limitations: original.limitations,
});
@@ -128,7 +128,7 @@ const memberEvidence = (
{
operation: "inspect_managed_members",
parameters: original.parameters,
result: jsonValueSchema.parse(normalized),
result: normalized,
rawResult: null,
limitations: normalized.limitations,
},
@@ -27,7 +27,7 @@ import {
parseEvidence,
type EvidenceProvider,
} from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { digestProcessCommitment } from "../../../src/domain/process/processScenario.js";
import { createServer } from "../../../src/server/createServer.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
@@ -45,14 +45,14 @@ const captureEvidence = (
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: { side },
result: jsonValueSchema.parse({
result: {
...observation,
manifest: {
...observation.manifest,
comparison_contract: comparisonContract,
comparison_contract_sha256: digestProcessCommitment(comparisonContract),
},
}),
},
confidence: "observed",
authority: "controlled-replay",
});
@@ -523,7 +523,7 @@ it("names the side and constraint when Evidence is not a usable capture", async
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: {},
result: jsonValueSchema.parse(result),
result: result,
});
expect(parseEvidence(invalidResult)).toEqual(invalidResult);
const malformed = await client.callTool({
@@ -565,7 +565,7 @@ it("keeps structural capture issues alongside semantic ones through MCP and the
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: {},
result: jsonValueSchema.parse({
result: {
...rest,
manifest,
exit: {
@@ -577,7 +577,7 @@ it("keeps structural capture issues alongside semantic ones through MCP and the
],
},
},
}),
},
});
const described =
"(at manifest.completed_at: Invalid input: expected string, received undefined (1 more issues))";
@@ -5,7 +5,7 @@ import { expect, it, onTestFinished } from "vitest";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { createEvidenceBundle } from "../../../src/domain/evidenceBundle.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { EMPTY_PROCESS_CAPTURE_EXAMPLE } from "../../../src/domain/process/processCaptureExample.js";
import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js";
import { compareProcessCaptures } from "../../../src/domain/process/processComparison.js";
@@ -48,11 +48,11 @@ it("rejects an inconsistent imported process comparison while retaining its Evid
left_evidence_id: left.evidence_id,
right_evidence_id: right.evidence_id,
},
result: jsonValueSchema.parse({
result: {
...nativeResult,
[dimension]: "contradiction",
status,
}),
},
confidence: "derived",
authority: "analyst-inference",
evidenceLinks: [left.evidence_id, right.evidence_id],
@@ -11,7 +11,7 @@ import { compareProcessEvidenceFiles } from "../../../src/application/process/Pr
import { PROCESS_PROVIDER } from "../../../src/domain/process/processEvidenceProvider.js";
import { processTraceCaptureFixture } from "../../../src/domain/process/processCapture.fixture.js";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createServer } from "../../../src/server/createServer.js";
import { observed as ok } from "../../fixtures/analysisExecution.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
@@ -25,7 +25,7 @@ const captureEvidence = (side: "left" | "right") =>
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: { side },
result: jsonValueSchema.parse(capture),
result: capture,
confidence: "observed",
authority: "controlled-replay",
locations: [{ kind: "artifact-path", path: `/fixture/${side}` }],
+3 -3
View File
@@ -184,7 +184,7 @@ describe("guided prompt completion from investigation records", () => {
const inspectionEvidence = createEvidence(undefined, fixtureProvider, {
operation: "inspect_artifact",
parameters: {},
result: jsonValueSchema.parse(inventoryInspection),
result: inventoryInspection,
confidence: "observed",
authority: "shipped-artifact",
evidenceLinks: inventoryInspection.evidence_links,
@@ -426,7 +426,7 @@ const createPagedInspectionEvidence = async (
{
operation: "inventory_artifact",
parameters: {},
result: jsonValueSchema.parse(inventoryResult),
result: inventoryResult,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -530,7 +530,7 @@ const createPagedInspectionEvidence = async (
{
operation: "inspect_artifact",
parameters: {},
result: jsonValueSchema.parse(result),
result: result,
confidence: "observed",
authority: "shipped-artifact",
evidenceLinks: result.evidence_links,
+2 -2
View File
@@ -18,7 +18,7 @@ import { createServer } from "../../../src/server/createServer.js";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { parseEvidenceBundle } from "../../../src/domain/evidenceBundle.js";
import { EMPTY_PROCESS_CAPTURE_EXAMPLE } from "../../../src/domain/process/processCaptureExample.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { PROCESS_PROVIDER } from "../../../src/domain/process/processEvidenceProvider.js";
import { processCaptureSchema } from "../../../src/domain/process/processCapture.js";
@@ -153,7 +153,7 @@ it("records capture disagreement as a contradicted unknown", async () => {
predicateType: "rea.process-capture",
operation: "capture_process_scenario",
parameters: {},
result: jsonValueSchema.parse(capture),
result: capture,
confidence: "observed",
authority: "controlled-replay",
});
@@ -4,7 +4,7 @@ import { expect, it } from "vitest";
import { FUNCTION_COMPARISON_EXAMPLE } from "../../../src/contracts/functionComparisonExample.js";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { functionDossierSchema } from "../../../src/domain/hopperValues.js";
import { jsonValueSchema } from "../../../src/domain/jsonValue.js";
import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
@@ -44,7 +44,7 @@ const pathSource = () => {
...template.parameters,
observation: "workflow-unknown-path",
},
result: jsonValueSchema.parse({
result: {
...dossier,
callees: [
{
@@ -54,7 +54,7 @@ const pathSource = () => {
body: { available: false, reason: "No body was observed." },
},
],
}),
},
confidence: template.confidence,
authority: template.authority,
relationshipCoverage: { status: "complete" },
@@ -76,10 +76,8 @@ const incompleteRight = (suffix: string) => {
{
operation: "analyze_function",
parameters: { ...template.parameters, observation: suffix },
result: jsonValueSchema.parse(
functionDossierSchema.parse(
FUNCTION_COMPARISON_EXAMPLE.left.normalized_result,
),
result: functionDossierSchema.parse(
FUNCTION_COMPARISON_EXAMPLE.left.normalized_result,
),
confidence: template.confidence,
authority: template.authority,
@@ -12,15 +12,17 @@ import {
compareManagedMemberPaths,
} from "../../../../src/application/managed/ManagedMemberComparisonService.js";
import { parseBinaryTarget } from "../../../../src/application/BinaryTargetResolver.js";
import { managedMemberComparisonResultSchema } from "../../../../src/domain/managed/managedMemberComparison.js";
import {
managedMemberComparisonResultSchema,
compareManagedMembersInputSchema,
} from "../../../../src/domain/managed/managedMemberComparison.js";
import { readManagedMemberEvidence } from "../../../../src/domain/managed/managedMemberComparisonMatch.js";
import { createEvidence } from "../../../../src/domain/evidence.js";
import { projectAnalysisError } from "../../../../src/domain/analysisErrorProjection.js";
import { jsonValueSchema } from "../../../../src/domain/jsonValue.js";
import { compareManagedMembersInputSchema } from "../../../../src/domain/managed/managedMemberComparison.js";
import { inspectManagedMembersBytes } from "../../../../src/dotnet/ManagedMemberInspector.js";
import { managedPeFixtureTarget } from "../../../../src/dotnet/ManagedPe.fixture.js";
import {
managedPeFixtureTarget,
buildManagedNestedTypeFixture,
buildManagedPeFixture,
} from "../../../../src/dotnet/ManagedPe.fixture.js";
@@ -139,7 +141,7 @@ const compare = (
{
operation: "inspect_managed_members",
parameters: {},
result: jsonValueSchema.parse(change?.(inspection) ?? inspection),
result: change?.(inspection) ?? inspection,
confidence: "observed",
authority: "shipped-artifact",
},
@@ -475,14 +477,14 @@ describe("managed member comparison subject identity", () => {
{
operation: "inspect_managed_members",
parameters: {},
result: jsonValueSchema.parse({
result: {
...inspection,
artifact: { ...inspection.artifact, sha256: otherDigest },
identity_scope: {
...inspection.identity_scope,
requires_artifact_sha256: otherDigest,
},
}),
},
},
);
const aligned = createEvidence(
@@ -563,11 +565,11 @@ describe("managed call-target comparison", () => {
{
operation: "inspect_managed_members",
parameters: {},
result: jsonValueSchema.parse({
result: {
...inspection,
call_edges:
alterEdges?.(inspection.call_edges) ?? inspection.call_edges,
}),
},
confidence: "observed",
authority: "shipped-artifact",
},
@@ -636,10 +638,10 @@ describe("managed member comparison path workflow", () => {
{
operation: "inspect_managed_members",
parameters: {},
result: jsonValueSchema.parse({
result: {
...inspection,
coverage: { ...inspection.coverage, state: "partial" },
}),
},
confidence: "observed",
authority: "shipped-artifact",
},
@@ -0,0 +1,265 @@
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { RuleTester } from "oxlint/plugins-dev";
import { describe, it } from "vitest";
import rule from "../../scripts/lint/rules/no-evidence-json-preadmission.mjs";
const filename = resolve("src/application/RuleFixture.ts");
const imports = `
import { createEvidence, createImmutableEvidenceSteps } from "../domain/evidence.js";
import { jsonValueSchema, jsonObjectSchema } from "../domain/jsonValue.js";
`;
const evidenceSource = new URL("../../src/domain/evidence.js", import.meta.url);
const jsonSource = new URL("../../src/domain/jsonValue.js", import.meta.url);
const fileImports = `
import { createEvidence } from ${JSON.stringify(evidenceSource.href)};
import { jsonValueSchema } from ${JSON.stringify(jsonSource.href)};
`;
const absoluteImports = `
import { createEvidence } from ${JSON.stringify(fileURLToPath(evidenceSource))};
import { jsonValueSchema } from ${JSON.stringify(fileURLToPath(jsonSource))};
`;
const valid = (name: string, code: string) => ({ name, filename, code });
const invalid = (name: string, code: string, field: string) => ({
name,
filename,
code,
errors: [{ messageId: "redundantJsonAdmission", data: { field } }],
output: null,
});
RuleTester.describe = describe;
RuleTester.it = it;
new RuleTester({
languageOptions: { sourceType: "module", parserOptions: { lang: "ts" } },
}).run("no-evidence-json-preadmission", rule, {
valid: [
valid(
"file URL binding still respects lexical shadows",
`${fileImports}
function build(createEvidence) { createEvidence(target, provider, {result: jsonValueSchema.parse(input)}); }`,
),
valid(
"HTTP modules are not filesystem owners",
`
import { createEvidence } from "https://example.test/src/domain/evidence.js";
import { jsonValueSchema } from "https://example.test/src/domain/jsonValue.js";
createEvidence(target, provider, {result: jsonValueSchema.parse(input)});`,
),
valid(
"malformed file URLs do not crash owner lookup",
`
import {createEvidence} from "file://%";
import {jsonValueSchema} from ${JSON.stringify(jsonSource.href)};
createEvidence(target, provider, {result: jsonValueSchema.parse(input)});`,
),
valid(
"queried file URL does not establish the canonical owner",
`
import {createEvidence} from ${JSON.stringify(`${evidenceSource.href}?instance=other`)};
import {jsonValueSchema} from ${JSON.stringify(jsonSource.href)};
createEvidence(target, provider, {result: jsonValueSchema.parse(input)});`,
),
valid(
"fragment file URL does not establish the canonical schema",
`
import {createEvidence} from ${JSON.stringify(evidenceSource.href)};
import {jsonValueSchema} from ${JSON.stringify(`${jsonSource.href}#other`)};
createEvidence(target, provider, {result: jsonValueSchema.parse(input)});`,
),
valid(
"post-fix process capture keeps producer facts",
`${imports}
createEvidence(undefined, provider, { result: capture });`,
),
valid(
"semantic format admission remains",
`${imports}
createEvidence(target, provider, { result: processCaptureSchema.parse(capture) });`,
),
valid(
"standalone JSON admission remains",
`${imports}
const observation = { result: jsonValueSchema.parse(result) };
executeAnalysis(observation);`,
),
valid(
"strong immutable Evidence contract remains",
`${imports}
createImmutableEvidenceSteps(target, provider, { result: jsonValueSchema.parse(result) });`,
),
valid(
"digest helper owns its typed JSON input",
`${imports}
const parameters = { ...jsonObjectSchema.parse(scenario), digest: scenarioDigest(scenario) };
createEvidence(target, provider, { parameters });`,
),
valid(
"multiuse parsed value retains its separate contract",
`${imports}
const result = jsonValueSchema.parse(input);
consumeJson(result);
createEvidence(target, provider, { result });`,
),
valid(
"single-use typed local is outside the direct expression rule",
`${imports}
const result: JsonValue = jsonValueSchema.parse(input);
createEvidence(target, provider, { result });`,
),
valid(
"local creator shadows imported creator",
`${imports}
function build(createEvidence) {
return createEvidence(target, provider, { result: jsonValueSchema.parse(input) });
}`,
),
valid(
"local schema shadows imported schema",
`${imports}
function build(jsonValueSchema) {
return createEvidence(target, provider, { result: jsonValueSchema.parse(input) });
}`,
),
valid(
"namespace shadowing is respected",
`
import * as evidence from "../domain/evidence.js";
import * as json from "../domain/jsonValue.js";
function build(json) {
return evidence.createEvidence(target, provider, { result: json.jsonValueSchema.parse(input) });
}`,
),
valid(
"creator namespace shadowing is respected",
`
import * as evidence from "../domain/evidence.js";
import * as json from "../domain/jsonValue.js";
function build(evidence) {
return evidence.createEvidence(target, provider, { result: json.jsonValueSchema.parse(input) });
}`,
),
valid(
"same-named exports from another module are unrelated",
`
import { createEvidence } from "../other/evidence.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
createEvidence(target, provider, { result: jsonValueSchema.parse(input) });`,
),
valid(
"same-named schema from another module is unrelated",
`
import { createEvidence } from "../domain/evidence.js";
import { jsonValueSchema } from "../other/jsonValue.js";
createEvidence(target, provider, { result: jsonValueSchema.parse(input) });`,
),
valid(
"safeParse is a separate Result boundary",
`${imports}
createEvidence(target, provider, { result: jsonValueSchema.safeParse(input) });`,
),
valid(
"nested parsing is not an immediate payload admission",
`${imports}
createEvidence(target, provider, { parameters: { trace_spec: jsonValueSchema.parse(specification) } });`,
),
valid(
"later spread may replace the parsed field",
`${imports}
createEvidence(target, provider, { result: jsonValueSchema.parse(input), ...overrides });`,
),
valid(
"later duplicate field replaces the parsed field",
`${imports}
createEvidence(target, provider, { result: jsonValueSchema.parse(input), result: replacement });`,
),
valid(
"unknown computed field may replace the parsed field",
`${imports}
createEvidence(target, provider, { result: jsonValueSchema.parse(input), [field]: replacement });`,
),
valid(
"explicit parse options are outside the direct admission rule",
`${imports}
createEvidence(target, provider, { result: jsonValueSchema.parse(input, options) });`,
),
],
invalid: [
invalid(
"file URLs preserve canonical JSON ownership",
`${fileImports}
createEvidence(target, provider, {result: jsonValueSchema.parse(input)});`,
"result",
),
invalid(
"absolute paths preserve canonical JSON ownership",
`${absoluteImports}
createEvidence(target, provider, {result: jsonValueSchema.parse(input)});`,
"result",
),
invalid(
"pre-fix process capture repeats JSON admission",
`${imports}
createEvidence(undefined, PROCESS_PROVIDER, { result: jsonValueSchema.parse(capture) });`,
"result",
),
invalid(
"object parameters repeat generic admission",
`${imports}
createEvidence(target, provider, { parameters: jsonObjectSchema.parse(parameters) });`,
"parameters",
),
invalid(
"raw payload admission belongs to Evidence",
`${imports}
createEvidence(target, provider, { rawResult: jsonValueSchema.parse(raw) });`,
"rawResult",
),
invalid(
"aliased imports retain their owner",
`
import { createEvidence as record } from "../domain/evidence.js";
import { jsonValueSchema as json } from "../domain/jsonValue.js";
record(target, provider, { result: json.parse(input) });`,
"result",
),
invalid(
"namespace members retain their owner",
`
import * as evidence from "../domain/evidence.js";
import * as json from "../domain/jsonValue.js";
evidence.createEvidence(target, provider, { result: json.jsonValueSchema.parse(input) });`,
"result",
),
invalid(
"static computed members retain their owner",
`
import * as evidence from "../domain/evidence.js";
import * as json from "../domain/jsonValue.js";
evidence["createEvidence"](target, provider, { ["result"]: json["jsonValueSchema"]["parse"](input) });`,
"result",
),
invalid(
"TypeScript source specifiers resolve to the same owner",
`
import { createEvidence } from "../domain/evidence.ts";
import { jsonObjectSchema } from "../domain/jsonValue.ts";
createEvidence(target, provider, { parameters: jsonObjectSchema.parse(input) });`,
"parameters",
),
invalid(
"an earlier spread does not replace the final payload",
`${imports}
createEvidence(target, provider, { ...base, result: jsonValueSchema.parse(input) });`,
"result",
),
invalid(
"unrelated local scopes do not hide the import",
`${imports}
function unrelated(jsonValueSchema) { return jsonValueSchema.parse(input); }
createEvidence(target, provider, { result: jsonValueSchema.parse(input) });`,
"result",
),
],
});
@@ -0,0 +1,58 @@
import { describe, it } from "vitest";
import { fileURLToPath } from "node:url";
import { RuleTester } from "oxlint/plugins-dev";
import rule from "../../scripts/lint/rules/no-fixture-root-cleanup.mjs";
RuleTester.describe = describe;
RuleTester.it = it;
const tester = new RuleTester({
languageOptions: { parserOptions: { lang: "ts" } },
});
const filename = fileURLToPath(
new URL("../boundary/ruleControl.test.ts", import.meta.url),
);
const imports = `
import { createTestTempDirectory as temp } from "../fixtures/temporaryDirectory.js";
import { afterEach as cleanup, afterAll, onTestFinished } from "vitest";
import { rm as remove } from "node:fs/promises";
`;
const fixtureSource = new URL(
"../fixtures/temporaryDirectory.js",
import.meta.url,
);
const localCleanupImports = `import {afterEach} from "vitest"; import {rm} from "node:fs/promises";`;
tester.run("no-fixture-root-cleanup", rule, {
valid: [
`import {createTestTempDirectory as temp} from ${JSON.stringify(fixtureSource.href)}; ${localCleanupImports} function work(temp: Function) { const root = temp(); afterEach(() => rm(root)); }`,
`import {createTestTempDirectory as temp} from "https://example.test/tests/fixtures/temporaryDirectory.js"; ${localCleanupImports} const root = await temp("owned-"); afterEach(() => rm(root));`,
`import {createTestTempDirectory as temp} from ${JSON.stringify(`${fixtureSource.href}?other`)}; ${localCleanupImports} const root = await temp("owned-"); afterEach(() => rm(root));`,
`${imports} const root = await temp("owned-"); await remove(root, { recursive: true });`,
`${imports} const root = await temp("owned-"); cleanup(() => remove(join(root, "child"), {recursive: true}));`,
`${imports} const root = await otherOwner(); cleanup(() => remove(root, { recursive: true }));`,
`${imports} const root = await temp("owned-"); cleanup(async () => { const root = await otherOwner(); await remove(root, {recursive: true}); });`,
`${imports} function work(temp: Function) { const root = temp(); cleanup(() => remove(root)); }`,
`${imports} const root = await temp("owned-"); function unrelated(cleanup: Function) { cleanup(() => remove(root)); }`,
`${imports} const root = await temp("owned-"); cleanup(() => { function remove(root: string) {} remove(root); });`,
`${imports} const roots = []; const root = await temp("owned-"); roots.push(root); roots.push(await createIdaTarget()); cleanup(async () => { for (const owned of roots) await remove(owned); });`,
`${imports} let root = await temp("owned-"); root = await otherOwner(); cleanup(() => remove(root));`,
`${imports} const root = await temp("owned-"); cleanup(() => connection.close());`,
`${imports} import * as fs from "node:fs/promises"; const root = await temp("owned-"); cleanup((fs: {rm: Function}) => fs.rm(root));`,
`${imports} const root = await temp("owned-"); { const remove = otherOwner; cleanup(() => remove(root)); }`,
'import { createTestTempDirectory as temp } from "./unrelated.js"; import { afterEach } from "vitest"; import { rm } from "node:fs/promises"; const root = await temp(); afterEach(() => rm(root));',
`${imports} const root = await temp("owned-"); function callback(root: string) { return remove(root); } cleanup(callback);`,
].map((code) => ({ code, filename })),
invalid: [
`import {createTestTempDirectory as temp} from ${JSON.stringify(fixtureSource.href)}; ${localCleanupImports} const root = await temp("owned-"); afterEach(() => rm(root));`,
`import {createTestTempDirectory as temp} from ${JSON.stringify(fileURLToPath(fixtureSource))}; ${localCleanupImports} const root = await temp("owned-"); afterEach(() => rm(root));`,
`${imports} const root = await temp("owned-"); cleanup(() => remove(root, {recursive: true}));`,
`${imports} const root = await temp("owned-"); afterAll(async () => { await remove(root, {recursive: true}); });`,
`${imports} const root = await temp("owned-"); onTestFinished(() => remove(root, {recursive: true}));`,
`${imports} const root = await temp("owned-"); const alias = root; cleanup(() => remove(alias));`,
`${imports} const root = await temp("owned-"); async function release() { await remove(root); } cleanup(release);`,
`${imports} const root = await temp("owned-"); const release = () => remove(root); cleanup(release);`,
`${imports} import { rmSync } from "node:fs"; const root = await temp("owned-"); cleanup(() => rmSync(root, {recursive: true}));`,
`${imports} import { removeTestWorkspace as release } from "../support/workspace/workspaceFixture.js"; const root = await temp("owned-"); cleanup(() => release(root));`,
`${imports} const root = await temp("owned-"); cleanup(async () => { await connection.close(); await remove(root, {recursive: true}); });`,
'import * as fixture from "../fixtures/temporaryDirectory.ts"; import * as vitest from "vitest"; import * as fs from "node:fs/promises"; const root = await fixture.createTestTempDirectory("owned-"); vitest.afterEach(() => fs.rm(root, {recursive: true}));',
].map((code) => ({ code, filename, errors: [{ messageId: "duplicate" }] })),
});
@@ -0,0 +1,184 @@
import { describe, expect, it } from "vitest";
import { fileURLToPath } from "node:url";
import { RuleTester } from "oxlint/plugins-dev";
import rule from "../../scripts/lint/rules/no-positional-tool-contract.mjs";
import { collectToolCatalogSources } from "../../scripts/lint/rules/tool-catalog-sources.mjs";
RuleTester.describe = describe;
RuleTester.it = it;
const tester = new RuleTester({
languageOptions: { parserOptions: { lang: "ts" } },
});
const filename = fileURLToPath(
new URL("../../src/server/ruleControl.ts", import.meta.url),
);
const catalog =
'import { GPU_TOOL_CONTRACTS as contracts } from "../contracts/gpu/gpuToolContracts.js";';
const catalogSource = new URL(
"../../src/contracts/gpu/gpuToolContracts.js",
import.meta.url,
);
tester.run("no-positional-tool-contract", rule, {
valid: [
`import {GPU_TOOL_CONTRACTS as contracts} from ${JSON.stringify(catalogSource.href)}; function read(contracts: {name: string}[]) { return contracts[0].name; }`,
'import {GPU_TOOL_CONTRACTS as contracts} from "https://example.test/src/contracts/gpu/gpuToolContracts.js"; contracts[0].name;',
`import {GPU_TOOL_CONTRACTS as contracts} from ${JSON.stringify(`${catalogSource.href}#other`)}; contracts[0].name;`,
`${catalog} for (const contract of contracts) register(contract);`,
`${catalog} contracts.forEach(register);`,
`${catalog} const selected = contracts.find(contract => contract.name === "inspect_gpu_code_objects");`,
`${catalog} type Contract = (typeof contracts)[number];`,
`${catalog} const copies = [...contracts];`,
`${catalog} const [...copies] = contracts;`,
`${catalog} function read(contracts: {name: string}[]) { return contracts[0].name; }`,
`${catalog} function read() { const contracts = [{name: "local"}]; return contracts.at(0)?.name; }`,
'import { GPU_TOOL_CONTRACTS as contracts } from "../unrelated.js"; contracts[0].name;',
'import { unrelated as contracts } from "../contracts/gpu/gpuToolContracts.js"; contracts[0].name;',
'const TOOL_CONTRACTS = [{name: "local"}]; TOOL_CONTRACTS[0].name;',
`${catalog} const mutable = [...contracts]; mutable[0].inputSchema;`,
`${catalog} contracts.length;`,
`${catalog} contracts[0]; contracts.at(1); const [unused] = contracts;`,
`${catalog} expect(contracts[0]?.description).toContain("documented behavior");`,
`${catalog} const [first] = contracts; const toggled = contracts.map(contract => contract === first ? {...contract, returnsTargetContent: !contract.returnsTargetContent} : contract); createCatalogDigests(toggled);`,
`${catalog} const selected = contracts[0]; const alias = selected; display(alias.description);`,
`${catalog} const selected = contracts[0]; selected.name = "catalog-control";`,
`${catalog} const [selected] = contracts; const { description } = selected; display(description);`,
`${catalog} function toolRegistrationOptions(contract: unknown) {} toolRegistrationOptions(contracts[0]);`,
`${catalog} { const contracts = [{name: "local"}]; contracts[0].name; }`,
'import * as catalogs from "../contracts/gpu/gpuToolContracts.js"; function read(catalogs: {GPU_TOOL_CONTRACTS: {name: string}[]}) { return catalogs.GPU_TOOL_CONTRACTS[0].name; }',
'import * as catalogs from "../contracts/gpu/gpuToolContracts.js"; catalogs.other[0].name;',
].map((code) => ({ code, filename })),
invalid: [
`import {GPU_TOOL_CONTRACTS as contracts} from ${JSON.stringify(catalogSource.href)}; contracts[0].name;`,
`import {GPU_TOOL_CONTRACTS as contracts} from ${JSON.stringify(fileURLToPath(catalogSource))}; contracts[0].inputSchema;`,
`${catalog} import {toolRegistrationOptions as options} from ${JSON.stringify(new URL("../../src/server/toolRegistrationOptions.js", import.meta.url).href)}; options(contracts[0]);`,
`${catalog} register(contracts[0].name);`,
`${catalog} contracts["0"].inputSchema.parse(input);`,
`${catalog} contracts.at(-1)?.outputSchema;`,
`${catalog} contracts["at"](1)?.name;`,
`${catalog} const alias = contracts; alias[2].name;`,
`${catalog} const first = contracts; const second = first; second[0].outputSchema;`,
`${catalog} type Selected = (typeof contracts)[0];`,
`${catalog} const [first] = contracts; register(first.name);`,
`${catalog} const [, second] = contracts; const selected = second; selected.inputSchema;`,
`${catalog} const selected = contracts[0]; const alias = selected; alias.inputSchema;`,
`${catalog} const { inputSchema } = contracts[0];`,
`${catalog} import {toolRegistrationOptions as options} from "./toolRegistrationOptions.js"; options(contracts[0]);`,
`${catalog} import {applicationToolRegistrationOptions as options} from "./toolRegistrationOptions.ts"; const selected = contracts.at(0); options(selected);`,
`${catalog} const selected = contracts[0]; selected.name; selected.outputSchema;`,
'import * as catalogs from "../contracts/gpu/gpuToolContracts.js"; catalogs.GPU_TOOL_CONTRACTS[0].name;',
'import * as catalogs from "../contracts/gpu/gpuToolContracts.js"; type Selected = (typeof catalogs.GPU_TOOL_CONTRACTS)[0];',
'import { TOOL_CONTRACTS } from "../contracts/toolContracts.ts"; TOOL_CONTRACTS[0].name;',
'import { MODEL_TOOL_CONTRACTS as selected } from "../contracts/model/modelToolContracts.js"; selected[0].inputSchema;',
'import { IL2CPP_TOOL_CONTRACTS as selected } from "../contracts/il2cpp/il2cppToolContracts.js"; selected[0].outputSchema;',
'import { BROWSER_SCENARIO_TOOL_CONTRACTS as nested } from "../contracts/browserScenarioToolContracts.js"; nested[0].name;',
'import { FUNCTION_WORKFLOW_TOOL_CONTRACTS as nested } from "../contracts/functionWorkflowToolContracts.js"; nested.at(0)?.name;',
].map((code) => ({ code, filename, errors: [{ messageId: "positional" }] })),
});
const sourcePath = (name: string) =>
fileURLToPath(new URL(`./catalog-rule-fixture/${name}`, import.meta.url));
describe("canonical catalog source composition", () => {
it("discovers newly composed exports and nested groups without evaluating modules", () => {
const sources = new Map([
[
sourcePath("toolContracts.ts"),
`
import { NEW_CATALOG as renamed } from "./newCatalog.js";
import { GROUP } from "./group.js";
import { UNUSED } from "./unused.js";
const generated = buildContracts();
const local = [...renamed, ...GROUP, ...generated, ...UNUSED.map(makeContract)];
const alias = local;
export const TOOL_CONTRACTS = [...alias] as const;
`,
],
[
sourcePath("newCatalog.ts"),
`
throw new Error("Must never execute the runtime catalog");
export const NEW_CATALOG = [{name: "new_tool"}];
`,
],
[
sourcePath("group.ts"),
`
import { NESTED as alias } from "./nested.ts";
export const GROUP = [...alias] satisfies readonly unknown[];
`,
],
[
sourcePath("nested.ts"),
'export const NESTED = [{name: "nested_tool"}];',
],
]);
const actual = collectToolCatalogSources(
sourcePath("toolContracts.ts"),
(path) => {
const source = sources.get(path);
if (source === undefined)
throw new Error(`Unexpected source read: ${path}`);
return source;
},
);
expect(actual).toEqual(
new Map([
[sourcePath("toolContracts"), new Set(["TOOL_CONTRACTS"])],
[sourcePath("newCatalog"), new Set(["NEW_CATALOG"])],
[sourcePath("group"), new Set(["GROUP"])],
[sourcePath("nested"), new Set(["NESTED"])],
]),
);
});
it("accepts official computed definitions while discovering imported catalog groups", () => {
const actual = collectToolCatalogSources(
fileURLToPath(
new URL("../../src/contracts/toolContracts.ts", import.meta.url),
),
);
const official = fileURLToPath(
new URL("../../src/contracts/officialToolContracts", import.meta.url),
);
const definitions = fileURLToPath(
new URL("../../src/contracts/hopperMemoryContracts", import.meta.url),
);
const nested = fileURLToPath(
new URL(
"../../src/contracts/browserScenarioToolContracts",
import.meta.url,
),
);
expect(actual.get(official)).toEqual(new Set(["OFFICIAL_TOOL_CONTRACTS"]));
expect(actual.has(definitions)).toBe(false);
expect(actual.get(nested)).toEqual(
new Set(["BROWSER_SCENARIO_TOOL_CONTRACTS"]),
);
});
it("propagates source-read and parse failures instead of disabling enforcement", () => {
const failure = new Error("catalog source unavailable");
expect(() =>
collectToolCatalogSources(sourcePath("toolContracts.ts"), () => {
throw failure;
}),
).toThrow(failure);
expect(() =>
collectToolCatalogSources(
sourcePath("toolContracts.ts"),
() => "export const TOOL_CONTRACTS = [",
),
).toThrow();
});
it.each([
"export const TOOL_CONTRACTS = buildCatalog();",
"export const OTHER = [];",
"const alias = alias; export const TOOL_CONTRACTS = [...alias];",
"export const TOOL_CONTRACTS = [...unresolved];",
])("refuses unsupported or missing canonical composition: %s", (source) => {
expect(() =>
collectToolCatalogSources(sourcePath("toolContracts.ts"), () => source),
).toThrow();
});
});
+2 -3
View File
@@ -1,6 +1,5 @@
import { artifactInventoryResultSchema } from "../../src/domain/artifactGraph.js";
import { createEvidence, type Evidence } from "../../src/domain/evidence.js";
import { jsonValueSchema } from "../../src/domain/jsonValue.js";
/** Partition a real scan into authenticated partial observations for merge tests. */
export const fragmentInventoryEvidence = (
@@ -26,7 +25,7 @@ export const fragmentInventoryEvidence = (
parameters: evidence.parameters,
confidence: "derived",
authority: evidence.authority,
result: jsonValueSchema.parse({
result: {
...inventory,
nodes: inventory.nodes.filter(
(_, ordinal) => ordinal % count === index,
@@ -37,7 +36,7 @@ export const fragmentInventoryEvidence = (
edges: inventory.edges.filter(
(_, ordinal) => ordinal % count === index,
),
}),
},
},
),
);
+3 -3
View File
@@ -1,5 +1,5 @@
import { createEvidence, type Evidence } from "../../src/domain/evidence.js";
import { jsonValueSchema } from "../../src/domain/jsonValue.js";
import { FUNCTION_COMPARISON_EXAMPLE } from "../../src/contracts/functionComparisonExample.js";
import type { NativeSymbolMetadata } from "../../src/domain/native/nativeSymbol.js";
import { functionDossierSchema } from "../../src/domain/hopperValues.js";
@@ -24,7 +24,7 @@ export const nativeMatchingInventory = (
createEvidence(nativeMatchingTarget(side), nativeMatchingProvider, {
operation: "list_procedures",
parameters: {},
result: jsonValueSchema.parse(entries),
result: entries,
evidenceLinks: [...evidenceLinks],
});
/** Explicit imported-origin fixture for tests that select exact-symbol correspondence. */
@@ -97,7 +97,7 @@ export const nativeMatchingDetails = (
observation = createEvidence(target, nativeMatchingProvider, {
operation: "analyze_function",
parameters: { procedure: address },
result: jsonValueSchema.parse(value),
result: value,
relationshipCoverage: { status: "complete" },
});
} else
+39
View File
@@ -0,0 +1,39 @@
import { readFile, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { z } from "zod";
const repository = fileURLToPath(new URL("../../", import.meta.url));
const configurationSchema = z.looseObject({
jsPlugins: z
.array(z.union([z.string(), z.looseObject({ specifier: z.string() })]))
.optional(),
});
/** Preserve repository lint policy while resolving local plugins at their owner. */
export const writeRepositoryOxlintConfiguration = async (
project: string,
): Promise<string> => {
const configuration = configurationSchema.parse(
JSON.parse(await readFile(join(repository, ".oxlintrc.json"), "utf8")),
);
const rebase = (specifier: string): string =>
specifier.startsWith(".") ? resolve(repository, specifier) : specifier;
const path = join(project, ".oxlintrc.json");
await writeFile(
path,
JSON.stringify({
...configuration,
...(configuration.jsPlugins === undefined
? {}
: {
jsPlugins: configuration.jsPlugins.map((plugin) =>
typeof plugin === "string"
? rebase(plugin)
: { ...plugin, specifier: rebase(plugin.specifier) },
),
}),
}),
);
return path;
};
+2 -2
View File
@@ -1,7 +1,7 @@
import { readyReviewedLedgerRequest } from "../../src/application/ReconstructionObligationLedger.fixture.js";
import { createEvidence } from "../../src/domain/evidence.js";
import { createEvidenceBundle } from "../../src/domain/evidenceBundle.js";
import { jsonValueSchema } from "../../src/domain/jsonValue.js";
import { reconstructionObligationProofSchema } from "../../src/domain/reconstructionObligationProof.js";
import type { ReconstructionObligationLedgerInput } from "../../src/domain/reconstructionObligationLedgerSchemas.js";
@@ -16,7 +16,7 @@ const replaceProof = (
predicateType: original.predicate_type,
operation: original.operation,
parameters: original.parameters,
result: jsonValueSchema.parse(result),
result: result,
confidence: original.confidence,
authority: original.authority,
});
+1 -2
View File
@@ -5,7 +5,6 @@ import { browserScenarioCaptureSchema } from "../../src/domain/browserScenarioCa
import { DEFAULT_BROWSER_SCENARIO_CAPTURE_LIMITS } from "../../src/domain/browserScenarioCaptureLimits.js";
import { browserScenarioEventSchema } from "../../src/domain/browserScenarioCaptureValues.js";
import { createEvidence } from "../../src/domain/evidence.js";
import { jsonValueSchema } from "../../src/domain/jsonValue.js";
/** Source-owned script capture with independently authored bytes. */
export const scriptScenarioFixture = (
@@ -134,7 +133,7 @@ export const scriptCaptureEvidenceFixture = () =>
{ id: "source-fixture", name: "Source fixture", version: "1" },
{
operation: "capture_browser_scenario",
result: jsonValueSchema.parse(scriptScenarioFixture()),
result: scriptScenarioFixture(),
parameters: {},
confidence: "observed",
authority: "controlled-replay",