audit-tools 0.32.16 → 0.32.18

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.
Files changed (105) hide show
  1. package/dist/audit/cli/conceptualDispatch.d.ts +9 -1
  2. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  3. package/dist/audit/cli/conceptualDispatch.js +3 -0
  4. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  5. package/dist/audit/contracts/workerSchemas.d.ts +13 -0
  6. package/dist/audit/contracts/workerSchemas.d.ts.map +1 -1
  7. package/dist/audit/decompose/buildStructureDecomposition.d.ts +14 -0
  8. package/dist/audit/decompose/buildStructureDecomposition.d.ts.map +1 -0
  9. package/dist/audit/decompose/buildStructureDecomposition.js +107 -0
  10. package/dist/audit/decompose/buildStructureDecomposition.js.map +1 -0
  11. package/dist/audit/decompose/findings.d.ts +23 -0
  12. package/dist/audit/decompose/findings.d.ts.map +1 -0
  13. package/dist/audit/decompose/findings.js +121 -0
  14. package/dist/audit/decompose/findings.js.map +1 -0
  15. package/dist/audit/decompose/sources.d.ts +21 -0
  16. package/dist/audit/decompose/sources.d.ts.map +1 -0
  17. package/dist/audit/decompose/sources.js +168 -0
  18. package/dist/audit/decompose/sources.js.map +1 -0
  19. package/dist/audit/extractors/commentDecomposition.d.ts +52 -0
  20. package/dist/audit/extractors/commentDecomposition.d.ts.map +1 -0
  21. package/dist/audit/extractors/commentDecomposition.js +298 -0
  22. package/dist/audit/extractors/commentDecomposition.js.map +1 -0
  23. package/dist/audit/extractors/dataStateCoupling.d.ts +26 -0
  24. package/dist/audit/extractors/dataStateCoupling.d.ts.map +1 -0
  25. package/dist/audit/extractors/dataStateCoupling.js +71 -0
  26. package/dist/audit/extractors/dataStateCoupling.js.map +1 -0
  27. package/dist/audit/io/artifacts.d.ts +3 -0
  28. package/dist/audit/io/artifacts.d.ts.map +1 -1
  29. package/dist/audit/io/artifacts.js +1 -0
  30. package/dist/audit/io/artifacts.js.map +1 -1
  31. package/dist/audit/orchestrator/dependencyMap.d.ts +1 -0
  32. package/dist/audit/orchestrator/dependencyMap.d.ts.map +1 -1
  33. package/dist/audit/orchestrator/dependencyMap.js +11 -0
  34. package/dist/audit/orchestrator/dependencyMap.js.map +1 -1
  35. package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
  36. package/dist/audit/orchestrator/executorRunners.js +2 -1
  37. package/dist/audit/orchestrator/executorRunners.js.map +1 -1
  38. package/dist/audit/orchestrator/executors.d.ts.map +1 -1
  39. package/dist/audit/orchestrator/executors.js +5 -0
  40. package/dist/audit/orchestrator/executors.js.map +1 -1
  41. package/dist/audit/orchestrator/nextStep.d.ts.map +1 -1
  42. package/dist/audit/orchestrator/nextStep.js +1 -0
  43. package/dist/audit/orchestrator/nextStep.js.map +1 -1
  44. package/dist/audit/orchestrator/state.d.ts.map +1 -1
  45. package/dist/audit/orchestrator/state.js +4 -0
  46. package/dist/audit/orchestrator/state.js.map +1 -1
  47. package/dist/audit/orchestrator/structureExecutors.d.ts +8 -0
  48. package/dist/audit/orchestrator/structureExecutors.d.ts.map +1 -1
  49. package/dist/audit/orchestrator/structureExecutors.js +30 -0
  50. package/dist/audit/orchestrator/structureExecutors.js.map +1 -1
  51. package/dist/audit/orchestrator/synthesisExecutors.d.ts.map +1 -1
  52. package/dist/audit/orchestrator/synthesisExecutors.js +1 -0
  53. package/dist/audit/orchestrator/synthesisExecutors.js.map +1 -1
  54. package/dist/audit/orchestrator/taskAffinityGraph.d.ts +2 -2
  55. package/dist/audit/reporting/mergeFindings.d.ts +2 -1
  56. package/dist/audit/reporting/mergeFindings.d.ts.map +1 -1
  57. package/dist/audit/reporting/mergeFindings.js +9 -1
  58. package/dist/audit/reporting/mergeFindings.js.map +1 -1
  59. package/dist/audit/reporting/synthesis.d.ts +2 -0
  60. package/dist/audit/reporting/synthesis.d.ts.map +1 -1
  61. package/dist/audit/reporting/synthesis.js +1 -1
  62. package/dist/audit/reporting/synthesis.js.map +1 -1
  63. package/dist/audit/types/structureDecomposition.d.ts +27 -0
  64. package/dist/audit/types/structureDecomposition.d.ts.map +1 -0
  65. package/dist/audit/types/structureDecomposition.js +2 -0
  66. package/dist/audit/types/structureDecomposition.js.map +1 -0
  67. package/dist/audit/types.d.ts +5 -0
  68. package/dist/audit/types.d.ts.map +1 -1
  69. package/dist/audit/validation/artifacts.d.ts.map +1 -1
  70. package/dist/audit/validation/artifacts.js +19 -1
  71. package/dist/audit/validation/artifacts.js.map +1 -1
  72. package/dist/remediate/state/types.d.ts +5 -0
  73. package/dist/remediate/state/types.d.ts.map +1 -1
  74. package/dist/shared/decompose/consensus.d.ts +66 -0
  75. package/dist/shared/decompose/consensus.d.ts.map +1 -0
  76. package/dist/shared/decompose/consensus.js +213 -0
  77. package/dist/shared/decompose/consensus.js.map +1 -0
  78. package/dist/shared/decompose/modularity.d.ts +44 -0
  79. package/dist/shared/decompose/modularity.d.ts.map +1 -0
  80. package/dist/shared/decompose/modularity.js +249 -0
  81. package/dist/shared/decompose/modularity.js.map +1 -0
  82. package/dist/shared/index.d.ts +7 -0
  83. package/dist/shared/index.d.ts.map +1 -1
  84. package/dist/shared/index.js +4 -0
  85. package/dist/shared/index.js.map +1 -1
  86. package/dist/shared/types/charter.d.ts +242 -0
  87. package/dist/shared/types/charter.d.ts.map +1 -0
  88. package/dist/shared/types/charter.js +146 -0
  89. package/dist/shared/types/charter.js.map +1 -0
  90. package/dist/shared/types/finding.d.ts +40 -0
  91. package/dist/shared/types/finding.d.ts.map +1 -1
  92. package/dist/shared/types/finding.js +10 -0
  93. package/dist/shared/types/finding.js.map +1 -1
  94. package/dist/shared/types/intentCheckpoint.d.ts +224 -0
  95. package/dist/shared/types/intentCheckpoint.d.ts.map +1 -1
  96. package/dist/shared/types/intentCheckpoint.js +16 -0
  97. package/dist/shared/types/intentCheckpoint.js.map +1 -1
  98. package/dist/shared/validation/charterGate.d.ts +38 -0
  99. package/dist/shared/validation/charterGate.d.ts.map +1 -0
  100. package/dist/shared/validation/charterGate.js +73 -0
  101. package/dist/shared/validation/charterGate.js.map +1 -0
  102. package/package.json +1 -1
  103. package/schemas/audit_result.schema.json +4 -0
  104. package/schemas/audit_results.schema.json +4 -0
  105. package/schemas/finding.schema.json +4 -0
