{"record":{"id":"b955fd297f8d1ba5","repo":"abhigyanpatwari/GitNexus","slug":"cobol-copy-expander-circular-copy-detected-cs","errorCode":null,"errorMessage":"[cobol-copy-expander] Circular COPY detected: ${cs.target} (${resolvedPath}) includes itself. Skipping expansion.","messagePattern":"\\[cobol-copy-expander\\] Circular COPY detected: (.+?) \\((.+?)\\) includes itself\\. Skipping expansion\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gitnexus/src/core/ingestion/cobol/cobol-copy-expander.ts","lineNumber":458,"sourceCode":"      // Record resolution metadata\n      allResolutions.push({\n        copyTarget: cs.target,\n        resolvedPath,\n        line: cs.startLine,\n        replacing: cs.replacing,\n        library: cs.library,\n      });\n\n      // Cannot resolve — keep original lines\n      if (resolvedPath === null) {\n        continue;\n      }\n\n      // Cycle detection\n      if (visited.has(resolvedPath)) {\n        if (!warnedCircular.has(resolvedPath)) {\n          warnedCircular.add(resolvedPath);\n          logger.warn(\n            `[cobol-copy-expander] Circular COPY detected: ${cs.target} (${resolvedPath}) ` +\n              `includes itself. Skipping expansion.`,\n          );\n        }\n        continue;\n      }\n\n      // Max depth exceeded — keep unexpanded\n      if (depth >= maxDepth) {\n        logger.warn(\n          `[cobol-copy-expander] Max expansion depth (${maxDepth}) reached for ` +\n            `COPY ${cs.target} in ${srcPath}. Skipping expansion.`,\n        );\n        continue;\n      }\n\n      // Guard against exponential breadth amplification (N copybooks each with N COPYs)\n      if (++totalExpansions > MAX_TOTAL_EXPANSIONS) {","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/ingestion/cobol/cobol-copy-expander.ts#L440-L476","documentation":"During COPY expansion, a copybook resolved to a path already on the active expansion chain (the visited set) — it includes itself, directly or transitively (A COPYs B, B COPYs A). Expansion of that COPY is skipped and the original lines kept; the warning fires once per path per run via the warnedCircular set.","triggerScenarios":"A copybook chain that loops: copybook A contains COPY B while B contains COPY A, or a copybook COPYs itself.","commonSituations":"Refactored copybooks that accidentally reference each other; copy-paste introducing a self-COPY. Real COBOL compilers reject such cycles, so this usually surfaces on legacy members that were never compiled as-is.","solutions":["Break the cycle: remove the recursive COPY statement from one of the copybooks","Extract the shared fragment into a third, leaf copybook that both A and B COPY","Re-run analysis — the expander keeps original lines so output stays parseable, but verify results for those members"],"exampleFix":"* before — CPYB contains: COPY CPYA.  CPYA contains: COPY CPYB.\n* after — remove the back-reference from CPYB\n       IDENTIFICATION DIVISION.\n       ...","handlingStrategy":"validation","validationCode":"// Pre-flight: DFS the copybook graph and fail on cycles before analysis\nfunction findCopyCycle(adj: Map<string, string[]>): string[] | null {\n  const state = new Map<string, 'visiting' | 'done'>();\n  const dfs = (node: string, stack: string[]): string[] | null => {\n    state.set(node, 'visiting');\n    for (const next of adj.get(node) ?? []) {\n      if (state.get(next) === 'visiting') return [...stack, next];\n      if (!state.has(next)) {\n        const cycle = dfs(next, [...stack, next]);\n        if (cycle) return cycle;\n      }\n    }\n    state.set(node, 'done');\n    return null;\n  };\n  for (const node of adj.keys()) if (!state.has(node)) {\n    const cycle = dfs(node, [node]);\n    if (cycle) return cycle;\n  }\n  return null;\n}","typeGuard":"function isAcyclic(adj: Map<string, string[]>): boolean {\n  return findCopyCycle(adj) === null;\n}","tryCatchPattern":null,"preventionTips":["Never let a copybook (directly or transitively) COPY anything on its own expansion chain","Run a cycle check over the copybook graph in CI for mainframe source trees","Compile members with a real COBOL compiler periodically — it rejects circular COPYs"],"tags":["cobol","copybook","circular-reference","preprocessor"],"backgroundTag":"circular-include","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}