{"record":{"id":"bccf8b99862d327d","repo":"tinyhumansai/openhuman","slug":"globs-not-allowed-use-directory-prefixes-got","errorCode":null,"errorMessage":"globs not allowed — use directory prefixes (got \"${p}\")","messagePattern":"globs not allowed — use directory prefixes \\(got \"(.+?)\"\\)","errorType":"validation","errorClass":"SpecError","httpStatus":null,"severity":"error","filePath":"scripts/agent-batch/lib.mjs","lineNumber":154,"sourceCode":"      throw new SpecError(`duplicate branch \"${agent.branch}\"`, `${at}.branch`);\n    }\n    seenBranch.add(agent.branch);\n    if (!Array.isArray(agent.owned_paths) || agent.owned_paths.length === 0) {\n      throw new SpecError(\n        \"owned_paths must be a non-empty array\",\n        `${at}.owned_paths`,\n      );\n    }\n    for (let j = 0; j < agent.owned_paths.length; j++) {\n      const p = agent.owned_paths[j];\n      if (typeof p !== \"string\" || p.length === 0) {\n        throw new SpecError(\n          \"must be a non-empty string\",\n          `${at}.owned_paths[${j}]`,\n        );\n      }\n      if (p.includes(\"*\") || p.includes(\"?\")) {\n        throw new SpecError(\n          `globs not allowed — use directory prefixes (got \"${p}\")`,\n          `${at}.owned_paths[${j}]`,\n        );\n      }\n      if (p.startsWith(\"/\")) {\n        throw new SpecError(\n          `paths must be repo-relative, not absolute (got \"${p}\")`,\n          `${at}.owned_paths[${j}]`,\n        );\n      }\n    }\n    if (\"allowed_shared_paths\" in agent) {\n      if (!Array.isArray(agent.allowed_shared_paths)) {\n        throw new SpecError(\"must be an array\", `${at}.allowed_shared_paths`);\n      }\n    }\n    if (\"labels\" in agent && !Array.isArray(agent.labels)) {\n      throw new SpecError(\"must be an array\", `${at}.labels`);","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/agent-batch/lib.mjs#L136-L172","documentation":"owned_paths entries must not contain the glob characters * or ? — the error text says \"use directory prefixes\". The reason is architectural: findOverlaps() enforces disjoint ownership via plain string prefix containment (comparePaths normalizes trailing slashes and checks startsWith), which cannot reason about glob semantics. A glob would silently defeat the overlap detector, so it is banned up front; the offending path is shown with index-precise path.","triggerScenarios":"\"owned_paths\": [\"src/**/*.rs\"], [\"app/src/*\"], or [\"docs?.md\"] on any agent. Any occurrence of * or ? anywhere in the path string triggers it.","commonSituations":"Porting file-scopes from .gitignore or CODEOWNERS syntax, which is glob-based; trying to express \"all Rust files\" instead of owning the directories; copy-pasting glob patterns from CI path filters.","solutions":["Replace globs with the enclosing directory prefix: \"src/**/*.rs\" → \"src/\" or a narrower \"src/openhuman/web3/\"","Own whole directories even if the agent touches only some files — overlap rules compare prefixes, so pick the deepest directory that covers the work","For a single file, use the file path itself (\"app/src/App.tsx\") — file paths have no glob chars"],"exampleFix":"// before\n\"owned_paths\": [\"src/openhuman/**/*.rs\"]\n\n// after\n\"owned_paths\": [\"src/openhuman/web3/\"]","handlingStrategy":"validation","validationCode":"for (const [i, a] of spec.agents.entries()) {\n  for (const [j, p] of a.owned_paths.entries()) {\n    if (typeof p === \"string\" && (p.includes(\"*\") || p.includes(\"?\"))) {\n      console.error(`agents[${i}].owned_paths[${j}] uses a glob — replace with a directory prefix`);\n      process.exit(1);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateSpec(spec);\n} catch (e) {\n  if (e instanceof SpecError && /globs not allowed/.test(e.message)) {\n    console.error(`rewrite as a directory prefix (e.g. \"src/openhuman/web3/\"): ${e.message}`);\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Remember owned_paths is prefix-based, not glob-based — think directories, not patterns","Do not copy scopes from .gitignore/CODEOWNERS/CI path filters into specs","After fixing paths, also run findOverlaps(spec) from lib.mjs to confirm agents stay disjoint"],"tags":["validation","json","spec","agent-batch","ownership","globs"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}