@@ -0,0 +1,168 @@
1
+ // Structure-layer source adapter (Phase B): turns the audit graph substrate into
2
+ // the independently-sourced views the overlay-and-delta operator consumes. PURE —
3
+ // the async extraction (comment/doc reads, git co-change) happens in the executor;
4
+ // this module only shapes already-gathered signals into partitions.
5
+ //
6
+ // Behavior-exhibited sources (call/import, git co-change, data/state) each become
7
+ // a WEIGHTED GRAPH clustered across the resolution ladder → a multi-resolution
8
+ // partition family (feeds both agreed-across-source and stable-across-scale).
9
+ // Intent-declared sources (directory depths, docs, comments) each become one or
10
+ // more PARTITIONS over the same file universe (feed agreed-across-source only).
11
+ import { resolutionSweep } from "audit-tools/shared";
12
+ import { allGraphEdges } from "../extractors/graphSignals.js";
13
+ import { GIT_CO_CHANGE_CATEGORY } from "../extractors/gitHistory.js";
14
+ import { deriveDataStateCoupling, } from "../extractors/dataStateCoupling.js";
15
+ function toPosix(path) {
16
+ return path.replace(/\\/g, "/");
17
+ }
18
+ /** Aggregate undirected edges over the universe into a WeightedGraph. */
19
+ function weightedGraph(universe, edges) {
20
+ const inScope = new Set(universe);
21
+ const byPair = new Map();
22
+ for (const edge of edges) {
23
+ const a = toPosix(edge.a);
24
+ const b = toPosix(edge.b);
25
+ if (a === b || !inScope.has(a) || !inScope.has(b))
26
+ continue;
27
+ if (!(edge.weight > 0))
28
+ continue;
29
+ const lo = a.localeCompare(b) <= 0 ? a : b;
30
+ const hi = a.localeCompare(b) <= 0 ? b : a;
31
+ const key = `${lo} ${hi}`;
32
+ byPair.set(key, (byPair.get(key) ?? 0) + edge.weight);
33
+ }
34
+ const aggregated = [];
35
+ for (const [key, weight] of byPair) {
36
+ const idx = key.indexOf(" ");
37
+ aggregated.push({ a: key.slice(0, idx), b: key.slice(idx + 1), weight });
38
+ }
39
+ return { nodes: universe, edges: aggregated };
40
+ }
41
+ /** Directed graph edges → undirected coupling edges (weight = confidence or 1). */
42
+ function edgesFromGraph(raw) {
43
+ if (!Array.isArray(raw))
44
+ return [];
45
+ const out = [];
46
+ for (const edge of raw) {
47
+ if (!edge ||
48
+ typeof edge.from !== "string" ||
49
+ typeof edge.to !== "string") {
50
+ continue;
51
+ }
52
+ const weight = typeof edge.confidence === "number" && edge.confidence > 0
53
+ ? edge.confidence
54
+ : 1;
55
+ out.push({ a: edge.from, b: edge.to, weight });
56
+ }
57
+ return out;
58
+ }
59
+ /** Build a single partition from disjoint member groups; ungrouped → singleton. */
60
+ function partitionFromGroups(universe, groups) {
61
+ const partition = new Map();
62
+ for (const node of universe)
63
+ partition.set(node, node);
64
+ for (const group of groups) {
65
+ const rep = [...group].sort((a, b) => a.localeCompare(b))[0];
66
+ if (!rep)
67
+ continue;
68
+ for (const member of group) {
69
+ const m = toPosix(member);
70
+ if (partition.has(m))
71
+ partition.set(m, rep);
72
+ }
73
+ }
74
+ return partition;
75
+ }
76
+ /** Directory-prefix partition at a given depth (community = first `depth` segs). */
77
+ function directoryPartition(universe, depth) {
78
+ const partition = new Map();
79
+ for (const node of universe) {
80
+ const segs = node.split("/");
81
+ // A file with fewer than depth+1 segments has no dir at this depth → itself.
82
+ const community = segs.length > depth ? segs.slice(0, depth).join("/") : node;
83
+ partition.set(node, community);
84
+ }
85
+ return partition;
86
+ }
87
+ const DEFAULT_DIRECTORY_DEPTHS = [1, 2, 3];
88
+ /**
89
+ * Build the structure-layer decomposition sources. Behavior sources with no edges
90
+ * and intent sources with no non-trivial grouping are omitted so an empty source
91
+ * never dilutes the agreement mean.
92
+ */
93
+ export function buildStructureSources(input) {
94
+ const universe = [...new Set(input.universe.map(toPosix))].sort((a, b) => a.localeCompare(b));
95
+ const sources = [];
96
+ // --- Behavior-exhibited sources ---
97
+ const callImport = weightedGraph(universe, allGraphEdges(input.graphBundle).map((e) => ({
98
+ a: e.from,
99
+ b: e.to,
100
+ weight: typeof e.confidence === "number" && e.confidence > 0 ? e.confidence : 1,
101
+ })));
102
+ if (callImport.edges.length > 0) {
103
+ sources.push({
104
+ id: "call_import",
105
+ family: "behavior",
106
+ partitions: resolutionSweep(callImport, input.resolutions),
107
+ });
108
+ }
109
+ const coChangeRaw = input.graphBundle.graphs[GIT_CO_CHANGE_CATEGORY];
110
+ const coChange = weightedGraph(universe, edgesFromGraph(coChangeRaw));
111
+ if (coChange.edges.length > 0) {
112
+ sources.push({
113
+ id: "co_change",
114
+ family: "behavior",
115
+ partitions: resolutionSweep(coChange, input.resolutions),
116
+ });
117
+ }
118
+ const dataState = weightedGraph(universe, deriveDataStateCoupling(input.graphBundle));
119
+ if (dataState.edges.length > 0) {
120
+ sources.push({
121
+ id: "data_state",
122
+ family: "behavior",
123
+ partitions: resolutionSweep(dataState, input.resolutions),
124
+ });
125
+ }
126
+ // --- Intent-declared sources ---
127
+ const depths = input.directoryDepths ?? DEFAULT_DIRECTORY_DEPTHS;
128
+ const directoryPartitions = depths.map((d) => directoryPartition(universe, d));
129
+ // Include the directory source only when at least one depth actually groups
130
+ // files (a flat repo with all files at the root yields only singletons).
131
+ const directoryGroups = directoryPartitions.some((p) => hasNonTrivialGroup(p));
132
+ if (directoryGroups) {
133
+ sources.push({
134
+ id: "directory",
135
+ family: "intent",
136
+ partitions: directoryPartitions,
137
+ });
138
+ }
139
+ if (input.docGroups.length > 0) {
140
+ sources.push({
141
+ id: "docs",
142
+ family: "intent",
143
+ partitions: [partitionFromGroups(universe, input.docGroups)],
144
+ });
145
+ }
146
+ const commentGraph = weightedGraph(universe, input.commentEdges);
147
+ if (commentGraph.edges.length > 0) {
148
+ // Comment cross-references are a coupling graph; cluster it at the ladder so a
149
+ // comment web forms boundaries the same way behavior graphs do.
150
+ sources.push({
151
+ id: "comments",
152
+ family: "intent",
153
+ partitions: resolutionSweep(commentGraph, input.resolutions),
154
+ });
155
+ }
156
+ return sources;
157
+ }
158
+ function hasNonTrivialGroup(partition) {
159
+ const counts = new Map();
160
+ for (const comm of partition.values()) {
161
+ counts.set(comm, (counts.get(comm) ?? 0) + 1);
162
+ }
163
+ for (const count of counts.values())
164
+ if (count >= 2)
165
+ return true;
166
+ return false;
167
+ }
168
+ //# sourceMappingURL=sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.js","sourceRoot":"","sources":["../../../src/audit/decompose/sources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { CouplingEdge } from "./dataStateCoupling.js";
2
+ /**
3
+ * Extract concatenated comment text from source, honoring the file's comment
4
+ * syntax and skipping string literals (single/double/backtick, backslash-escaped)
5
+ * so a comment marker inside a string is not misread. A single-pass char scanner:
6
+ * normal → string → line-comment → block-comment. Degrades gracefully (an
7
+ * unterminated block just consumes to EOF).
8
+ */
9
+ export declare function extractCommentText(source: string, path: string): string;
10
+ export interface CommentDecompositionResult {
11
+ /** Intent-declared coupling edges from comment cross-references (undirected). */
12
+ edges: CouplingEdge[];
13
+ /** Number of files whose source was read + scanned. */
14
+ scannedFiles: number;
15
+ }
16
+ export interface CommentDecompositionParams {
17
+ root: string;
18
+ /** In-scope repo-relative file paths. */
19
+ files: string[];
20
+ /**
21
+ * Injectable file reader (absolute path → text | undefined). Defaults to a
22
+ * size-capped node:fs read; tests supply a map-backed reader.
23
+ */
24
+ readFileText?: (absPath: string) => Promise<string | undefined>;
25
+ /** Skip files larger than this many bytes when reading (default 512 KiB). */
26
+ maxBytes?: number;
27
+ }
28
+ /**
29
+ * Derive intent-declared coupling edges from comment cross-references across the
30
+ * in-scope files. For each file, its comment text is scanned for the distinctive
31
+ * reference tokens of OTHER files; a match adds an undirected edge. Deterministic:
32
+ * files are processed in sorted order and edges are canonicalized + sorted.
33
+ */
34
+ export declare function deriveCommentDecomposition(params: CommentDecompositionParams): Promise<CommentDecompositionResult>;
35
+ export interface DocGroupsParams {
36
+ root: string;
37
+ /** Doc files (prose) to mine — README / ADRs / other markdown. */
38
+ docFiles: string[];
39
+ /** In-scope code files a doc may name (the grouping universe). */
40
+ codeFiles: string[];
41
+ readFileText?: (absPath: string) => Promise<string | undefined>;
42
+ maxBytes?: number;
43
+ }
44
+ /**
45
+ * Derive intent-declared groups from docs: each doc's ENTIRE text (docs are
46
+ * prose, not comment-embedded) is scanned for the reference tokens of in-scope
47
+ * code files; every code file a single doc names becomes one group (the doc
48
+ * declares a module). Returns disjoint member groups of size ≥ 2 (a doc naming
49
+ * one file declares no grouping), lexically sorted. Deterministic.
50
+ */
51
+ export declare function deriveDocGroups(params: DocGroupsParams): Promise<string[][]>;
52
+ //# sourceMappingURL=commentDecomposition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commentDecomposition.d.ts","sourceRoot":"","sources":["../../../src/audit/extractors/commentDecomposition.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAiD3D;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoEvE;AA8CD,MAAM,WAAW,0BAA0B;IACzC,iFAAiF;IACjF,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAChE,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiBD;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,0BAA0B,CAAC,CA0DrC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,kEAAkE;IAClE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CA0CrB"}
@@ -0,0 +1,298 @@
1
+ // Comment-decomposition extractor (Phase B intent-declared source; design of
2
+ // record spec/conceptual-design-review-design.md §"Structure decomposition
3
+ // sources" rule 2: "Comments are their own delta — comments are stated intent
4
+ // embedded in code").
5
+ //
6
+ // Comments are stated intent embedded in the code. This extractor mines the
7
+ // INTENT-DECLARED structure they assert: where a file's comments explicitly
8
+ // cross-reference another in-scope file (by path), the author is declaring the
9
+ // two related. Those cross-references become an intent-declared coupling source
10
+ // that the overlay-and-delta operator compares against the behavior graphs — a
11
+ // comment that claims a boundary the code does not honor surfaces as a
12
+ // non-co-localization finding downstream.
13
+ //
14
+ // The "stripped vs unstripped" pair the design calls for falls out structurally:
15
+ // the STRIPPED view (code without comments) is exactly the existing call/import
16
+ // coupling graph; the UNSTRIPPED intent is this comment source. Phase C layers the
17
+ // LLM comments-stripped semantic-cohesion pass on top; Phase B stays deterministic.
18
+ //
19
+ // Comment lexing is keyed by file EXTENSION — comment syntax is per-language
20
+ // lexical fact, not an environment coupling (the language-neutral invariant is
21
+ // about the graph/planning contract, not pretending `.py` doesn't use `#`).
22
+ // Unknown extensions fall back to the C-family `//` + `/* */` so a stray `#`
23
+ // (e.g. a JS private field) is never misread as a comment.
24
+ import { readFile } from "node:fs/promises";
25
+ import { join } from "node:path";
26
+ const C_FAMILY = { line: ["//"], block: [["/*", "*/"]] };
27
+ const HASH_ONLY = { line: ["#"], block: [] };
28
+ const PY = {
29
+ line: ["#"],
30
+ block: [
31
+ ['"""', '"""'],
32
+ ["'''", "'''"],
33
+ ],
34
+ };
35
+ const MARKUP = { line: [], block: [["<!--", "-->"]] };
36
+ const CSS = { line: [], block: [["/*", "*/"]] };
37
+ const SQL_LIKE = { line: ["--"], block: [["/*", "*/"]] };
38
+ /** Extension (with dot, lowercased) → comment syntax. Unknown → C_FAMILY. */
39
+ const SYNTAX_BY_EXT = {
40
+ ".js": C_FAMILY, ".jsx": C_FAMILY, ".ts": C_FAMILY, ".tsx": C_FAMILY,
41
+ ".mjs": C_FAMILY, ".cjs": C_FAMILY, ".mts": C_FAMILY, ".cts": C_FAMILY,
42
+ ".java": C_FAMILY, ".c": C_FAMILY, ".h": C_FAMILY, ".cpp": C_FAMILY,
43
+ ".hpp": C_FAMILY, ".cc": C_FAMILY, ".cs": C_FAMILY, ".go": C_FAMILY,
44
+ ".rs": C_FAMILY, ".swift": C_FAMILY, ".kt": C_FAMILY, ".scala": C_FAMILY,
45
+ ".php": C_FAMILY, ".dart": C_FAMILY,
46
+ ".py": PY, ".pyi": PY,
47
+ ".rb": HASH_ONLY, ".sh": HASH_ONLY, ".bash": HASH_ONLY, ".zsh": HASH_ONLY,
48
+ ".yaml": HASH_ONLY, ".yml": HASH_ONLY, ".toml": HASH_ONLY, ".r": HASH_ONLY,
49
+ ".pl": HASH_ONLY, ".conf": HASH_ONLY, ".ini": HASH_ONLY, ".cfg": HASH_ONLY,
50
+ ".sql": SQL_LIKE, ".lua": SQL_LIKE, ".hs": SQL_LIKE, ".elm": SQL_LIKE,
51
+ ".html": MARKUP, ".htm": MARKUP, ".xml": MARKUP, ".vue": MARKUP,
52
+ ".svelte": MARKUP, ".md": MARKUP, ".markdown": MARKUP,
53
+ ".css": CSS, ".scss": CSS, ".less": CSS,
54
+ };
55
+ function extensionOf(path) {
56
+ const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
57
+ const dot = path.lastIndexOf(".");
58
+ if (dot <= slash)
59
+ return "";
60
+ return path.slice(dot).toLowerCase();
61
+ }
62
+ function syntaxFor(path) {
63
+ return SYNTAX_BY_EXT[extensionOf(path)] ?? C_FAMILY;
64
+ }
65
+ /**
66
+ * Extract concatenated comment text from source, honoring the file's comment
67
+ * syntax and skipping string literals (single/double/backtick, backslash-escaped)
68
+ * so a comment marker inside a string is not misread. A single-pass char scanner:
69
+ * normal → string → line-comment → block-comment. Degrades gracefully (an
70
+ * unterminated block just consumes to EOF).
71
+ */
72
+ export function extractCommentText(source, path) {
73
+ const syntax = syntaxFor(path);
74
+ const out = [];
75
+ const n = source.length;
76
+ let i = 0;
77
+ const startsWith = (marker) => source.startsWith(marker, i);
78
+ while (i < n) {
79
+ const ch = source[i];
80
+ // String literals — skip so markers inside them don't count.
81
+ if (ch === '"' || ch === "'" || ch === "`") {
82
+ // Python triple-quote docstrings are handled as block comments below; only
83
+ // treat as a string here when it is NOT an opening triple quote for PY.
84
+ const triple = ch + ch + ch;
85
+ const isTriple = startsWith(triple);
86
+ const treatAsBlock = syntax.block.some(([open]) => open === triple);
87
+ if (!(isTriple && treatAsBlock)) {
88
+ i += 1;
89
+ while (i < n) {
90
+ if (source[i] === "\\") {
91
+ i += 2;
92
+ continue;
93
+ }
94
+ if (source[i] === ch) {
95
+ i += 1;
96
+ break;
97
+ }
98
+ i += 1;
99
+ }
100
+ continue;
101
+ }
102
+ }
103
+ // Block comments (incl. Python triple-quote docstrings).
104
+ let matchedBlock = false;
105
+ for (const [open, close] of syntax.block) {
106
+ if (startsWith(open)) {
107
+ const end = source.indexOf(close, i + open.length);
108
+ const stop = end === -1 ? n : end;
109
+ out.push(source.slice(i + open.length, stop));
110
+ i = end === -1 ? n : end + close.length;
111
+ matchedBlock = true;
112
+ break;
113
+ }
114
+ }
115
+ if (matchedBlock)
116
+ continue;
117
+ // Line comments.
118
+ let matchedLine = false;
119
+ for (const marker of syntax.line) {
120
+ if (startsWith(marker)) {
121
+ const nl = source.indexOf("\n", i);
122
+ const stop = nl === -1 ? n : nl;
123
+ out.push(source.slice(i + marker.length, stop));
124
+ i = stop;
125
+ matchedLine = true;
126
+ break;
127
+ }
128
+ }
129
+ if (matchedLine)
130
+ continue;
131
+ i += 1;
132
+ }
133
+ return out.join("\n");
134
+ }
135
+ /** Normalize a repo path to forward slashes for matching. */
136
+ function toPosix(path) {
137
+ return path.replace(/\\/g, "/");
138
+ }
139
+ const GENERIC_STEMS = new Set([
140
+ "index",
141
+ "types",
142
+ "type",
143
+ "utils",
144
+ "util",
145
+ "helpers",
146
+ "helper",
147
+ "constants",
148
+ "main",
149
+ "mod",
150
+ ]);
151
+ /**
152
+ * Distinctive reference tokens for a file — the strings a comment would plausibly
153
+ * use to name it. Path-like tokens (≥ 2 segments) are always distinctive; a bare
154
+ * basename qualifies only when it is long enough and not a generic stem, so
155
+ * `index`/`types` never spuriously couple files.
156
+ */
157
+ function referenceTokens(posixPath) {
158
+ const tokens = new Set();
159
+ const noExt = posixPath.replace(/\.[^./]+$/, "");
160
+ tokens.add(posixPath);
161
+ tokens.add(noExt);
162
+ const segs = posixPath.split("/");
163
+ if (segs.length >= 2) {
164
+ tokens.add(segs.slice(-2).join("/"));
165
+ const lastTwoNoExt = segs.slice(-2).join("/").replace(/\.[^./]+$/, "");
166
+ tokens.add(lastTwoNoExt);
167
+ }
168
+ const base = segs[segs.length - 1] ?? posixPath;
169
+ const stem = base.replace(/\.[^./]+$/, "");
170
+ if (stem.length >= 5 && !GENERIC_STEMS.has(stem.toLowerCase())) {
171
+ tokens.add(base); // basename WITH extension only, to stay distinctive
172
+ }
173
+ // Keep only tokens with a path separator or a kept distinctive basename.
174
+ return [...tokens].filter((t) => t.includes("/") || t === base);
175
+ }
176
+ const DEFAULT_MAX_BYTES = 512 * 1024;
177
+ async function defaultReadFileText(absPath, maxBytes) {
178
+ try {
179
+ const buf = await readFile(absPath);
180
+ if (buf.byteLength > maxBytes)
181
+ return undefined;
182
+ return buf.toString("utf8");
183
+ }
184
+ catch {
185
+ return undefined;
186
+ }
187
+ }
188
+ /**
189
+ * Derive intent-declared coupling edges from comment cross-references across the
190
+ * in-scope files. For each file, its comment text is scanned for the distinctive
191
+ * reference tokens of OTHER files; a match adds an undirected edge. Deterministic:
192
+ * files are processed in sorted order and edges are canonicalized + sorted.
193
+ */
194
+ export async function deriveCommentDecomposition(params) {
195
+ const maxBytes = params.maxBytes ?? DEFAULT_MAX_BYTES;
196
+ const read = params.readFileText ?? ((abs) => defaultReadFileText(abs, maxBytes));
197
+ const files = [...new Set(params.files.map(toPosix))].sort((a, b) => a.localeCompare(b));
198
+ // token → owning file (longest/most-specific token wins on collision is
199
+ // unnecessary; a token maps to exactly one file by construction of paths).
200
+ const tokenOwner = new Map();
201
+ for (const file of files) {
202
+ for (const token of referenceTokens(file)) {
203
+ // A token shared by two files (possible for a bare basename) is ambiguous —
204
+ // drop it rather than couple arbitrarily.
205
+ if (tokenOwner.has(token))
206
+ tokenOwner.set(token, "\0ambiguous");
207
+ else
208
+ tokenOwner.set(token, file);
209
+ }
210
+ }
211
+ for (const [token, owner] of [...tokenOwner]) {
212
+ if (owner === "\0ambiguous")
213
+ tokenOwner.delete(token);
214
+ }
215
+ // Sort tokens longest-first so a specific path matches before a substring.
216
+ const tokens = [...tokenOwner.keys()].sort((a, b) => b.length - a.length || a.localeCompare(b));
217
+ const weightByPair = new Map();
218
+ let scannedFiles = 0;
219
+ for (const file of files) {
220
+ const text = await read(join(params.root, file));
221
+ if (text === undefined)
222
+ continue;
223
+ scannedFiles += 1;
224
+ const comments = extractCommentText(text, file);
225
+ if (comments.length === 0)
226
+ continue;
227
+ const posixComments = toPosix(comments);
228
+ const referenced = new Set();
229
+ for (const token of tokens) {
230
+ const owner = tokenOwner.get(token);
231
+ if (owner === file || referenced.has(owner))
232
+ continue;
233
+ if (posixComments.includes(token))
234
+ referenced.add(owner);
235
+ }
236
+ for (const other of referenced) {
237
+ const a = file.localeCompare(other) <= 0 ? file : other;
238
+ const b = file.localeCompare(other) <= 0 ? other : file;
239
+ const key = `${a} ${b}`;
240
+ weightByPair.set(key, (weightByPair.get(key) ?? 0) + 1);
241
+ }
242
+ }
243
+ const edges = [];
244
+ for (const [key, weight] of weightByPair) {
245
+ const idx = key.indexOf(" ");
246
+ edges.push({ a: key.slice(0, idx), b: key.slice(idx + 1), weight });
247
+ }
248
+ edges.sort((x, y) => x.a.localeCompare(y.a) || x.b.localeCompare(y.b));
249
+ return { edges, scannedFiles };
250
+ }
251
+ /**
252
+ * Derive intent-declared groups from docs: each doc's ENTIRE text (docs are
253
+ * prose, not comment-embedded) is scanned for the reference tokens of in-scope
254
+ * code files; every code file a single doc names becomes one group (the doc
255
+ * declares a module). Returns disjoint member groups of size ≥ 2 (a doc naming
256
+ * one file declares no grouping), lexically sorted. Deterministic.
257
+ */
258
+ export async function deriveDocGroups(params) {
259
+ const maxBytes = params.maxBytes ?? DEFAULT_MAX_BYTES;
260
+ const read = params.readFileText ?? ((abs) => defaultReadFileText(abs, maxBytes));
261
+ const codeFiles = [...new Set(params.codeFiles.map(toPosix))].sort((a, b) => a.localeCompare(b));
262
+ const docFiles = [...new Set(params.docFiles.map(toPosix))].sort((a, b) => a.localeCompare(b));
263
+ const tokenOwner = new Map();
264
+ for (const file of codeFiles) {
265
+ for (const token of referenceTokens(file)) {
266
+ if (tokenOwner.has(token))
267
+ tokenOwner.set(token, "\0ambiguous");
268
+ else
269
+ tokenOwner.set(token, file);
270
+ }
271
+ }
272
+ for (const [token, owner] of [...tokenOwner]) {
273
+ if (owner === "\0ambiguous")
274
+ tokenOwner.delete(token);
275
+ }
276
+ const tokens = [...tokenOwner.keys()].sort((a, b) => b.length - a.length || a.localeCompare(b));
277
+ const groups = [];
278
+ for (const doc of docFiles) {
279
+ const text = await read(join(params.root, doc));
280
+ if (text === undefined)
281
+ continue;
282
+ const posixText = toPosix(text);
283
+ const named = new Set();
284
+ for (const token of tokens) {
285
+ const owner = tokenOwner.get(token);
286
+ if (named.has(owner))
287
+ continue;
288
+ if (posixText.includes(token))
289
+ named.add(owner);
290
+ }
291
+ if (named.size >= 2) {
292
+ groups.push([...named].sort((a, b) => a.localeCompare(b)));
293
+ }
294
+ }
295
+ groups.sort((a, b) => (a[0] ?? "").localeCompare(b[0] ?? ""));
296
+ return groups;
297
+ }
298
+ //# sourceMappingURL=commentDecomposition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commentDecomposition.js","sourceRoot":"","sources":["../../../src/audit/extractors/commentDecomposition.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { GraphBundle } from "audit-tools/shared";
2
+ /** An undirected weighted coupling edge (canonical `a < b`). */
3
+ export interface CouplingEdge {
4
+ a: string;
5
+ b: string;
6
+ weight: number;
7
+ }
8
+ export interface DataStateCouplingOptions {
9
+ /**
10
+ * A target is "generic" (dropped) once its referrer count exceeds
11
+ * max(genericAbsolute, genericFraction × universe). Ubiquitous targets carry no
12
+ * grouping signal and would otherwise couple everything.
13
+ */
14
+ genericFraction?: number;
15
+ genericAbsolute?: number;
16
+ /** Minimum shared-target count for an edge to be emitted. */
17
+ minSharedTargets?: number;
18
+ }
19
+ /**
20
+ * Derive data/state coupling edges from a graph bundle's structural edges. Two
21
+ * source files sharing K non-generic targets get one undirected edge of weight K.
22
+ * Deterministic: edges are canonicalized (`a < b`) and sorted by (a, b). Degrades
23
+ * to `[]` for an edgeless / malformed bundle (never throws).
24
+ */
25
+ export declare function deriveDataStateCoupling(graphBundle: GraphBundle, options?: DataStateCouplingOptions): CouplingEdge[];
26
+ //# sourceMappingURL=dataStateCoupling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataStateCoupling.d.ts","sourceRoot":"","sources":["../../../src/audit/extractors/dataStateCoupling.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,wBAA6B,GACrC,YAAY,EAAE,CAgDhB"}
@@ -0,0 +1,71 @@
1
+ // Data/state coupling extractor (Phase B behavior-exhibited source; design of
2
+ // record spec/conceptual-design-review-design.md §"Structure decomposition
3
+ // sources"): "code touching the same artifact/state even with no direct call."
4
+ //
5
+ // Realized deterministically + language-neutrally as BIBLIOGRAPHIC COUPLING: two
6
+ // files that reference the SAME targets are coupled through that shared state,
7
+ // even when neither calls the other. This is distinct from the direct
8
+ // call/import source (which is the edges themselves) — here the signal is shared
9
+ // OUT-neighbors, computed purely from the existing structural edge set (no file
10
+ // reads, no new IO).
11
+ //
12
+ // A target referenced by nearly everything (a ubiquitous util / logger) carries
13
+ // no grouping signal — like a stop-word — so targets whose in-degree exceeds a
14
+ // genericness cap are dropped before pairing. This also bounds the cost: a hub
15
+ // with N referrers would otherwise contribute O(N²) pairs.
16
+ import { allGraphEdges } from "./graphSignals.js";
17
+ const DEFAULT_GENERIC_FRACTION = 0.25;
18
+ const DEFAULT_GENERIC_ABSOLUTE = 12;
19
+ const DEFAULT_MIN_SHARED_TARGETS = 2;
20
+ /**
21
+ * Derive data/state coupling edges from a graph bundle's structural edges. Two
22
+ * source files sharing K non-generic targets get one undirected edge of weight K.
23
+ * Deterministic: edges are canonicalized (`a < b`) and sorted by (a, b). Degrades
24
+ * to `[]` for an edgeless / malformed bundle (never throws).
25
+ */
26
+ export function deriveDataStateCoupling(graphBundle, options = {}) {
27
+ const genericFraction = options.genericFraction ?? DEFAULT_GENERIC_FRACTION;
28
+ const genericAbsolute = options.genericAbsolute ?? DEFAULT_GENERIC_ABSOLUTE;
29
+ const minSharedTargets = options.minSharedTargets ?? DEFAULT_MIN_SHARED_TARGETS;
30
+ const edges = allGraphEdges(graphBundle);
31
+ if (edges.length === 0)
32
+ return [];
33
+ // target → set of source files that reference it (self-references dropped).
34
+ const referrersByTarget = new Map();
35
+ const sources = new Set();
36
+ for (const edge of edges) {
37
+ if (edge.from === edge.to)
38
+ continue;
39
+ sources.add(edge.from);
40
+ let referrers = referrersByTarget.get(edge.to);
41
+ if (!referrers) {
42
+ referrers = new Set();
43
+ referrersByTarget.set(edge.to, referrers);
44
+ }
45
+ referrers.add(edge.from);
46
+ }
47
+ const genericThreshold = Math.max(genericAbsolute, Math.ceil(sources.size * genericFraction));
48
+ // Accumulate shared-target counts per source pair, over non-generic targets.
49
+ const sharedByPair = new Map();
50
+ for (const referrers of referrersByTarget.values()) {
51
+ if (referrers.size < 2 || referrers.size > genericThreshold)
52
+ continue;
53
+ const members = [...referrers].sort((a, b) => a.localeCompare(b));
54
+ for (let i = 0; i < members.length; i++) {
55
+ for (let j = i + 1; j < members.length; j++) {
56
+ const key = `${members[i]} ${members[j]}`;
57
+ sharedByPair.set(key, (sharedByPair.get(key) ?? 0) + 1);
58
+ }
59
+ }
60
+ }
61
+ const result = [];
62
+ for (const [key, weight] of sharedByPair) {
63
+ if (weight < minSharedTargets)
64
+ continue;
65
+ const idx = key.indexOf(" ");
66
+ result.push({ a: key.slice(0, idx), b: key.slice(idx + 1), weight });
67
+ }
68
+ result.sort((x, y) => x.a.localeCompare(y.a) || x.b.localeCompare(y.b));
69
+ return result;
70
+ }
71
+ //# sourceMappingURL=dataStateCoupling.js.map