@zbigniewsobiecki/squint 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1065 -0
- package/bin/dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/commands/_shared/db-helper.d.ts +18 -0
- package/dist/commands/_shared/db-helper.d.ts.map +1 -0
- package/dist/commands/_shared/db-helper.js +72 -0
- package/dist/commands/_shared/db-helper.js.map +1 -0
- package/dist/commands/_shared/flags.d.ts +20 -0
- package/dist/commands/_shared/flags.d.ts.map +1 -0
- package/dist/commands/_shared/flags.js +38 -0
- package/dist/commands/_shared/flags.js.map +1 -0
- package/dist/commands/_shared/index.d.ts +6 -0
- package/dist/commands/_shared/index.d.ts.map +1 -0
- package/dist/commands/_shared/index.js +6 -0
- package/dist/commands/_shared/index.js.map +1 -0
- package/dist/commands/_shared/output.d.ts +22 -0
- package/dist/commands/_shared/output.d.ts.map +1 -0
- package/dist/commands/_shared/output.js +36 -0
- package/dist/commands/_shared/output.js.map +1 -0
- package/dist/commands/_shared/source-reader.d.ts +23 -0
- package/dist/commands/_shared/source-reader.d.ts.map +1 -0
- package/dist/commands/_shared/source-reader.js +45 -0
- package/dist/commands/_shared/source-reader.js.map +1 -0
- package/dist/commands/_shared/symbol-resolver.d.ts +35 -0
- package/dist/commands/_shared/symbol-resolver.d.ts.map +1 -0
- package/dist/commands/_shared/symbol-resolver.js +102 -0
- package/dist/commands/_shared/symbol-resolver.js.map +1 -0
- package/dist/commands/browse.d.ts +13 -0
- package/dist/commands/browse.d.ts.map +1 -0
- package/dist/commands/browse.js +106 -0
- package/dist/commands/browse.js.map +1 -0
- package/dist/commands/domains/create.d.ts +15 -0
- package/dist/commands/domains/create.d.ts.map +1 -0
- package/dist/commands/domains/create.js +34 -0
- package/dist/commands/domains/create.js.map +1 -0
- package/dist/commands/domains/delete.d.ts +14 -0
- package/dist/commands/domains/delete.d.ts.map +1 -0
- package/dist/commands/domains/delete.js +41 -0
- package/dist/commands/domains/delete.js.map +1 -0
- package/dist/commands/domains/index.d.ts +2 -0
- package/dist/commands/domains/index.d.ts.map +1 -0
- package/dist/commands/domains/index.js +2 -0
- package/dist/commands/domains/index.js.map +1 -0
- package/dist/commands/domains/list.d.ts +12 -0
- package/dist/commands/domains/list.d.ts.map +1 -0
- package/dist/commands/domains/list.js +67 -0
- package/dist/commands/domains/list.js.map +1 -0
- package/dist/commands/domains/merge.d.ts +14 -0
- package/dist/commands/domains/merge.d.ts.map +1 -0
- package/dist/commands/domains/merge.js +40 -0
- package/dist/commands/domains/merge.js.map +1 -0
- package/dist/commands/domains/rename.d.ts +14 -0
- package/dist/commands/domains/rename.d.ts.map +1 -0
- package/dist/commands/domains/rename.js +33 -0
- package/dist/commands/domains/rename.js.map +1 -0
- package/dist/commands/domains/show.d.ts +14 -0
- package/dist/commands/domains/show.d.ts.map +1 -0
- package/dist/commands/domains/show.js +47 -0
- package/dist/commands/domains/show.js.map +1 -0
- package/dist/commands/domains/sync.d.ts +11 -0
- package/dist/commands/domains/sync.d.ts.map +1 -0
- package/dist/commands/domains/sync.js +33 -0
- package/dist/commands/domains/sync.js.map +1 -0
- package/dist/commands/domains/update.d.ts +14 -0
- package/dist/commands/domains/update.d.ts.map +1 -0
- package/dist/commands/domains/update.js +28 -0
- package/dist/commands/domains/update.js.map +1 -0
- package/dist/commands/features/assign.d.ts +16 -0
- package/dist/commands/features/assign.d.ts.map +1 -0
- package/dist/commands/features/assign.js +51 -0
- package/dist/commands/features/assign.js.map +1 -0
- package/dist/commands/features/create.d.ts +15 -0
- package/dist/commands/features/create.d.ts.map +1 -0
- package/dist/commands/features/create.js +30 -0
- package/dist/commands/features/create.js.map +1 -0
- package/dist/commands/features/delete.d.ts +14 -0
- package/dist/commands/features/delete.d.ts.map +1 -0
- package/dist/commands/features/delete.js +37 -0
- package/dist/commands/features/delete.js.map +1 -0
- package/dist/commands/features/generate.d.ts +34 -0
- package/dist/commands/features/generate.d.ts.map +1 -0
- package/dist/commands/features/generate.js +178 -0
- package/dist/commands/features/generate.js.map +1 -0
- package/dist/commands/features/index.d.ts +2 -0
- package/dist/commands/features/index.d.ts.map +1 -0
- package/dist/commands/features/index.js +2 -0
- package/dist/commands/features/index.js.map +1 -0
- package/dist/commands/features/list.d.ts +11 -0
- package/dist/commands/features/list.d.ts.map +1 -0
- package/dist/commands/features/list.js +45 -0
- package/dist/commands/features/list.js.map +1 -0
- package/dist/commands/features/show.d.ts +15 -0
- package/dist/commands/features/show.d.ts.map +1 -0
- package/dist/commands/features/show.js +61 -0
- package/dist/commands/features/show.js.map +1 -0
- package/dist/commands/features/unassign.d.ts +16 -0
- package/dist/commands/features/unassign.d.ts.map +1 -0
- package/dist/commands/features/unassign.js +55 -0
- package/dist/commands/features/unassign.js.map +1 -0
- package/dist/commands/features/update.d.ts +16 -0
- package/dist/commands/features/update.d.ts.map +1 -0
- package/dist/commands/features/update.js +54 -0
- package/dist/commands/features/update.js.map +1 -0
- package/dist/commands/files/imported-by.d.ts +13 -0
- package/dist/commands/files/imported-by.d.ts.map +1 -0
- package/dist/commands/files/imported-by.js +40 -0
- package/dist/commands/files/imported-by.js.map +1 -0
- package/dist/commands/files/imports.d.ts +14 -0
- package/dist/commands/files/imports.d.ts.map +1 -0
- package/dist/commands/files/imports.js +48 -0
- package/dist/commands/files/imports.js.map +1 -0
- package/dist/commands/files/index.d.ts +2 -0
- package/dist/commands/files/index.d.ts.map +1 -0
- package/dist/commands/files/index.js +2 -0
- package/dist/commands/files/index.js.map +1 -0
- package/dist/commands/files/list.d.ts +11 -0
- package/dist/commands/files/list.d.ts.map +1 -0
- package/dist/commands/files/list.js +35 -0
- package/dist/commands/files/list.js.map +1 -0
- package/dist/commands/files/orphans.d.ts +12 -0
- package/dist/commands/files/orphans.d.ts.map +1 -0
- package/dist/commands/files/orphans.js +43 -0
- package/dist/commands/files/orphans.js.map +1 -0
- package/dist/commands/files/show.d.ts +14 -0
- package/dist/commands/files/show.d.ts.map +1 -0
- package/dist/commands/files/show.js +95 -0
- package/dist/commands/files/show.js.map +1 -0
- package/dist/commands/flows/add-step.d.ts +19 -0
- package/dist/commands/flows/add-step.d.ts.map +1 -0
- package/dist/commands/flows/add-step.js +46 -0
- package/dist/commands/flows/add-step.js.map +1 -0
- package/dist/commands/flows/create.d.ts +17 -0
- package/dist/commands/flows/create.d.ts.map +1 -0
- package/dist/commands/flows/create.js +39 -0
- package/dist/commands/flows/create.js.map +1 -0
- package/dist/commands/flows/delete.d.ts +14 -0
- package/dist/commands/flows/delete.d.ts.map +1 -0
- package/dist/commands/flows/delete.js +37 -0
- package/dist/commands/flows/delete.js.map +1 -0
- package/dist/commands/flows/generate.d.ts +50 -0
- package/dist/commands/flows/generate.d.ts.map +1 -0
- package/dist/commands/flows/generate.js +438 -0
- package/dist/commands/flows/generate.js.map +1 -0
- package/dist/commands/flows/index.d.ts +2 -0
- package/dist/commands/flows/index.d.ts.map +1 -0
- package/dist/commands/flows/index.js +2 -0
- package/dist/commands/flows/index.js.map +1 -0
- package/dist/commands/flows/list.d.ts +12 -0
- package/dist/commands/flows/list.d.ts.map +1 -0
- package/dist/commands/flows/list.js +98 -0
- package/dist/commands/flows/list.js.map +1 -0
- package/dist/commands/flows/remove-step.d.ts +18 -0
- package/dist/commands/flows/remove-step.d.ts.map +1 -0
- package/dist/commands/flows/remove-step.js +41 -0
- package/dist/commands/flows/remove-step.js.map +1 -0
- package/dist/commands/flows/show.d.ts +17 -0
- package/dist/commands/flows/show.d.ts.map +1 -0
- package/dist/commands/flows/show.js +136 -0
- package/dist/commands/flows/show.js.map +1 -0
- package/dist/commands/flows/trace.d.ts +22 -0
- package/dist/commands/flows/trace.d.ts.map +1 -0
- package/dist/commands/flows/trace.js +217 -0
- package/dist/commands/flows/trace.js.map +1 -0
- package/dist/commands/flows/update.d.ts +17 -0
- package/dist/commands/flows/update.d.ts.map +1 -0
- package/dist/commands/flows/update.js +60 -0
- package/dist/commands/flows/update.js.map +1 -0
- package/dist/commands/flows/verify.d.ts +21 -0
- package/dist/commands/flows/verify.d.ts.map +1 -0
- package/dist/commands/flows/verify.js +123 -0
- package/dist/commands/flows/verify.js.map +1 -0
- package/dist/commands/gaps.d.ts +14 -0
- package/dist/commands/gaps.d.ts.map +1 -0
- package/dist/commands/gaps.js +184 -0
- package/dist/commands/gaps.js.map +1 -0
- package/dist/commands/hierarchy/index.d.ts +20 -0
- package/dist/commands/hierarchy/index.d.ts.map +1 -0
- package/dist/commands/hierarchy/index.js +344 -0
- package/dist/commands/hierarchy/index.js.map +1 -0
- package/dist/commands/ingest.d.ts +23 -0
- package/dist/commands/ingest.d.ts.map +1 -0
- package/dist/commands/ingest.js +249 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/interactions/create.d.ts +16 -0
- package/dist/commands/interactions/create.d.ts.map +1 -0
- package/dist/commands/interactions/create.js +58 -0
- package/dist/commands/interactions/create.js.map +1 -0
- package/dist/commands/interactions/delete.d.ts +16 -0
- package/dist/commands/interactions/delete.d.ts.map +1 -0
- package/dist/commands/interactions/delete.js +28 -0
- package/dist/commands/interactions/delete.js.map +1 -0
- package/dist/commands/interactions/generate.d.ts +62 -0
- package/dist/commands/interactions/generate.d.ts.map +1 -0
- package/dist/commands/interactions/generate.js +870 -0
- package/dist/commands/interactions/generate.js.map +1 -0
- package/dist/commands/interactions/index.d.ts +2 -0
- package/dist/commands/interactions/index.d.ts.map +1 -0
- package/dist/commands/interactions/index.js +2 -0
- package/dist/commands/interactions/index.js.map +1 -0
- package/dist/commands/interactions/list.d.ts +15 -0
- package/dist/commands/interactions/list.d.ts.map +1 -0
- package/dist/commands/interactions/list.js +127 -0
- package/dist/commands/interactions/list.js.map +1 -0
- package/dist/commands/interactions/show.d.ts +17 -0
- package/dist/commands/interactions/show.d.ts.map +1 -0
- package/dist/commands/interactions/show.js +80 -0
- package/dist/commands/interactions/show.js.map +1 -0
- package/dist/commands/interactions/update.d.ts +20 -0
- package/dist/commands/interactions/update.d.ts.map +1 -0
- package/dist/commands/interactions/update.js +57 -0
- package/dist/commands/interactions/update.js.map +1 -0
- package/dist/commands/interactions/validate.d.ts +12 -0
- package/dist/commands/interactions/validate.d.ts.map +1 -0
- package/dist/commands/interactions/validate.js +94 -0
- package/dist/commands/interactions/validate.js.map +1 -0
- package/dist/commands/interactions/verify.d.ts +18 -0
- package/dist/commands/interactions/verify.d.ts.map +1 -0
- package/dist/commands/interactions/verify.js +127 -0
- package/dist/commands/interactions/verify.js.map +1 -0
- package/dist/commands/llm/_shared/base-llm-command.d.ts +44 -0
- package/dist/commands/llm/_shared/base-llm-command.d.ts.map +1 -0
- package/dist/commands/llm/_shared/base-llm-command.js +73 -0
- package/dist/commands/llm/_shared/base-llm-command.js.map +1 -0
- package/dist/commands/llm/_shared/coverage.d.ts +61 -0
- package/dist/commands/llm/_shared/coverage.d.ts.map +1 -0
- package/dist/commands/llm/_shared/coverage.js +161 -0
- package/dist/commands/llm/_shared/coverage.js.map +1 -0
- package/dist/commands/llm/_shared/csv-utils.d.ts +65 -0
- package/dist/commands/llm/_shared/csv-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/csv-utils.js +231 -0
- package/dist/commands/llm/_shared/csv-utils.js.map +1 -0
- package/dist/commands/llm/_shared/csv.d.ts +44 -0
- package/dist/commands/llm/_shared/csv.d.ts.map +1 -0
- package/dist/commands/llm/_shared/csv.js +76 -0
- package/dist/commands/llm/_shared/csv.js.map +1 -0
- package/dist/commands/llm/_shared/entity-utils.d.ts +11 -0
- package/dist/commands/llm/_shared/entity-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/entity-utils.js +87 -0
- package/dist/commands/llm/_shared/entity-utils.js.map +1 -0
- package/dist/commands/llm/_shared/flow-csv.d.ts +74 -0
- package/dist/commands/llm/_shared/flow-csv.d.ts.map +1 -0
- package/dist/commands/llm/_shared/flow-csv.js +198 -0
- package/dist/commands/llm/_shared/flow-csv.js.map +1 -0
- package/dist/commands/llm/_shared/flow-prompts.d.ts +61 -0
- package/dist/commands/llm/_shared/flow-prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/flow-prompts.js +281 -0
- package/dist/commands/llm/_shared/flow-prompts.js.map +1 -0
- package/dist/commands/llm/_shared/flow-validation.d.ts +69 -0
- package/dist/commands/llm/_shared/flow-validation.d.ts.map +1 -0
- package/dist/commands/llm/_shared/flow-validation.js +176 -0
- package/dist/commands/llm/_shared/flow-validation.js.map +1 -0
- package/dist/commands/llm/_shared/llm-utils.d.ts +88 -0
- package/dist/commands/llm/_shared/llm-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/llm-utils.js +256 -0
- package/dist/commands/llm/_shared/llm-utils.js.map +1 -0
- package/dist/commands/llm/_shared/module-csv.d.ts +76 -0
- package/dist/commands/llm/_shared/module-csv.d.ts.map +1 -0
- package/dist/commands/llm/_shared/module-csv.js +196 -0
- package/dist/commands/llm/_shared/module-csv.js.map +1 -0
- package/dist/commands/llm/_shared/module-prompts.d.ts +107 -0
- package/dist/commands/llm/_shared/module-prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/module-prompts.js +395 -0
- package/dist/commands/llm/_shared/module-prompts.js.map +1 -0
- package/dist/commands/llm/_shared/process-utils.d.ts +52 -0
- package/dist/commands/llm/_shared/process-utils.d.ts.map +1 -0
- package/dist/commands/llm/_shared/process-utils.js +214 -0
- package/dist/commands/llm/_shared/process-utils.js.map +1 -0
- package/dist/commands/llm/_shared/prompts.d.ts +132 -0
- package/dist/commands/llm/_shared/prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/prompts.js +391 -0
- package/dist/commands/llm/_shared/prompts.js.map +1 -0
- package/dist/commands/llm/_shared/pure-check.d.ts +10 -0
- package/dist/commands/llm/_shared/pure-check.d.ts.map +1 -0
- package/dist/commands/llm/_shared/pure-check.js +449 -0
- package/dist/commands/llm/_shared/pure-check.js.map +1 -0
- package/dist/commands/llm/_shared/verify/content-verifier.d.ts +40 -0
- package/dist/commands/llm/_shared/verify/content-verifier.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/content-verifier.js +247 -0
- package/dist/commands/llm/_shared/verify/content-verifier.js.map +1 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.d.ts +34 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.js +1096 -0
- package/dist/commands/llm/_shared/verify/coverage-checker.js.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.d.ts +30 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.js +118 -0
- package/dist/commands/llm/_shared/verify/verify-prompts.js.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-types.d.ts +47 -0
- package/dist/commands/llm/_shared/verify/verify-types.d.ts.map +1 -0
- package/dist/commands/llm/_shared/verify/verify-types.js +2 -0
- package/dist/commands/llm/_shared/verify/verify-types.js.map +1 -0
- package/dist/commands/llm/annotate.d.ts +7 -0
- package/dist/commands/llm/annotate.d.ts.map +1 -0
- package/dist/commands/llm/annotate.js +11 -0
- package/dist/commands/llm/annotate.js.map +1 -0
- package/dist/commands/llm/features/feature-grouper.d.ts +31 -0
- package/dist/commands/llm/features/feature-grouper.d.ts.map +1 -0
- package/dist/commands/llm/features/feature-grouper.js +223 -0
- package/dist/commands/llm/features/feature-grouper.js.map +1 -0
- package/dist/commands/llm/features/index.d.ts +6 -0
- package/dist/commands/llm/features/index.d.ts.map +1 -0
- package/dist/commands/llm/features/index.js +6 -0
- package/dist/commands/llm/features/index.js.map +1 -0
- package/dist/commands/llm/features/types.d.ts +10 -0
- package/dist/commands/llm/features/types.d.ts.map +1 -0
- package/dist/commands/llm/features/types.js +5 -0
- package/dist/commands/llm/features/types.js.map +1 -0
- package/dist/commands/llm/features.d.ts +7 -0
- package/dist/commands/llm/features.d.ts.map +1 -0
- package/dist/commands/llm/features.js +11 -0
- package/dist/commands/llm/features.js.map +1 -0
- package/dist/commands/llm/flows/atomic-flow-builder.d.ts +51 -0
- package/dist/commands/llm/flows/atomic-flow-builder.d.ts.map +1 -0
- package/dist/commands/llm/flows/atomic-flow-builder.js +247 -0
- package/dist/commands/llm/flows/atomic-flow-builder.js.map +1 -0
- package/dist/commands/llm/flows/dedup.d.ts +18 -0
- package/dist/commands/llm/flows/dedup.d.ts.map +1 -0
- package/dist/commands/llm/flows/dedup.js +76 -0
- package/dist/commands/llm/flows/dedup.js.map +1 -0
- package/dist/commands/llm/flows/entry-point-detector.d.ts +41 -0
- package/dist/commands/llm/flows/entry-point-detector.d.ts.map +1 -0
- package/dist/commands/llm/flows/entry-point-detector.js +388 -0
- package/dist/commands/llm/flows/entry-point-detector.js.map +1 -0
- package/dist/commands/llm/flows/flow-enhancer.d.ts +21 -0
- package/dist/commands/llm/flows/flow-enhancer.d.ts.map +1 -0
- package/dist/commands/llm/flows/flow-enhancer.js +166 -0
- package/dist/commands/llm/flows/flow-enhancer.js.map +1 -0
- package/dist/commands/llm/flows/flow-tracer.d.ts +50 -0
- package/dist/commands/llm/flows/flow-tracer.d.ts.map +1 -0
- package/dist/commands/llm/flows/flow-tracer.js +271 -0
- package/dist/commands/llm/flows/flow-tracer.js.map +1 -0
- package/dist/commands/llm/flows/flow-validator.d.ts +31 -0
- package/dist/commands/llm/flows/flow-validator.d.ts.map +1 -0
- package/dist/commands/llm/flows/flow-validator.js +262 -0
- package/dist/commands/llm/flows/flow-validator.js.map +1 -0
- package/dist/commands/llm/flows/gap-flow-generator.d.ts +13 -0
- package/dist/commands/llm/flows/gap-flow-generator.d.ts.map +1 -0
- package/dist/commands/llm/flows/gap-flow-generator.js +48 -0
- package/dist/commands/llm/flows/gap-flow-generator.js.map +1 -0
- package/dist/commands/llm/flows/index.d.ts +12 -0
- package/dist/commands/llm/flows/index.d.ts.map +1 -0
- package/dist/commands/llm/flows/index.js +12 -0
- package/dist/commands/llm/flows/index.js.map +1 -0
- package/dist/commands/llm/flows/types.d.ts +87 -0
- package/dist/commands/llm/flows/types.d.ts.map +1 -0
- package/dist/commands/llm/flows/types.js +5 -0
- package/dist/commands/llm/flows/types.js.map +1 -0
- package/dist/commands/llm/flows.d.ts +7 -0
- package/dist/commands/llm/flows.d.ts.map +1 -0
- package/dist/commands/llm/flows.js +11 -0
- package/dist/commands/llm/flows.js.map +1 -0
- package/dist/commands/llm/interactions.d.ts +7 -0
- package/dist/commands/llm/interactions.d.ts.map +1 -0
- package/dist/commands/llm/interactions.js +11 -0
- package/dist/commands/llm/interactions.js.map +1 -0
- package/dist/commands/llm/modules.d.ts +7 -0
- package/dist/commands/llm/modules.d.ts.map +1 -0
- package/dist/commands/llm/modules.js +11 -0
- package/dist/commands/llm/modules.js.map +1 -0
- package/dist/commands/llm/relationships.d.ts +7 -0
- package/dist/commands/llm/relationships.d.ts.map +1 -0
- package/dist/commands/llm/relationships.js +11 -0
- package/dist/commands/llm/relationships.js.map +1 -0
- package/dist/commands/modules/assign.d.ts +14 -0
- package/dist/commands/modules/assign.d.ts.map +1 -0
- package/dist/commands/modules/assign.js +54 -0
- package/dist/commands/modules/assign.js.map +1 -0
- package/dist/commands/modules/create.d.ts +16 -0
- package/dist/commands/modules/create.d.ts.map +1 -0
- package/dist/commands/modules/create.js +37 -0
- package/dist/commands/modules/create.js.map +1 -0
- package/dist/commands/modules/delete.d.ts +14 -0
- package/dist/commands/modules/delete.d.ts.map +1 -0
- package/dist/commands/modules/delete.js +54 -0
- package/dist/commands/modules/delete.js.map +1 -0
- package/dist/commands/modules/generate.d.ts +84 -0
- package/dist/commands/modules/generate.d.ts.map +1 -0
- package/dist/commands/modules/generate.js +1234 -0
- package/dist/commands/modules/generate.js.map +1 -0
- package/dist/commands/modules/index.d.ts +2 -0
- package/dist/commands/modules/index.d.ts.map +1 -0
- package/dist/commands/modules/index.js +2 -0
- package/dist/commands/modules/index.js.map +1 -0
- package/dist/commands/modules/list.d.ts +13 -0
- package/dist/commands/modules/list.d.ts.map +1 -0
- package/dist/commands/modules/list.js +92 -0
- package/dist/commands/modules/list.js.map +1 -0
- package/dist/commands/modules/prune.d.ts +10 -0
- package/dist/commands/modules/prune.d.ts.map +1 -0
- package/dist/commands/modules/prune.js +23 -0
- package/dist/commands/modules/prune.js.map +1 -0
- package/dist/commands/modules/show.d.ts +15 -0
- package/dist/commands/modules/show.d.ts.map +1 -0
- package/dist/commands/modules/show.js +95 -0
- package/dist/commands/modules/show.js.map +1 -0
- package/dist/commands/modules/unassign.d.ts +13 -0
- package/dist/commands/modules/unassign.d.ts.map +1 -0
- package/dist/commands/modules/unassign.js +49 -0
- package/dist/commands/modules/unassign.js.map +1 -0
- package/dist/commands/modules/update.d.ts +15 -0
- package/dist/commands/modules/update.d.ts.map +1 -0
- package/dist/commands/modules/update.js +50 -0
- package/dist/commands/modules/update.js.map +1 -0
- package/dist/commands/modules/verify.d.ts +18 -0
- package/dist/commands/modules/verify.d.ts.map +1 -0
- package/dist/commands/modules/verify.js +114 -0
- package/dist/commands/modules/verify.js.map +1 -0
- package/dist/commands/overview.d.ts +12 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +219 -0
- package/dist/commands/overview.js.map +1 -0
- package/dist/commands/parse.d.ts +30 -0
- package/dist/commands/parse.d.ts.map +1 -0
- package/dist/commands/parse.js +211 -0
- package/dist/commands/parse.js.map +1 -0
- package/dist/commands/process-groups/index.d.ts +2 -0
- package/dist/commands/process-groups/index.d.ts.map +1 -0
- package/dist/commands/process-groups/index.js +2 -0
- package/dist/commands/process-groups/index.js.map +1 -0
- package/dist/commands/process-groups/list.d.ts +11 -0
- package/dist/commands/process-groups/list.d.ts.map +1 -0
- package/dist/commands/process-groups/list.js +98 -0
- package/dist/commands/process-groups/list.js.map +1 -0
- package/dist/commands/relationships/annotate.d.ts +27 -0
- package/dist/commands/relationships/annotate.d.ts.map +1 -0
- package/dist/commands/relationships/annotate.js +453 -0
- package/dist/commands/relationships/annotate.js.map +1 -0
- package/dist/commands/relationships/index.d.ts +2 -0
- package/dist/commands/relationships/index.d.ts.map +1 -0
- package/dist/commands/relationships/index.js +2 -0
- package/dist/commands/relationships/index.js.map +1 -0
- package/dist/commands/relationships/list.d.ts +18 -0
- package/dist/commands/relationships/list.d.ts.map +1 -0
- package/dist/commands/relationships/list.js +147 -0
- package/dist/commands/relationships/list.js.map +1 -0
- package/dist/commands/relationships/next.d.ts +17 -0
- package/dist/commands/relationships/next.d.ts.map +1 -0
- package/dist/commands/relationships/next.js +178 -0
- package/dist/commands/relationships/next.js.map +1 -0
- package/dist/commands/relationships/set.d.ts +19 -0
- package/dist/commands/relationships/set.d.ts.map +1 -0
- package/dist/commands/relationships/set.js +65 -0
- package/dist/commands/relationships/set.js.map +1 -0
- package/dist/commands/relationships/show.d.ts +13 -0
- package/dist/commands/relationships/show.d.ts.map +1 -0
- package/dist/commands/relationships/show.js +59 -0
- package/dist/commands/relationships/show.js.map +1 -0
- package/dist/commands/relationships/unset.d.ts +16 -0
- package/dist/commands/relationships/unset.d.ts.map +1 -0
- package/dist/commands/relationships/unset.js +62 -0
- package/dist/commands/relationships/unset.js.map +1 -0
- package/dist/commands/relationships/verify.d.ts +24 -0
- package/dist/commands/relationships/verify.d.ts.map +1 -0
- package/dist/commands/relationships/verify.js +328 -0
- package/dist/commands/relationships/verify.js.map +1 -0
- package/dist/commands/stats.d.ts +11 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +207 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/symbols/annotate.d.ts +32 -0
- package/dist/commands/symbols/annotate.d.ts.map +1 -0
- package/dist/commands/symbols/annotate.js +862 -0
- package/dist/commands/symbols/annotate.js.map +1 -0
- package/dist/commands/symbols/deps.d.ts +18 -0
- package/dist/commands/symbols/deps.d.ts.map +1 -0
- package/dist/commands/symbols/deps.js +104 -0
- package/dist/commands/symbols/deps.js.map +1 -0
- package/dist/commands/symbols/index.d.ts +2 -0
- package/dist/commands/symbols/index.d.ts.map +1 -0
- package/dist/commands/symbols/index.js +2 -0
- package/dist/commands/symbols/index.js.map +1 -0
- package/dist/commands/symbols/list.d.ts +17 -0
- package/dist/commands/symbols/list.d.ts.map +1 -0
- package/dist/commands/symbols/list.js +136 -0
- package/dist/commands/symbols/list.js.map +1 -0
- package/dist/commands/symbols/next.d.ts +15 -0
- package/dist/commands/symbols/next.d.ts.map +1 -0
- package/dist/commands/symbols/next.js +147 -0
- package/dist/commands/symbols/next.js.map +1 -0
- package/dist/commands/symbols/prereqs.d.ts +18 -0
- package/dist/commands/symbols/prereqs.d.ts.map +1 -0
- package/dist/commands/symbols/prereqs.js +107 -0
- package/dist/commands/symbols/prereqs.js.map +1 -0
- package/dist/commands/symbols/ready.d.ts +17 -0
- package/dist/commands/symbols/ready.d.ts.map +1 -0
- package/dist/commands/symbols/ready.js +126 -0
- package/dist/commands/symbols/ready.js.map +1 -0
- package/dist/commands/symbols/set.d.ts +27 -0
- package/dist/commands/symbols/set.d.ts.map +1 -0
- package/dist/commands/symbols/set.js +241 -0
- package/dist/commands/symbols/set.js.map +1 -0
- package/dist/commands/symbols/show.d.ts +19 -0
- package/dist/commands/symbols/show.d.ts.map +1 -0
- package/dist/commands/symbols/show.js +182 -0
- package/dist/commands/symbols/show.js.map +1 -0
- package/dist/commands/symbols/understood.d.ts +15 -0
- package/dist/commands/symbols/understood.d.ts.map +1 -0
- package/dist/commands/symbols/understood.js +101 -0
- package/dist/commands/symbols/understood.js.map +1 -0
- package/dist/commands/symbols/unset.d.ts +16 -0
- package/dist/commands/symbols/unset.d.ts.map +1 -0
- package/dist/commands/symbols/unset.js +48 -0
- package/dist/commands/symbols/unset.js.map +1 -0
- package/dist/commands/symbols/verify.d.ts +25 -0
- package/dist/commands/symbols/verify.d.ts.map +1 -0
- package/dist/commands/symbols/verify.js +360 -0
- package/dist/commands/symbols/verify.js.map +1 -0
- package/dist/db/connection.d.ts +14 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +37 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/database-facade.d.ts +125 -0
- package/dist/db/database-facade.d.ts.map +1 -0
- package/dist/db/database-facade.js +347 -0
- package/dist/db/database-facade.js.map +1 -0
- package/dist/db/database.d.ts +9 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +11 -0
- package/dist/db/database.js.map +1 -0
- package/dist/db/index.d.ts +7 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +11 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/repositories/_shared/call-graph-query.d.ts +10 -0
- package/dist/db/repositories/_shared/call-graph-query.d.ts.map +1 -0
- package/dist/db/repositories/_shared/call-graph-query.js +59 -0
- package/dist/db/repositories/_shared/call-graph-query.js.map +1 -0
- package/dist/db/repositories/call-graph-service.d.ts +28 -0
- package/dist/db/repositories/call-graph-service.d.ts.map +1 -0
- package/dist/db/repositories/call-graph-service.js +223 -0
- package/dist/db/repositories/call-graph-service.js.map +1 -0
- package/dist/db/repositories/definition-repository.d.ts +99 -0
- package/dist/db/repositories/definition-repository.d.ts.map +1 -0
- package/dist/db/repositories/definition-repository.js +317 -0
- package/dist/db/repositories/definition-repository.js.map +1 -0
- package/dist/db/repositories/dependency-repository.d.ts +78 -0
- package/dist/db/repositories/dependency-repository.d.ts.map +1 -0
- package/dist/db/repositories/dependency-repository.js +446 -0
- package/dist/db/repositories/dependency-repository.js.map +1 -0
- package/dist/db/repositories/domain-repository.d.ts +97 -0
- package/dist/db/repositories/domain-repository.d.ts.map +1 -0
- package/dist/db/repositories/domain-repository.js +261 -0
- package/dist/db/repositories/domain-repository.js.map +1 -0
- package/dist/db/repositories/feature-repository.d.ts +64 -0
- package/dist/db/repositories/feature-repository.d.ts.map +1 -0
- package/dist/db/repositories/feature-repository.js +189 -0
- package/dist/db/repositories/feature-repository.js.map +1 -0
- package/dist/db/repositories/file-repository.d.ts +67 -0
- package/dist/db/repositories/file-repository.d.ts.map +1 -0
- package/dist/db/repositories/file-repository.js +179 -0
- package/dist/db/repositories/file-repository.js.map +1 -0
- package/dist/db/repositories/flow-repository.d.ts +172 -0
- package/dist/db/repositories/flow-repository.d.ts.map +1 -0
- package/dist/db/repositories/flow-repository.js +599 -0
- package/dist/db/repositories/flow-repository.js.map +1 -0
- package/dist/db/repositories/graph-repository.d.ts +93 -0
- package/dist/db/repositories/graph-repository.d.ts.map +1 -0
- package/dist/db/repositories/graph-repository.js +413 -0
- package/dist/db/repositories/graph-repository.js.map +1 -0
- package/dist/db/repositories/index.d.ts +20 -0
- package/dist/db/repositories/index.d.ts.map +1 -0
- package/dist/db/repositories/index.js +15 -0
- package/dist/db/repositories/index.js.map +1 -0
- package/dist/db/repositories/interaction-analysis.d.ts +78 -0
- package/dist/db/repositories/interaction-analysis.d.ts.map +1 -0
- package/dist/db/repositories/interaction-analysis.js +340 -0
- package/dist/db/repositories/interaction-analysis.js.map +1 -0
- package/dist/db/repositories/interaction-repository.d.ts +145 -0
- package/dist/db/repositories/interaction-repository.d.ts.map +1 -0
- package/dist/db/repositories/interaction-repository.js +395 -0
- package/dist/db/repositories/interaction-repository.js.map +1 -0
- package/dist/db/repositories/metadata-repository.d.ts +110 -0
- package/dist/db/repositories/metadata-repository.d.ts.map +1 -0
- package/dist/db/repositories/metadata-repository.js +294 -0
- package/dist/db/repositories/metadata-repository.js.map +1 -0
- package/dist/db/repositories/module-repository.d.ts +162 -0
- package/dist/db/repositories/module-repository.d.ts.map +1 -0
- package/dist/db/repositories/module-repository.js +519 -0
- package/dist/db/repositories/module-repository.js.map +1 -0
- package/dist/db/repositories/relationship-repository.d.ts +98 -0
- package/dist/db/repositories/relationship-repository.d.ts.map +1 -0
- package/dist/db/repositories/relationship-repository.js +421 -0
- package/dist/db/repositories/relationship-repository.js.map +1 -0
- package/dist/db/schema-manager.d.ts +31 -0
- package/dist/db/schema-manager.d.ts.map +1 -0
- package/dist/db/schema-manager.js +398 -0
- package/dist/db/schema-manager.js.map +1 -0
- package/dist/db/schema.d.ts +404 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +234 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/utils/tree-builder.d.ts +25 -0
- package/dist/db/utils/tree-builder.d.ts.map +1 -0
- package/dist/db/utils/tree-builder.js +38 -0
- package/dist/db/utils/tree-builder.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/ast-parser.d.ts +23 -0
- package/dist/parser/ast-parser.d.ts.map +1 -0
- package/dist/parser/ast-parser.js +65 -0
- package/dist/parser/ast-parser.js.map +1 -0
- package/dist/parser/definition-extractor.d.ts +29 -0
- package/dist/parser/definition-extractor.d.ts.map +1 -0
- package/dist/parser/definition-extractor.js +379 -0
- package/dist/parser/definition-extractor.js.map +1 -0
- package/dist/parser/reference-extractor.d.ts +72 -0
- package/dist/parser/reference-extractor.d.ts.map +1 -0
- package/dist/parser/reference-extractor.js +759 -0
- package/dist/parser/reference-extractor.js.map +1 -0
- package/dist/utils/file-scanner.d.ts +6 -0
- package/dist/utils/file-scanner.d.ts.map +1 -0
- package/dist/utils/file-scanner.js +33 -0
- package/dist/utils/file-scanner.js.map +1 -0
- package/dist/web/api-transforms.d.ts +4 -0
- package/dist/web/api-transforms.d.ts.map +1 -0
- package/dist/web/api-transforms.js +4 -0
- package/dist/web/api-transforms.js.map +1 -0
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +229 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/server.test.d.ts +2 -0
- package/dist/web/server.test.d.ts.map +1 -0
- package/dist/web/server.test.js +505 -0
- package/dist/web/server.test.js.map +1 -0
- package/dist/web/transforms/flow-transforms.d.ts +117 -0
- package/dist/web/transforms/flow-transforms.d.ts.map +1 -0
- package/dist/web/transforms/flow-transforms.js +202 -0
- package/dist/web/transforms/flow-transforms.js.map +1 -0
- package/dist/web/transforms/index.d.ts +4 -0
- package/dist/web/transforms/index.d.ts.map +1 -0
- package/dist/web/transforms/index.js +4 -0
- package/dist/web/transforms/index.js.map +1 -0
- package/dist/web/transforms/module-transforms.d.ts +42 -0
- package/dist/web/transforms/module-transforms.d.ts.map +1 -0
- package/dist/web/transforms/module-transforms.js +64 -0
- package/dist/web/transforms/module-transforms.js.map +1 -0
- package/dist/web/transforms/symbol-transforms.d.ts +31 -0
- package/dist/web/transforms/symbol-transforms.d.ts.map +1 -0
- package/dist/web/transforms/symbol-transforms.js +95 -0
- package/dist/web/transforms/symbol-transforms.js.map +1 -0
- package/package.json +96 -0
- package/ui/dist/assets/index-DP3dRMlh.js +268 -0
- package/ui/dist/assets/index-DP3dRMlh.js.map +1 -0
- package/ui/dist/assets/index-Db204Xn1.css +1 -0
- package/ui/dist/index.html +67 -0
|
@@ -0,0 +1,1096 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1: Deterministic coverage and structural checks (no LLM required).
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { isTestFile } from '../module-prompts.js';
|
|
6
|
+
import { detectImpurePatterns } from '../pure-check.js';
|
|
7
|
+
/**
|
|
8
|
+
* Read source lines from a file synchronously (for use in non-async verification).
|
|
9
|
+
*/
|
|
10
|
+
function readSourceSync(filePath, startLine, endLine) {
|
|
11
|
+
try {
|
|
12
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
13
|
+
const lines = content.split('\n');
|
|
14
|
+
return lines.slice(startLine - 1, endLine).join('\n');
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check annotation coverage for the given aspects.
|
|
22
|
+
* Reports missing annotations as issues.
|
|
23
|
+
*/
|
|
24
|
+
export function checkAnnotationCoverage(db, aspects) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
let missingCount = 0;
|
|
27
|
+
const totalDefinitions = db.definitions.getCount();
|
|
28
|
+
let annotatedDefinitions = totalDefinitions;
|
|
29
|
+
for (const aspect of aspects) {
|
|
30
|
+
const missingIds = db.metadata.getDefinitionsWithout(aspect);
|
|
31
|
+
if (missingIds.length > 0) {
|
|
32
|
+
annotatedDefinitions = Math.min(annotatedDefinitions, totalDefinitions - missingIds.length);
|
|
33
|
+
missingCount += missingIds.length;
|
|
34
|
+
// Report first 50 missing as individual issues
|
|
35
|
+
for (const defId of missingIds.slice(0, 50)) {
|
|
36
|
+
const def = db.definitions.getById(defId);
|
|
37
|
+
if (def) {
|
|
38
|
+
issues.push({
|
|
39
|
+
definitionId: defId,
|
|
40
|
+
definitionName: def.name,
|
|
41
|
+
filePath: def.filePath,
|
|
42
|
+
line: def.line,
|
|
43
|
+
severity: 'error',
|
|
44
|
+
category: 'missing-annotation',
|
|
45
|
+
message: `Missing '${aspect}' annotation`,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (missingIds.length > 50) {
|
|
50
|
+
issues.push({
|
|
51
|
+
severity: 'info',
|
|
52
|
+
category: 'missing-annotation',
|
|
53
|
+
message: `... and ${missingIds.length - 50} more definitions missing '${aspect}'`,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Check for suspicious pure:true annotations
|
|
59
|
+
if (aspects.includes('pure')) {
|
|
60
|
+
const pureIssues = checkPureAnnotations(db);
|
|
61
|
+
issues.push(...pureIssues);
|
|
62
|
+
}
|
|
63
|
+
// Check for inconsistent domain tags across same-named definitions
|
|
64
|
+
if (aspects.includes('domain')) {
|
|
65
|
+
const domainIssues = checkDomainConsistency(db);
|
|
66
|
+
issues.push(...domainIssues);
|
|
67
|
+
}
|
|
68
|
+
// Get relationship counts
|
|
69
|
+
let totalRelationships = 0;
|
|
70
|
+
let annotatedRelationships = 0;
|
|
71
|
+
try {
|
|
72
|
+
annotatedRelationships = db.relationships.getCount();
|
|
73
|
+
const unannotated = db.relationships.getUnannotatedCount();
|
|
74
|
+
totalRelationships = annotatedRelationships + unannotated;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Table doesn't exist
|
|
78
|
+
}
|
|
79
|
+
const passed = missingCount === 0;
|
|
80
|
+
return {
|
|
81
|
+
passed,
|
|
82
|
+
issues,
|
|
83
|
+
stats: {
|
|
84
|
+
totalDefinitions,
|
|
85
|
+
annotatedDefinitions: totalDefinitions - missingCount,
|
|
86
|
+
totalRelationships,
|
|
87
|
+
annotatedRelationships,
|
|
88
|
+
missingCount,
|
|
89
|
+
structuralIssueCount: 0,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check for inconsistent domain tags across definitions with the same name and kind.
|
|
95
|
+
*/
|
|
96
|
+
function checkDomainConsistency(db) {
|
|
97
|
+
const issues = [];
|
|
98
|
+
const allDefs = db.definitions.getAll();
|
|
99
|
+
// Group definitions by (name, kind)
|
|
100
|
+
const groups = new Map();
|
|
101
|
+
for (const def of allDefs) {
|
|
102
|
+
const key = `${def.name}::${def.kind}`;
|
|
103
|
+
if (!groups.has(key))
|
|
104
|
+
groups.set(key, []);
|
|
105
|
+
groups.get(key).push({ id: def.id, name: def.name, kind: def.kind, line: def.line });
|
|
106
|
+
}
|
|
107
|
+
for (const [, defs] of groups) {
|
|
108
|
+
if (defs.length < 2)
|
|
109
|
+
continue;
|
|
110
|
+
// Get domain metadata for each definition
|
|
111
|
+
const domainVariants = new Map(); // normalized domain string → def IDs
|
|
112
|
+
for (const def of defs) {
|
|
113
|
+
const domainValue = db.metadata.getValue(def.id, 'domain');
|
|
114
|
+
if (!domainValue)
|
|
115
|
+
continue;
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(domainValue);
|
|
118
|
+
const normalized = JSON.stringify([...parsed].sort());
|
|
119
|
+
if (!domainVariants.has(normalized))
|
|
120
|
+
domainVariants.set(normalized, []);
|
|
121
|
+
domainVariants.get(normalized).push(def.id);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Skip unparseable domain values
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// If there are multiple distinct domain variants, flag inconsistency
|
|
128
|
+
if (domainVariants.size > 1) {
|
|
129
|
+
for (const def of defs) {
|
|
130
|
+
const domainValue = db.metadata.getValue(def.id, 'domain');
|
|
131
|
+
if (!domainValue)
|
|
132
|
+
continue;
|
|
133
|
+
const fullDef = db.definitions.getById(def.id);
|
|
134
|
+
issues.push({
|
|
135
|
+
definitionId: def.id,
|
|
136
|
+
definitionName: def.name,
|
|
137
|
+
filePath: fullDef?.filePath,
|
|
138
|
+
line: def.line,
|
|
139
|
+
severity: 'warning',
|
|
140
|
+
category: 'inconsistent-domain',
|
|
141
|
+
message: `'${def.name}' (${def.kind}) has domain ${domainValue} — other definitions with same name have different domains`,
|
|
142
|
+
fixData: { action: 'harmonize-domain' },
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return issues;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Check for suspicious pure:true annotations using deterministic pattern detection.
|
|
151
|
+
*/
|
|
152
|
+
function checkPureAnnotations(db) {
|
|
153
|
+
const issues = [];
|
|
154
|
+
// Get all definitions that have pure = "true"
|
|
155
|
+
const pureTrueIds = db.metadata.getDefinitionsWith('pure');
|
|
156
|
+
for (const defId of pureTrueIds) {
|
|
157
|
+
const pureValue = db.metadata.getValue(defId, 'pure');
|
|
158
|
+
if (pureValue !== 'true')
|
|
159
|
+
continue;
|
|
160
|
+
const def = db.definitions.getById(defId);
|
|
161
|
+
if (!def)
|
|
162
|
+
continue;
|
|
163
|
+
// Skip types that are inherently pure
|
|
164
|
+
if (def.kind === 'interface' || def.kind === 'type' || def.kind === 'enum')
|
|
165
|
+
continue;
|
|
166
|
+
try {
|
|
167
|
+
const source = readSourceSync(db.resolveFilePath(def.filePath), def.line, def.endLine);
|
|
168
|
+
if (!source)
|
|
169
|
+
continue;
|
|
170
|
+
const impureReasons = detectImpurePatterns(source);
|
|
171
|
+
if (impureReasons.length > 0) {
|
|
172
|
+
issues.push({
|
|
173
|
+
definitionId: def.id,
|
|
174
|
+
definitionName: def.name,
|
|
175
|
+
filePath: def.filePath,
|
|
176
|
+
line: def.line,
|
|
177
|
+
severity: 'warning',
|
|
178
|
+
category: 'suspect-pure',
|
|
179
|
+
message: `'${def.name}' marked pure but source contains: ${impureReasons[0]}`,
|
|
180
|
+
suggestion: 'Consider changing pure to "false"',
|
|
181
|
+
fixData: { action: 'set-pure-false' },
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// File not readable — skip
|
|
187
|
+
}
|
|
188
|
+
// Gate 2: transitive impurity — check if any dependency has pure:false
|
|
189
|
+
if (issues.every((i) => i.definitionId !== defId || i.category !== 'suspect-pure')) {
|
|
190
|
+
try {
|
|
191
|
+
const deps = db.dependencies.getWithMetadata(defId, 'pure');
|
|
192
|
+
for (const dep of deps) {
|
|
193
|
+
const depPure = db.metadata.getValue(dep.id, 'pure');
|
|
194
|
+
if (depPure === 'false') {
|
|
195
|
+
issues.push({
|
|
196
|
+
definitionId: def.id,
|
|
197
|
+
definitionName: def.name,
|
|
198
|
+
filePath: def.filePath,
|
|
199
|
+
line: def.line,
|
|
200
|
+
severity: 'warning',
|
|
201
|
+
category: 'suspect-pure',
|
|
202
|
+
message: `'${def.name}' marked pure but depends on impure '${dep.name}'`,
|
|
203
|
+
suggestion: 'Consider changing pure to "false"',
|
|
204
|
+
fixData: { action: 'set-pure-false' },
|
|
205
|
+
});
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Ignore errors
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return issues;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Check relationship coverage and structural issues.
|
|
219
|
+
*/
|
|
220
|
+
export function checkRelationshipCoverage(db) {
|
|
221
|
+
const issues = [];
|
|
222
|
+
let structuralIssueCount = 0;
|
|
223
|
+
// Count unannotated relationships
|
|
224
|
+
let annotatedRelationships = 0;
|
|
225
|
+
let unannotatedCount = 0;
|
|
226
|
+
try {
|
|
227
|
+
annotatedRelationships = db.relationships.getCount();
|
|
228
|
+
unannotatedCount = db.relationships.getUnannotatedCount();
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Table doesn't exist
|
|
232
|
+
}
|
|
233
|
+
const totalRelationships = annotatedRelationships + unannotatedCount;
|
|
234
|
+
if (unannotatedCount > 0) {
|
|
235
|
+
const unannotated = db.relationships.getUnannotated({ limit: 50 });
|
|
236
|
+
for (const rel of unannotated) {
|
|
237
|
+
issues.push({
|
|
238
|
+
definitionId: rel.fromDefinitionId,
|
|
239
|
+
definitionName: rel.fromName,
|
|
240
|
+
severity: 'error',
|
|
241
|
+
category: 'missing-relationship',
|
|
242
|
+
message: `Missing: ${rel.fromName} → ${rel.toName}`,
|
|
243
|
+
fixData: { action: 'annotate-missing-relationship', targetDefinitionId: rel.toDefinitionId },
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
if (unannotatedCount > 50) {
|
|
247
|
+
issues.push({
|
|
248
|
+
severity: 'error',
|
|
249
|
+
category: 'missing-relationship',
|
|
250
|
+
message: `... and ${unannotatedCount - 50} more missing relationships`,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
structuralIssueCount += unannotatedCount;
|
|
254
|
+
}
|
|
255
|
+
// Check for PENDING_LLM_ANNOTATION relationships
|
|
256
|
+
try {
|
|
257
|
+
const allRels = db.relationships.getAll({ limit: 100000 });
|
|
258
|
+
const pendingRels = allRels.filter((r) => r.semantic === 'PENDING_LLM_ANNOTATION');
|
|
259
|
+
for (const rel of pendingRels) {
|
|
260
|
+
issues.push({
|
|
261
|
+
definitionId: rel.fromDefinitionId,
|
|
262
|
+
definitionName: rel.fromName,
|
|
263
|
+
severity: 'error',
|
|
264
|
+
category: 'pending-annotation',
|
|
265
|
+
message: `${rel.fromName} → ${rel.toName} (${rel.relationshipType}) has placeholder PENDING_LLM_ANNOTATION`,
|
|
266
|
+
fixData: { action: 'reannotate-relationship', targetDefinitionId: rel.toDefinitionId },
|
|
267
|
+
});
|
|
268
|
+
structuralIssueCount++;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Table doesn't exist
|
|
273
|
+
}
|
|
274
|
+
// Duplicate target detection: extends/implements where same (from_id, type) links to multiple to_ids with same name
|
|
275
|
+
try {
|
|
276
|
+
const allRels = db.relationships.getAll({ limit: 100000 });
|
|
277
|
+
const byFromAndType = new Map();
|
|
278
|
+
for (const rel of allRels) {
|
|
279
|
+
if (rel.relationshipType === 'extends' || rel.relationshipType === 'implements') {
|
|
280
|
+
const key = `${rel.fromDefinitionId}:${rel.relationshipType}`;
|
|
281
|
+
if (!byFromAndType.has(key))
|
|
282
|
+
byFromAndType.set(key, []);
|
|
283
|
+
byFromAndType.get(key).push({ toId: rel.toDefinitionId, toName: rel.toName });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
for (const [key, targets] of byFromAndType) {
|
|
287
|
+
// Check if multiple targets share the same name (cartesian product error)
|
|
288
|
+
const nameGroups = new Map();
|
|
289
|
+
for (const t of targets) {
|
|
290
|
+
if (!nameGroups.has(t.toName))
|
|
291
|
+
nameGroups.set(t.toName, []);
|
|
292
|
+
nameGroups.get(t.toName).push(t.toId);
|
|
293
|
+
}
|
|
294
|
+
for (const [name, ids] of nameGroups) {
|
|
295
|
+
if (ids.length > 1) {
|
|
296
|
+
const [fromIdStr, relType] = key.split(':');
|
|
297
|
+
issues.push({
|
|
298
|
+
severity: 'error',
|
|
299
|
+
category: 'duplicate-target',
|
|
300
|
+
message: `Definition #${fromIdStr} has ${ids.length} '${relType}' relationships to different definitions named '${name}' (IDs: ${ids.join(', ')})`,
|
|
301
|
+
suggestion: 'This is likely a cartesian product error — only one target should exist',
|
|
302
|
+
});
|
|
303
|
+
structuralIssueCount++;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
// Table doesn't exist
|
|
310
|
+
}
|
|
311
|
+
// Relationship type mismatch detection
|
|
312
|
+
try {
|
|
313
|
+
const typeMismatchIssues = checkRelationshipTypeMismatches(db);
|
|
314
|
+
issues.push(...typeMismatchIssues);
|
|
315
|
+
structuralIssueCount += typeMismatchIssues.length;
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
// Ignore errors
|
|
319
|
+
}
|
|
320
|
+
// Stale file detection
|
|
321
|
+
try {
|
|
322
|
+
const allFiles = db.files.getAll();
|
|
323
|
+
for (const file of allFiles) {
|
|
324
|
+
try {
|
|
325
|
+
fs.accessSync(db.resolveFilePath(file.path));
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
issues.push({
|
|
329
|
+
filePath: file.path,
|
|
330
|
+
severity: 'warning',
|
|
331
|
+
category: 'stale-file',
|
|
332
|
+
message: `File no longer exists on disk: ${file.path}`,
|
|
333
|
+
suggestion: 'Use --fix to remove stale file entries',
|
|
334
|
+
});
|
|
335
|
+
structuralIssueCount++;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// Files table doesn't exist
|
|
341
|
+
}
|
|
342
|
+
// Missing extends: definitions where extends_name is set but no extends relationship exists
|
|
343
|
+
try {
|
|
344
|
+
const BUILTIN_BASE_CLASSES = new Set([
|
|
345
|
+
'Error',
|
|
346
|
+
'TypeError',
|
|
347
|
+
'RangeError',
|
|
348
|
+
'SyntaxError',
|
|
349
|
+
'ReferenceError',
|
|
350
|
+
'URIError',
|
|
351
|
+
'EvalError',
|
|
352
|
+
'AggregateError',
|
|
353
|
+
'Array',
|
|
354
|
+
'Map',
|
|
355
|
+
'Set',
|
|
356
|
+
'WeakMap',
|
|
357
|
+
'WeakSet',
|
|
358
|
+
'RegExp',
|
|
359
|
+
'Promise',
|
|
360
|
+
'Proxy',
|
|
361
|
+
'Event',
|
|
362
|
+
'EventTarget',
|
|
363
|
+
'CustomEvent',
|
|
364
|
+
'HTMLElement',
|
|
365
|
+
'HTMLDivElement',
|
|
366
|
+
'HTMLInputElement',
|
|
367
|
+
'ReadableStream',
|
|
368
|
+
'WritableStream',
|
|
369
|
+
'TransformStream',
|
|
370
|
+
'EventEmitter',
|
|
371
|
+
]);
|
|
372
|
+
const allDefs = db.definitions.getAll();
|
|
373
|
+
for (const def of allDefs) {
|
|
374
|
+
if (!def.extendsName)
|
|
375
|
+
continue;
|
|
376
|
+
// Skip built-in base classes that have no definition in the DB
|
|
377
|
+
if (BUILTIN_BASE_CLASSES.has(def.extendsName))
|
|
378
|
+
continue;
|
|
379
|
+
const relsFrom = db.relationships.getFrom(def.id);
|
|
380
|
+
const hasExtendsRel = relsFrom.some((r) => r.relationshipType === 'extends');
|
|
381
|
+
if (!hasExtendsRel) {
|
|
382
|
+
const fullDef = db.definitions.getById(def.id);
|
|
383
|
+
issues.push({
|
|
384
|
+
definitionId: def.id,
|
|
385
|
+
definitionName: def.name,
|
|
386
|
+
filePath: fullDef?.filePath,
|
|
387
|
+
line: def.line,
|
|
388
|
+
severity: 'warning',
|
|
389
|
+
category: 'missing-extends',
|
|
390
|
+
message: `Definition '${def.name}' has extends_name='${def.extendsName}' but no 'extends' relationship annotation`,
|
|
391
|
+
suggestion: 'The target class may not be indexed, or the extends clause uses unsupported syntax',
|
|
392
|
+
});
|
|
393
|
+
structuralIssueCount++;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
// Ignore errors
|
|
399
|
+
}
|
|
400
|
+
// Missing implements: definitions where implements_names is set but no implements relationship exists
|
|
401
|
+
try {
|
|
402
|
+
const BUILTIN_INTERFACES = new Set([
|
|
403
|
+
'Iterable',
|
|
404
|
+
'Iterator',
|
|
405
|
+
'AsyncIterable',
|
|
406
|
+
'AsyncIterator',
|
|
407
|
+
'PromiseLike',
|
|
408
|
+
'ArrayLike',
|
|
409
|
+
'Disposable',
|
|
410
|
+
'AsyncDisposable',
|
|
411
|
+
]);
|
|
412
|
+
const allDefs2 = db.definitions.getAll();
|
|
413
|
+
for (const def of allDefs2) {
|
|
414
|
+
const fullDef = db.definitions.getById(def.id);
|
|
415
|
+
if (!fullDef?.implementsNames || fullDef.implementsNames.length === 0)
|
|
416
|
+
continue;
|
|
417
|
+
const relsFrom = db.relationships.getFrom(def.id);
|
|
418
|
+
const implementsRels = new Set(relsFrom.filter((r) => r.relationshipType === 'implements').map((r) => r.toName));
|
|
419
|
+
for (const ifaceName of fullDef.implementsNames) {
|
|
420
|
+
if (BUILTIN_INTERFACES.has(ifaceName))
|
|
421
|
+
continue;
|
|
422
|
+
if (implementsRels.has(ifaceName))
|
|
423
|
+
continue;
|
|
424
|
+
issues.push({
|
|
425
|
+
definitionId: def.id,
|
|
426
|
+
definitionName: def.name,
|
|
427
|
+
filePath: fullDef.filePath,
|
|
428
|
+
line: def.line,
|
|
429
|
+
severity: 'warning',
|
|
430
|
+
category: 'missing-implements',
|
|
431
|
+
message: `Definition '${def.name}' implements '${ifaceName}' but no 'implements' relationship annotation exists`,
|
|
432
|
+
suggestion: 'The target interface may not be indexed, or the implements clause uses unsupported syntax',
|
|
433
|
+
});
|
|
434
|
+
structuralIssueCount++;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// Ignore errors
|
|
440
|
+
}
|
|
441
|
+
const totalDefinitions = db.definitions.getCount();
|
|
442
|
+
const passed = unannotatedCount === 0 && structuralIssueCount === 0;
|
|
443
|
+
return {
|
|
444
|
+
passed,
|
|
445
|
+
issues,
|
|
446
|
+
stats: {
|
|
447
|
+
totalDefinitions,
|
|
448
|
+
annotatedDefinitions: totalDefinitions,
|
|
449
|
+
totalRelationships,
|
|
450
|
+
annotatedRelationships,
|
|
451
|
+
missingCount: unannotatedCount,
|
|
452
|
+
structuralIssueCount,
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Detect relationship type mismatches: relationships marked as 'uses' that should be 'extends' or 'implements'.
|
|
458
|
+
*
|
|
459
|
+
* Tier 1 — Column-based: checks definitions with extends_name/implements_names/extends_interfaces
|
|
460
|
+
* against relationship_annotations marked as 'uses' targeting those same definitions.
|
|
461
|
+
* Tier 2 — Source-code regex: for definitions with inheritance columns, checks source code
|
|
462
|
+
* for extends/implements keywords targeting relationship targets.
|
|
463
|
+
*/
|
|
464
|
+
function checkRelationshipTypeMismatches(db) {
|
|
465
|
+
const issues = [];
|
|
466
|
+
const allDefs = db.definitions.getAll();
|
|
467
|
+
for (const def of allDefs) {
|
|
468
|
+
// Get full definition details (includes implementsNames, extendsInterfaces)
|
|
469
|
+
const fullDef = db.definitions.getById(def.id);
|
|
470
|
+
if (!fullDef)
|
|
471
|
+
continue;
|
|
472
|
+
// Collect all inheritance target names
|
|
473
|
+
const extendsNames = new Set();
|
|
474
|
+
const implementsNames = new Set();
|
|
475
|
+
if (fullDef.extendsName) {
|
|
476
|
+
extendsNames.add(fullDef.extendsName);
|
|
477
|
+
}
|
|
478
|
+
if (fullDef.extendsInterfaces) {
|
|
479
|
+
for (const name of fullDef.extendsInterfaces) {
|
|
480
|
+
extendsNames.add(name);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (fullDef.implementsNames) {
|
|
484
|
+
for (const name of fullDef.implementsNames) {
|
|
485
|
+
implementsNames.add(name);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// Skip if no inheritance
|
|
489
|
+
if (extendsNames.size === 0 && implementsNames.size === 0)
|
|
490
|
+
continue;
|
|
491
|
+
// Get all relationships from this definition
|
|
492
|
+
const relsFrom = db.relationships.getFrom(def.id);
|
|
493
|
+
for (const rel of relsFrom) {
|
|
494
|
+
if (rel.relationshipType !== 'uses')
|
|
495
|
+
continue;
|
|
496
|
+
// Tier 1: check if target name matches a known inheritance target
|
|
497
|
+
let expectedType = null;
|
|
498
|
+
if (extendsNames.has(rel.toName)) {
|
|
499
|
+
expectedType = 'extends';
|
|
500
|
+
}
|
|
501
|
+
else if (implementsNames.has(rel.toName)) {
|
|
502
|
+
expectedType = 'implements';
|
|
503
|
+
}
|
|
504
|
+
if (expectedType) {
|
|
505
|
+
issues.push({
|
|
506
|
+
definitionId: def.id,
|
|
507
|
+
definitionName: def.name,
|
|
508
|
+
filePath: fullDef.filePath,
|
|
509
|
+
line: def.line,
|
|
510
|
+
severity: 'warning',
|
|
511
|
+
category: 'wrong-relationship-type',
|
|
512
|
+
message: `'${def.name}' → '${rel.toName}' is type 'uses' but should be '${expectedType}' (based on definition columns)`,
|
|
513
|
+
suggestion: `Use --fix to change relationship type to '${expectedType}'`,
|
|
514
|
+
fixData: {
|
|
515
|
+
action: 'change-relationship-type',
|
|
516
|
+
targetDefinitionId: rel.toDefinitionId,
|
|
517
|
+
expectedType,
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return issues;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Check flow quality: structural integrity and coverage of generated flows.
|
|
527
|
+
*/
|
|
528
|
+
export function checkFlowQuality(db) {
|
|
529
|
+
const issues = [];
|
|
530
|
+
let structuralIssueCount = 0;
|
|
531
|
+
const allFlows = db.flows.getAll();
|
|
532
|
+
const allModulesWithMembers = db.modules.getAllWithMembers();
|
|
533
|
+
const moduleMap = new Map(allModulesWithMembers.map((m) => [m.id, m]));
|
|
534
|
+
// Check 1 — orphan-entry-point: Flow references a module with no callable definitions
|
|
535
|
+
const callableKinds = new Set(['function', 'class', 'const', 'variable', 'method']);
|
|
536
|
+
for (const flow of allFlows) {
|
|
537
|
+
if (!flow.entryPointModuleId)
|
|
538
|
+
continue;
|
|
539
|
+
const mod = moduleMap.get(flow.entryPointModuleId);
|
|
540
|
+
if (!mod)
|
|
541
|
+
continue;
|
|
542
|
+
const hasCallable = mod.members.some((m) => callableKinds.has(m.kind));
|
|
543
|
+
if (!hasCallable) {
|
|
544
|
+
issues.push({
|
|
545
|
+
severity: 'error',
|
|
546
|
+
category: 'orphan-entry-point',
|
|
547
|
+
message: `Flow '${flow.name}' (id=${flow.id}) references module '${mod.fullPath}' which has no callable definitions (all members are type-only)`,
|
|
548
|
+
suggestion: 'Use --fix to remove this flow',
|
|
549
|
+
fixData: { action: 'remove-flow', targetDefinitionId: flow.id },
|
|
550
|
+
});
|
|
551
|
+
structuralIssueCount++;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
// Check 2 — empty-flow: Flow has 0 steps
|
|
555
|
+
for (const flow of allFlows) {
|
|
556
|
+
const steps = db.flows.getSteps(flow.id);
|
|
557
|
+
if (steps.length === 0) {
|
|
558
|
+
issues.push({
|
|
559
|
+
severity: 'warning',
|
|
560
|
+
category: 'empty-flow',
|
|
561
|
+
message: `Flow '${flow.name}' (id=${flow.id}) has 0 interaction steps`,
|
|
562
|
+
suggestion: 'Use --fix to remove empty flows',
|
|
563
|
+
fixData: { action: 'remove-flow', targetDefinitionId: flow.id },
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
// Check 3 — dangling-interaction: Flow step references a non-existent interaction
|
|
568
|
+
for (const flow of allFlows) {
|
|
569
|
+
const steps = db.flows.getSteps(flow.id);
|
|
570
|
+
for (const step of steps) {
|
|
571
|
+
const interaction = db.interactions.getById(step.interactionId);
|
|
572
|
+
if (!interaction) {
|
|
573
|
+
issues.push({
|
|
574
|
+
severity: 'error',
|
|
575
|
+
category: 'dangling-interaction',
|
|
576
|
+
message: `Flow '${flow.name}' (id=${flow.id}) step ${step.stepOrder} references non-existent interaction ${step.interactionId}`,
|
|
577
|
+
});
|
|
578
|
+
structuralIssueCount++;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
// Check 4 — duplicate-slug: Multiple flows share the same slug
|
|
583
|
+
const slugCounts = new Map();
|
|
584
|
+
for (const flow of allFlows) {
|
|
585
|
+
const ids = slugCounts.get(flow.slug) ?? [];
|
|
586
|
+
ids.push(flow.id);
|
|
587
|
+
slugCounts.set(flow.slug, ids);
|
|
588
|
+
}
|
|
589
|
+
for (const [slug, ids] of slugCounts) {
|
|
590
|
+
if (ids.length > 1) {
|
|
591
|
+
issues.push({
|
|
592
|
+
severity: 'warning',
|
|
593
|
+
category: 'duplicate-slug',
|
|
594
|
+
message: `Slug '${slug}' is shared by ${ids.length} flows (IDs: ${ids.join(', ')})`,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// Check 5 — uncovered-interactions: Interactions not covered by any flow (informational)
|
|
599
|
+
const coveredInteractionIds = new Set();
|
|
600
|
+
for (const flow of allFlows) {
|
|
601
|
+
const steps = db.flows.getSteps(flow.id);
|
|
602
|
+
for (const step of steps) {
|
|
603
|
+
coveredInteractionIds.add(step.interactionId);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
const allInteractions = db.interactions.getAll();
|
|
607
|
+
const relevantInteractions = allInteractions.filter((i) => i.pattern !== 'test-internal');
|
|
608
|
+
const uncovered = relevantInteractions.filter((i) => !coveredInteractionIds.has(i.id));
|
|
609
|
+
if (uncovered.length > 0) {
|
|
610
|
+
issues.push({
|
|
611
|
+
severity: 'info',
|
|
612
|
+
category: 'uncovered-interactions',
|
|
613
|
+
message: `${uncovered.length}/${relevantInteractions.length} relevant interactions are not covered by any flow`,
|
|
614
|
+
});
|
|
615
|
+
for (const i of uncovered.slice(0, 20)) {
|
|
616
|
+
issues.push({
|
|
617
|
+
severity: 'info',
|
|
618
|
+
category: 'uncovered-interactions',
|
|
619
|
+
message: ` ${i.fromModulePath} → ${i.toModulePath}${i.semantic ? `: ${i.semantic}` : ''}`,
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
if (uncovered.length > 20) {
|
|
623
|
+
issues.push({
|
|
624
|
+
severity: 'info',
|
|
625
|
+
category: 'uncovered-interactions',
|
|
626
|
+
message: ` ... and ${uncovered.length - 20} more`,
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// Check 6 — broken-chain: consecutive steps where toModuleId doesn't connect to next step
|
|
631
|
+
for (const flow of allFlows) {
|
|
632
|
+
const steps = db.flows.getSteps(flow.id);
|
|
633
|
+
if (steps.length < 2)
|
|
634
|
+
continue;
|
|
635
|
+
for (let i = 0; i < steps.length - 1; i++) {
|
|
636
|
+
const currentInteraction = db.interactions.getById(steps[i].interactionId);
|
|
637
|
+
const nextInteraction = db.interactions.getById(steps[i + 1].interactionId);
|
|
638
|
+
if (!currentInteraction || !nextInteraction)
|
|
639
|
+
continue; // Skip nulls (caught by dangling-interaction)
|
|
640
|
+
const currentTo = currentInteraction.toModuleId;
|
|
641
|
+
const nextFrom = nextInteraction.fromModuleId;
|
|
642
|
+
const nextTo = nextInteraction.toModuleId;
|
|
643
|
+
if (currentTo !== nextFrom && currentTo !== nextTo) {
|
|
644
|
+
issues.push({
|
|
645
|
+
severity: 'warning',
|
|
646
|
+
category: 'broken-chain',
|
|
647
|
+
message: `Flow '${flow.name}' (id=${flow.id}) has broken chain at step ${steps[i].stepOrder}→${steps[i + 1].stepOrder}: module #${currentTo} doesn't connect to next step`,
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
// Check 7 — entry-mismatch: entry point module != first step's from module
|
|
653
|
+
for (const flow of allFlows) {
|
|
654
|
+
if (!flow.entryPointModuleId)
|
|
655
|
+
continue;
|
|
656
|
+
const steps = db.flows.getSteps(flow.id);
|
|
657
|
+
if (steps.length === 0)
|
|
658
|
+
continue;
|
|
659
|
+
const firstInteraction = db.interactions.getById(steps[0].interactionId);
|
|
660
|
+
if (!firstInteraction)
|
|
661
|
+
continue;
|
|
662
|
+
if (flow.entryPointModuleId !== firstInteraction.fromModuleId) {
|
|
663
|
+
issues.push({
|
|
664
|
+
severity: 'warning',
|
|
665
|
+
category: 'entry-mismatch',
|
|
666
|
+
message: `Flow '${flow.name}' (id=${flow.id}) entry module #${flow.entryPointModuleId} doesn't match first step's from module #${firstInteraction.fromModuleId}`,
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
// Check 8 — entry-not-in-module: entry point definition not a member of entry module
|
|
671
|
+
for (const flow of allFlows) {
|
|
672
|
+
if (!flow.entryPointId || !flow.entryPointModuleId)
|
|
673
|
+
continue;
|
|
674
|
+
const mod = moduleMap.get(flow.entryPointModuleId);
|
|
675
|
+
if (!mod)
|
|
676
|
+
continue;
|
|
677
|
+
const isMember = mod.members.some((m) => m.definitionId === flow.entryPointId);
|
|
678
|
+
if (!isMember) {
|
|
679
|
+
issues.push({
|
|
680
|
+
severity: 'error',
|
|
681
|
+
category: 'entry-not-in-module',
|
|
682
|
+
message: `Flow '${flow.name}' (id=${flow.id}) entry point definition #${flow.entryPointId} is not a member of entry module #${flow.entryPointModuleId}`,
|
|
683
|
+
fixData: { action: 'null-entry-point', flowId: flow.id },
|
|
684
|
+
});
|
|
685
|
+
structuralIssueCount++;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
const passed = structuralIssueCount === 0;
|
|
689
|
+
return {
|
|
690
|
+
passed,
|
|
691
|
+
issues,
|
|
692
|
+
stats: {
|
|
693
|
+
totalDefinitions: allFlows.length,
|
|
694
|
+
annotatedDefinitions: allFlows.length - structuralIssueCount,
|
|
695
|
+
totalRelationships: relevantInteractions.length,
|
|
696
|
+
annotatedRelationships: coveredInteractionIds.size,
|
|
697
|
+
missingCount: uncovered.length,
|
|
698
|
+
structuralIssueCount,
|
|
699
|
+
},
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Check module assignment quality: test symbols in production modules,
|
|
704
|
+
* non-exported test symbols in shared modules.
|
|
705
|
+
*/
|
|
706
|
+
export function checkModuleAssignments(db) {
|
|
707
|
+
const issues = [];
|
|
708
|
+
let structuralIssueCount = 0;
|
|
709
|
+
const modules = db.modules.getAll();
|
|
710
|
+
if (modules.length === 0) {
|
|
711
|
+
return {
|
|
712
|
+
passed: true,
|
|
713
|
+
issues: [],
|
|
714
|
+
stats: {
|
|
715
|
+
totalDefinitions: db.definitions.getCount(),
|
|
716
|
+
annotatedDefinitions: 0,
|
|
717
|
+
totalRelationships: 0,
|
|
718
|
+
annotatedRelationships: 0,
|
|
719
|
+
missingCount: 0,
|
|
720
|
+
structuralIssueCount: 0,
|
|
721
|
+
},
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
const testModuleIds = db.modules.getTestModuleIds();
|
|
725
|
+
// Check 1: test-in-production — test file symbols assigned to non-test modules
|
|
726
|
+
const allModulesWithMembers = db.modules.getAllWithMembers();
|
|
727
|
+
for (const mod of allModulesWithMembers) {
|
|
728
|
+
if (testModuleIds.has(mod.id))
|
|
729
|
+
continue; // production module check only
|
|
730
|
+
for (const member of mod.members) {
|
|
731
|
+
if (isTestFile(member.filePath)) {
|
|
732
|
+
issues.push({
|
|
733
|
+
definitionId: member.definitionId,
|
|
734
|
+
definitionName: member.name,
|
|
735
|
+
filePath: member.filePath,
|
|
736
|
+
line: member.line,
|
|
737
|
+
severity: 'warning',
|
|
738
|
+
category: 'test-in-production',
|
|
739
|
+
message: `Test symbol '${member.name}' from test file assigned to production module '${mod.fullPath}'`,
|
|
740
|
+
suggestion: 'Move to a test module (project.testing.*)',
|
|
741
|
+
fixData: { action: 'move-to-test-module' },
|
|
742
|
+
});
|
|
743
|
+
structuralIssueCount++;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
// Check 2: non-exported test symbol in shared module
|
|
748
|
+
// Flag non-exported symbols from test files assigned to modules that have
|
|
749
|
+
// members from multiple different files (i.e. shared/infrastructure modules)
|
|
750
|
+
for (const mod of allModulesWithMembers) {
|
|
751
|
+
// Count distinct files in this module
|
|
752
|
+
const distinctFiles = new Set(mod.members.map((m) => m.filePath));
|
|
753
|
+
if (distinctFiles.size <= 1)
|
|
754
|
+
continue; // single-file module is fine
|
|
755
|
+
for (const member of mod.members) {
|
|
756
|
+
if (isTestFile(member.filePath) && !member.isExported) {
|
|
757
|
+
issues.push({
|
|
758
|
+
definitionId: member.definitionId,
|
|
759
|
+
definitionName: member.name,
|
|
760
|
+
filePath: member.filePath,
|
|
761
|
+
line: member.line,
|
|
762
|
+
severity: 'info',
|
|
763
|
+
category: 'non-exported-in-shared',
|
|
764
|
+
message: `Non-exported test symbol '${member.name}' in shared module '${mod.fullPath}' (${distinctFiles.size} files)`,
|
|
765
|
+
suggestion: 'File-local test symbols should not be in shared modules — assign to a general test module',
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
// Check 3: unassigned-definition — definitions not assigned to any module (informational)
|
|
771
|
+
try {
|
|
772
|
+
const unassigned = db.modules.getUnassigned();
|
|
773
|
+
if (unassigned.length > 0) {
|
|
774
|
+
issues.push({
|
|
775
|
+
severity: 'info',
|
|
776
|
+
category: 'unassigned-definition',
|
|
777
|
+
message: `${unassigned.length} definitions are not assigned to any module`,
|
|
778
|
+
});
|
|
779
|
+
for (const sym of unassigned.slice(0, 20)) {
|
|
780
|
+
issues.push({
|
|
781
|
+
definitionId: sym.id,
|
|
782
|
+
definitionName: sym.name,
|
|
783
|
+
filePath: sym.filePath,
|
|
784
|
+
line: sym.line,
|
|
785
|
+
severity: 'info',
|
|
786
|
+
category: 'unassigned-definition',
|
|
787
|
+
message: ` ${sym.name} (${sym.kind}) in ${sym.filePath}:${sym.line}`,
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
if (unassigned.length > 20) {
|
|
791
|
+
issues.push({
|
|
792
|
+
severity: 'info',
|
|
793
|
+
category: 'unassigned-definition',
|
|
794
|
+
message: ` ... and ${unassigned.length - 20} more`,
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
catch {
|
|
800
|
+
// Ignore errors
|
|
801
|
+
}
|
|
802
|
+
const totalDefinitions = db.definitions.getCount();
|
|
803
|
+
const passed = structuralIssueCount === 0;
|
|
804
|
+
return {
|
|
805
|
+
passed,
|
|
806
|
+
issues,
|
|
807
|
+
stats: {
|
|
808
|
+
totalDefinitions,
|
|
809
|
+
annotatedDefinitions: totalDefinitions,
|
|
810
|
+
totalRelationships: 0,
|
|
811
|
+
annotatedRelationships: 0,
|
|
812
|
+
missingCount: 0,
|
|
813
|
+
structuralIssueCount,
|
|
814
|
+
},
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Check referential integrity: detect ghost rows referencing deleted entities.
|
|
819
|
+
*/
|
|
820
|
+
export function checkReferentialIntegrity(db) {
|
|
821
|
+
const issues = [];
|
|
822
|
+
let structuralIssueCount = 0;
|
|
823
|
+
const ghosts = db.findGhostRows();
|
|
824
|
+
for (const g of ghosts.ghostRelationships) {
|
|
825
|
+
issues.push({
|
|
826
|
+
severity: 'error',
|
|
827
|
+
category: 'ghost-relationship',
|
|
828
|
+
message: `Relationship annotation #${g.id} references a deleted definition`,
|
|
829
|
+
fixData: { action: 'remove-ghost', ghostTable: g.table, ghostRowId: g.id },
|
|
830
|
+
});
|
|
831
|
+
structuralIssueCount++;
|
|
832
|
+
}
|
|
833
|
+
for (const g of ghosts.ghostMembers) {
|
|
834
|
+
issues.push({
|
|
835
|
+
severity: 'error',
|
|
836
|
+
category: 'ghost-member',
|
|
837
|
+
message: `Module member for definition #${g.definitionId} references a deleted definition or module`,
|
|
838
|
+
fixData: { action: 'remove-ghost', ghostTable: g.table, ghostRowId: g.definitionId },
|
|
839
|
+
});
|
|
840
|
+
structuralIssueCount++;
|
|
841
|
+
}
|
|
842
|
+
for (const g of ghosts.ghostEntryPoints) {
|
|
843
|
+
issues.push({
|
|
844
|
+
severity: 'error',
|
|
845
|
+
category: 'ghost-entry-point',
|
|
846
|
+
message: `Flow #${g.id} references a deleted entry point definition`,
|
|
847
|
+
fixData: { action: 'remove-ghost', ghostTable: g.table, ghostRowId: g.id },
|
|
848
|
+
});
|
|
849
|
+
structuralIssueCount++;
|
|
850
|
+
}
|
|
851
|
+
for (const g of ghosts.ghostEntryModules) {
|
|
852
|
+
issues.push({
|
|
853
|
+
severity: 'error',
|
|
854
|
+
category: 'ghost-entry-module',
|
|
855
|
+
message: `Flow #${g.id} references a deleted entry point module`,
|
|
856
|
+
fixData: { action: 'remove-ghost', ghostTable: g.table, ghostRowId: g.id },
|
|
857
|
+
});
|
|
858
|
+
structuralIssueCount++;
|
|
859
|
+
}
|
|
860
|
+
for (const g of ghosts.ghostInteractions) {
|
|
861
|
+
issues.push({
|
|
862
|
+
severity: 'error',
|
|
863
|
+
category: 'ghost-interaction',
|
|
864
|
+
message: `Interaction #${g.id} references a deleted module`,
|
|
865
|
+
fixData: { action: 'remove-ghost', ghostTable: g.table, ghostRowId: g.id },
|
|
866
|
+
});
|
|
867
|
+
structuralIssueCount++;
|
|
868
|
+
}
|
|
869
|
+
for (const g of ghosts.ghostSubflows) {
|
|
870
|
+
issues.push({
|
|
871
|
+
severity: 'error',
|
|
872
|
+
category: 'ghost-subflow',
|
|
873
|
+
message: `Subflow step (rowid=${g.rowid}) references a deleted flow`,
|
|
874
|
+
fixData: { action: 'remove-ghost', ghostTable: g.table, ghostRowId: g.rowid },
|
|
875
|
+
});
|
|
876
|
+
structuralIssueCount++;
|
|
877
|
+
}
|
|
878
|
+
const passed = structuralIssueCount === 0;
|
|
879
|
+
return {
|
|
880
|
+
passed,
|
|
881
|
+
issues,
|
|
882
|
+
stats: {
|
|
883
|
+
totalDefinitions: 0,
|
|
884
|
+
annotatedDefinitions: 0,
|
|
885
|
+
totalRelationships: 0,
|
|
886
|
+
annotatedRelationships: 0,
|
|
887
|
+
missingCount: 0,
|
|
888
|
+
structuralIssueCount,
|
|
889
|
+
},
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Check interaction quality: self-loops, missing import paths, symbol mismatches,
|
|
894
|
+
* false bidirectionals, and ungrounded inferred interactions.
|
|
895
|
+
*/
|
|
896
|
+
export function checkInteractionQuality(db, processGroups) {
|
|
897
|
+
const issues = [];
|
|
898
|
+
let structuralIssueCount = 0;
|
|
899
|
+
const allInteractions = db.interactions.getAll();
|
|
900
|
+
if (allInteractions.length === 0) {
|
|
901
|
+
return {
|
|
902
|
+
passed: true,
|
|
903
|
+
issues: [],
|
|
904
|
+
stats: {
|
|
905
|
+
totalDefinitions: 0,
|
|
906
|
+
annotatedDefinitions: 0,
|
|
907
|
+
totalRelationships: 0,
|
|
908
|
+
annotatedRelationships: 0,
|
|
909
|
+
missingCount: 0,
|
|
910
|
+
structuralIssueCount: 0,
|
|
911
|
+
},
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
// Build call graph edge set for O(1) lookups
|
|
915
|
+
const callGraphEdges = new Set();
|
|
916
|
+
try {
|
|
917
|
+
const moduleCallGraph = db.callGraph.getModuleCallGraph();
|
|
918
|
+
for (const edge of moduleCallGraph) {
|
|
919
|
+
callGraphEdges.add(`${edge.fromModuleId}->${edge.toModuleId}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
catch {
|
|
923
|
+
// Call graph may not be available
|
|
924
|
+
}
|
|
925
|
+
// Build module members lookup for symbol mismatch checks
|
|
926
|
+
const allModulesWithMembers = db.modules.getAllWithMembers();
|
|
927
|
+
const moduleMemberNames = new Map();
|
|
928
|
+
for (const mod of allModulesWithMembers) {
|
|
929
|
+
moduleMemberNames.set(mod.id, new Set(mod.members.map((m) => m.name)));
|
|
930
|
+
}
|
|
931
|
+
// Helper to check if two modules are cross-process
|
|
932
|
+
const isCrossProcess = (fromId, toId) => {
|
|
933
|
+
if (!processGroups)
|
|
934
|
+
return false;
|
|
935
|
+
const fromGroup = processGroups.moduleToGroup.get(fromId);
|
|
936
|
+
const toGroup = processGroups.moduleToGroup.get(toId);
|
|
937
|
+
if (fromGroup === undefined || toGroup === undefined)
|
|
938
|
+
return false;
|
|
939
|
+
return fromGroup !== toGroup;
|
|
940
|
+
};
|
|
941
|
+
// Build AST edge flow map for direction-implausible check (Check 8)
|
|
942
|
+
// Map: "groupA->groupB" → count of AST edges from groupA to groupB
|
|
943
|
+
const astFlowCounts = new Map();
|
|
944
|
+
if (processGroups) {
|
|
945
|
+
for (const interaction of allInteractions) {
|
|
946
|
+
if (interaction.source !== 'ast' && interaction.source !== 'ast-import')
|
|
947
|
+
continue;
|
|
948
|
+
const fromGroup = processGroups.moduleToGroup.get(interaction.fromModuleId);
|
|
949
|
+
const toGroup = processGroups.moduleToGroup.get(interaction.toModuleId);
|
|
950
|
+
if (fromGroup === undefined || toGroup === undefined)
|
|
951
|
+
continue;
|
|
952
|
+
if (fromGroup === toGroup)
|
|
953
|
+
continue;
|
|
954
|
+
const key = `${fromGroup}->${toGroup}`;
|
|
955
|
+
astFlowCounts.set(key, (astFlowCounts.get(key) ?? 0) + 1);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
for (const interaction of allInteractions) {
|
|
959
|
+
// Check 1: self-loop-interaction
|
|
960
|
+
if (interaction.fromModuleId === interaction.toModuleId) {
|
|
961
|
+
issues.push({
|
|
962
|
+
severity: 'error',
|
|
963
|
+
category: 'self-loop-interaction',
|
|
964
|
+
message: `Interaction #${interaction.id} is a self-loop: ${interaction.fromModulePath} → ${interaction.toModulePath}`,
|
|
965
|
+
fixData: { action: 'remove-interaction', interactionId: interaction.id },
|
|
966
|
+
});
|
|
967
|
+
structuralIssueCount++;
|
|
968
|
+
continue; // Skip other checks for self-loops
|
|
969
|
+
}
|
|
970
|
+
// Check 2: no-import-path (for AST/import-based interactions)
|
|
971
|
+
if (interaction.source === 'ast' || interaction.source === 'ast-import') {
|
|
972
|
+
try {
|
|
973
|
+
const hasImport = db.interactions.hasModuleImportPath(interaction.fromModuleId, interaction.toModuleId);
|
|
974
|
+
if (!hasImport) {
|
|
975
|
+
issues.push({
|
|
976
|
+
severity: 'warning',
|
|
977
|
+
category: 'no-import-path',
|
|
978
|
+
message: `Interaction #${interaction.id} (${interaction.fromModulePath} → ${interaction.toModulePath}) has source '${interaction.source}' but no import path exists`,
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
catch {
|
|
983
|
+
// Skip if query fails
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
// Check 3: interaction-symbol-mismatch
|
|
987
|
+
if (interaction.symbols) {
|
|
988
|
+
try {
|
|
989
|
+
const symbolNames = typeof interaction.symbols === 'string' ? JSON.parse(interaction.symbols) : interaction.symbols;
|
|
990
|
+
const targetMembers = moduleMemberNames.get(interaction.toModuleId);
|
|
991
|
+
if (targetMembers && symbolNames.length > 0) {
|
|
992
|
+
const mismatched = symbolNames.filter((s) => !targetMembers.has(s));
|
|
993
|
+
if (mismatched.length > 0 && mismatched.length === symbolNames.length) {
|
|
994
|
+
issues.push({
|
|
995
|
+
severity: 'warning',
|
|
996
|
+
category: 'interaction-symbol-mismatch',
|
|
997
|
+
message: `Interaction #${interaction.id} (${interaction.fromModulePath} → ${interaction.toModulePath}): all ${symbolNames.length} symbols not found in target module`,
|
|
998
|
+
fixData: { action: 'rebuild-symbols', interactionId: interaction.id },
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
catch {
|
|
1004
|
+
// JSON parse error — skip
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
// Check 4: false-bidirectional
|
|
1008
|
+
if (interaction.direction === 'bi') {
|
|
1009
|
+
const reverseKey = `${interaction.toModuleId}->${interaction.fromModuleId}`;
|
|
1010
|
+
if (!callGraphEdges.has(reverseKey)) {
|
|
1011
|
+
issues.push({
|
|
1012
|
+
severity: 'warning',
|
|
1013
|
+
category: 'false-bidirectional',
|
|
1014
|
+
message: `Interaction #${interaction.id} (${interaction.fromModulePath} → ${interaction.toModulePath}) is 'bi' but no reverse call graph edge exists`,
|
|
1015
|
+
fixData: { action: 'set-direction-uni', interactionId: interaction.id },
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
// Check 5: ungrounded-inferred (process-aware)
|
|
1020
|
+
if (interaction.source === 'llm-inferred') {
|
|
1021
|
+
// Skip check for cross-process interactions — they're expected to have no static evidence
|
|
1022
|
+
if (!isCrossProcess(interaction.fromModuleId, interaction.toModuleId)) {
|
|
1023
|
+
const forwardKey = `${interaction.fromModuleId}->${interaction.toModuleId}`;
|
|
1024
|
+
const hasCallEdge = callGraphEdges.has(forwardKey);
|
|
1025
|
+
let hasImport = false;
|
|
1026
|
+
try {
|
|
1027
|
+
hasImport = db.interactions.hasModuleImportPath(interaction.fromModuleId, interaction.toModuleId);
|
|
1028
|
+
}
|
|
1029
|
+
catch {
|
|
1030
|
+
// Skip
|
|
1031
|
+
}
|
|
1032
|
+
if (!hasCallEdge && !hasImport) {
|
|
1033
|
+
issues.push({
|
|
1034
|
+
severity: 'warning',
|
|
1035
|
+
category: 'ungrounded-inferred',
|
|
1036
|
+
message: `Interaction #${interaction.id} (${interaction.fromModulePath} → ${interaction.toModulePath}) is 'llm-inferred' with no import path and no call graph edge`,
|
|
1037
|
+
fixData: { action: 'remove-interaction', interactionId: interaction.id },
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
// Check 8: direction-implausible (for llm-inferred cross-process interactions)
|
|
1043
|
+
if (interaction.source === 'llm-inferred' && processGroups) {
|
|
1044
|
+
const fromGroup = processGroups.moduleToGroup.get(interaction.fromModuleId);
|
|
1045
|
+
const toGroup = processGroups.moduleToGroup.get(interaction.toModuleId);
|
|
1046
|
+
if (fromGroup !== undefined && toGroup !== undefined && fromGroup !== toGroup) {
|
|
1047
|
+
const forwardKey = `${fromGroup}->${toGroup}`;
|
|
1048
|
+
const reverseKey = `${toGroup}->${fromGroup}`;
|
|
1049
|
+
const forwardCount = astFlowCounts.get(forwardKey) ?? 0;
|
|
1050
|
+
const reverseCount = astFlowCounts.get(reverseKey) ?? 0;
|
|
1051
|
+
// Flag if AST edges only flow in the reverse direction
|
|
1052
|
+
if (forwardCount === 0 && reverseCount > 0) {
|
|
1053
|
+
issues.push({
|
|
1054
|
+
severity: 'warning',
|
|
1055
|
+
category: 'direction-implausible',
|
|
1056
|
+
message: `Interaction #${interaction.id} (${interaction.fromModulePath} → ${interaction.toModulePath}) goes against AST edge flow (${reverseCount} AST edges flow in reverse, 0 forward)`,
|
|
1057
|
+
fixData: { action: 'remove-interaction', interactionId: interaction.id },
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
// Check 6: fan-in-anomaly
|
|
1064
|
+
try {
|
|
1065
|
+
const anomalies = db.interactionAnalysis.detectFanInAnomalies();
|
|
1066
|
+
for (const anomaly of anomalies) {
|
|
1067
|
+
// Get all llm-inferred interactions targeting this module
|
|
1068
|
+
const inferredToModule = allInteractions.filter((i) => i.toModuleId === anomaly.moduleId && i.source === 'llm-inferred');
|
|
1069
|
+
for (const interaction of inferredToModule) {
|
|
1070
|
+
issues.push({
|
|
1071
|
+
severity: 'warning',
|
|
1072
|
+
category: 'fan-in-anomaly',
|
|
1073
|
+
message: `Interaction #${interaction.id} (${interaction.fromModulePath} → ${anomaly.modulePath}) targets a fan-in anomaly (${anomaly.llmFanIn} LLM inbound, ${anomaly.astFanIn} AST inbound)`,
|
|
1074
|
+
fixData: { action: 'remove-inferred-to-module', targetModuleId: anomaly.moduleId },
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
catch {
|
|
1080
|
+
// Skip if analysis fails
|
|
1081
|
+
}
|
|
1082
|
+
const passed = structuralIssueCount === 0;
|
|
1083
|
+
return {
|
|
1084
|
+
passed,
|
|
1085
|
+
issues,
|
|
1086
|
+
stats: {
|
|
1087
|
+
totalDefinitions: allInteractions.length,
|
|
1088
|
+
annotatedDefinitions: allInteractions.length - structuralIssueCount,
|
|
1089
|
+
totalRelationships: 0,
|
|
1090
|
+
annotatedRelationships: 0,
|
|
1091
|
+
missingCount: 0,
|
|
1092
|
+
structuralIssueCount,
|
|
1093
|
+
},
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
//# sourceMappingURL=coverage-checker.js.map
|