$schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
# Runtime boundaries: process execution and fs IO hygiene.
include:
  - "apps/**/src/**/*.ts"
  - "packages/**/src/**/*.ts"
exclude:
  - "**/tests/**"
  - "**/*.test.ts"

rules:
  - id: no-direct-process-spawn
    description: >
      Process execution must go through @gobing-ai/ts-runtime ProcessExecutor
      (or ts-ai-runner for agents). Do not call Bun.spawn/spawnSync, import
      node:child_process, or pull in execa/zx at app/package sources.
    severity: error
    evaluator:
      type: forbidden-import
      config:
        forbidden:
          - specifier: "node:child_process"
          - specifier: "child_process"
          - pattern: "Bun\\.(spawn|spawnSync)\\s*\\("
            matchMode: usage
          - specifier: "execa"
          - specifier: "zx"
        scope:
          include:
            - "apps/**/src/**/*.ts"
            - "packages/**/src/**/*.ts"
          exclude:
            - "**/tests/**"
            - "**/*.test.ts"

  - id: no-direct-fs-io
    description: "Prefer ts-runtime's FileSystem seam for fs IO."
    severity: warning
    evaluator:
      type: forbidden-import
      config:
        forbidden:
          - pattern: "from\\s+['\"]node:fs(?:/promises)?['\"]|require\\(['\"]node:fs"
            matchMode: usage
          - pattern: "\\bBun\\.(?:write)\\("
            matchMode: usage
        scope:
          include:
            - "apps/**/src/**/*.ts"
            - "packages/**/src/**/*.ts"
          exclude:
            - "**/tests/**"
            - "**/*.test.ts"

            # Low-level system primitives (O_EXCL locks, FD byte-tailing, FS watcher, atomic registry, Vite glob fallback):
            - "packages/domain/src/planning/locks.ts" # POSIX atomic O_EXCL file locks
            - "packages/domain/src/retention.ts" # recursive backup-dir reclamation + mtime stat (task 0622 R8); ts-runtime FileSystem seam has no recursive dir remove
            - "packages/app/src/services/token-ledger-service.ts" # FD byte-window log tailing
            - "packages/app/src/services/token-ledger-watcher.ts" # node:fs watch() live watcher
            - "packages/app/src/services/project-registry.ts" # atomic projects.json persistence
            - "packages/app/src/services/slash-commands-service.ts" # synchronous ~/.config/spur/slash_commands.json persistence (mirrors project-registry.ts)
            - "packages/app/src/services/agent-usage-producer.ts" # atomic agent-usage snapshot write (tmp + rename, mirrors project-registry.ts; task 0892 R1)
            - "packages/app/src/services/history-service.ts" # versioned analyze artifact + bounded-errors sidecar + latest.json symlink pointer (task 0474); ts-runtime FileSystem seam has no symlink, so the pointer uses node:fs directly (mirrors project-registry.ts persistence exemption)
            - "packages/app/src/observability/workflow-run-log-sink.ts" # sync FD append for mid-run tail-able all-in-one run log (task 0426 / feature D2); append() is sync from the observability bus
            - "apps/cli/src/commands/workflow.ts" # FD byte-window tail of the mid-run run log for `workflow trace --follow` streaming (task 0428 / feature D2); readSync at offset over the observability sink's FDs
            - "apps/web/src/modules/discover.ts" # Vite/Astro module scanner fallback under bun test

            # Synchronous bootstrap & path resolution:
            - "packages/config/src/bundled-config.ts" # sync bundledConfigRoot() directory walk
            - "packages/config/src/loader.ts" # sync resolveConfigFile() / schema specifier lookup
            - "packages/config/src/executor-update.ts" # atomic single-entry config update (task 0797): O_EXCL lock, fsync'd tmp+rename commit, lstat symlink refusal, mode preservation — ts-runtime FileSystem seam has no lstat/fsync/chmod/O_EXCL
            - "packages/app/src/services/project-start.ts" # sync CLI binary path checks before daemon spawn
            - "apps/cli/src/commands/serve.ts" # sync resolveServeCwd() directory validation before server startup (task 0805 R2); mirrors task.ts sync-template exemption

            # Synchronous template & workflow resolvers:
            - "apps/cli/src/commands/task.ts" # sync loadTemplateContent/Bodies callbacks
            - "packages/app/src/services/workflow-service.ts" # composition advisory source (0775: facts extracted from the live definition inside the synchronous validate path; the baseline snapshot sync read was retired)
            - "apps/cli/src/release-ops.ts" # sync manifest/workspace reads + Bun.write rewrites inside the git release flow (task 0617); mirrors task.ts sync-template exemption
            - "apps/cli/src/version-carriers.ts" # sync manifest reads + Bun.write rewrites for registered release carriers (task 0854); mirrors release-ops.ts sync exemption
