{"record":{"id":"e9b3caa8c7a6902b","repo":"ruvnet/ruflo","slug":"repopath-must-be-the-git-top-level-top","errorCode":null,"errorMessage":"repoPath must be the Git top-level: ${top}","messagePattern":"repoPath must be the Git top-level: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/codex/src/harness/repository-state.ts","lineNumber":411,"sourceCode":"    || submodule.commit !== submodule.expectedCommit\n    || submodule.trackedPatch.bytes > 0\n    || submodule.untrackedManifest.entries.length > 0\n    || submodule.submodules.some(hasDirtySubmodule);\n}\n\n/**\n * Capture a stable, content-addressed Git source state.\n *\n * The collector performs two complete reads and refuses a moving worktree.\n * Ignored files are intentionally excluded because Git does not treat them as\n * repository source. Untracked symlinks bind their link target text without\n * following the target outside the worktree.\n */\nexport function captureRepositorySourceState(repoPath: string | URL): ExactSourceState {\n  const requested = repoPath instanceof URL ? fileURLToPath(repoPath) : repoPath;\n  const repoRoot = realpathSync(resolve(requested));\n  const top = realpathSync(gitText(repoRoot, ['rev-parse', '--show-toplevel']));\n  if (top !== repoRoot) throw new Error(`repoPath must be the Git top-level: ${top}`);\n\n  const cleanStatus = (): Buffer => gitBuffer(repoRoot, [\n    'status',\n    '--porcelain=v1',\n    '-z',\n    '--untracked-files=all',\n    '--ignore-submodules=none',\n  ]);\n  const initialStatus = cleanStatus();\n  if (initialStatus.length === 0) {\n    repositoryPaths(repoRoot, false);\n    const baseCommit = gitText(repoRoot, ['rev-parse', '--verify', 'HEAD']);\n    const treeId = gitText(repoRoot, ['rev-parse', '--verify', 'HEAD^{tree}']);\n    if (cleanStatus().length !== 0 || gitText(repoRoot, ['rev-parse', '--verify', 'HEAD']) !== baseCommit) {\n      throw new Error('repository changed while capturing exact source state');\n    }\n    const repository = repositoryIdentity(repoRoot);\n    const identity = {","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/codex/src/harness/repository-state.ts#L393-L429","documentation":"captureRepositorySourceState() requires repoPath to be exactly the worktree top-level: it realpaths the input and compares it with `git rev-parse --show-toplevel` (also realpathed). Passing a subdirectory of the repo, or a path that resolves elsewhere, throws. This guarantees subsequent git plumbing always runs from the true root.","triggerScenarios":"Calling captureRepositorySourceState('src/subdir') or with process.cwd() while the process runs inside a subdirectory; passing a linked worktree's inner directory; URL paths whose fileURLToPath result is not the top-level.","commonSituations":"CLIs invoke the harness from wherever the user happens to be (a monorepo package dir); scripts hardcode a package path; monorepo subpackages each try to snapshot 'their' directory.","solutions":["Resolve the root first: pass the output of `git rev-parse --show-toplevel`","In CLI code, chdir or resolve upward from cwd before calling","If you truly need a subdirectory scope, that is unsupported — capture the whole worktree"],"exampleFix":"// before\ncaptureRepositorySourceState('v3/@claude-flow/codex'); // subdir -> throws\n// after\nimport { execSync } from 'node:child_process';\nconst root = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\ncaptureRepositorySourceState(root);","handlingStrategy":"validation","validationCode":"import { execSync } from 'node:child_process';\nconst gitTop = (p: string) => execSync('git rev-parse --show-toplevel', { cwd: p, encoding: 'utf8' }).trim();\nif (realpathSync(resolve(p)) !== realpathSync(gitTop(p))) throw new Error('not top-level');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize repo-root derivation (rev-parse --show-toplevel) in one helper and use it everywhere","Test harness entry points from subdirectories to catch cwd assumptions","Remember subdirectory scoping is unsupported: always capture the whole worktree"],"tags":["git","repository-root","validation"],"backgroundTag":"wrong-repository-root","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}